In our first example, the one we called "simple TCP program",
we could only run one client at a time.
In this example, our goal is going to be to enable several clients to talk to the server,
In parallel. We'll achieve that by using threads, and I'll try to explain the concept of multi threading
real quick right now. A thread in our example is just going to be an instance of the same application.
It's the same code, same operations, same methods - we just run them separately for each new client. On the
server side,
we're going to have one main class, where we're going to have our main method.
The first thing we're going to do in this class is - we're going to open the server socket.
Then we're going to run an infinite loop, where for each incoming connection, we're going to open a new
thread.
Now I repeat - this is a very shortened version.
We're going to go through the entire code later. For now,
this is what threads look like for every new client that connects to the server -
we run a new thread,
this calls a run method in a server thread that we create for every new connection.
So to sum up, whenever a new connection comes to the server, we create a regular socket,
by accepting that connection - that's coming through the server socket, and then we create a thread for
that particular connection.
After that, we just go back to the loop and wait for the new connection to show up.
All right.
Hopefully this will clear up as we go through the code.
I'm going to open Eclipse.
I'm going to create a new package and I'm going to name it simple_tcp_multithread. This time we'll need
two server classes. One is ServerMain,
and the other one is ServerThread.
We'll copy the Client class from our previous example, because the code in the client is not really going
to change.
We're only changing the server.
We're only enabling the server to accept several connections at a time.
So I'm just going to copy the client into our new package.
All right, let's get going.
I'm going to start from the ServerMain class.
The first thing we're going to need is going to be the main method.
And then inside our main method, we're going to have the try-catch block
again - we're familiar with that.
We're going to do the printStackTrace() in the catch block, and in the try block we're going to call
new ServerMain(). Then, we're going to create this ServerMain method.
It's going to be public,
and the first thing we're going to need here is the server socket.
We'll use 2020 for our port number again.
And I'm going to press
Ctrl + Shift +O to import all and necessary packets.
Let's print out a message just so we know where we are when the program runs.
We're gonna say "Port 2020 is now open."
Now we need that infinite while loop,
I'm going to add a comment here -
you create an infinite loop by just typing "true" in the condition.
So whatever happens inside the loop, we're always going to come back and do another run through the loop.
So the point of this loop is to create a new thread for every new client that shows up. The first step
would be to create a socket for every new client.
So we're going to create the socket object, and we get the socket object when we accept a connection
coming into the server socket. Again, I'm going to press Ctrl + Shift + O to import the socket package,
and now I'm going to work on the thread.
So now you're going to have to bear with me, I'm going to explain the code as I go, and some of it will
only become clear later.
So let's just type it in and see what happens.
First I'm going to create a ServerThread object, and I'm going to have to use a constructor from the
ServerThread class.
Now since we don't have anything in that class yet, we're going to have this warning throughout typing
this code, but don't worry about that - we're gonna resolve that later.
So here's our object. We're going to say new ServerThread and we're going to forward the socket as the
argument.
Here's that error that I was talking about.
We're just gonna ignore that for now and it's actually going to resolve itself.
Now, we're going to need a Thread - Java already has a Thread class, since threads are a pretty common conception.
We're going to forward our server_thread object as an argument, and then we're going to say thread.start().
Now what this means is - whenever we run into this line, we're going to call a run() method in the ServerThread
ServerThread class - you'll realize later on what that means since right now we haven't built our run() method
yet.
So let's go to our ServerThread class, and get into it right now. Our ServerThread class is going
to have to "implement Runnable".
By the way,
this could be done in a different manner, but we're going to use Runnable. What Runnable is - it's pretty
much an interface and is like a template for an object that is intended to be executed by a thread.
It defines a single method which is >>run()<< - we haven't defined it yet, but we are going to - and that run() method
is meant to contain the code that is executed by the thread.
This is going to make much more sense when we run the code so let's get into it and hopefully it will
clear up. Now, before we add that run() method,
we need to create the constructor that I mentioned in our previous class.
If you're not familiar with constructors - a constructor is kind of a special method, that is called when
an object is initiated.
So a class constructor initializes instances - or objects - of that class.
In our case, we need to initialize the object that we forwarded from our ServerMain class, and that
would be our socket object.
We're going to define that object as private, because we don't want other threads to be able - other threads
or classes - to be able to access a socket in a particular thread.
So it's going to be private Socket socket, and then we're going to say public server_thread.
Now this method has to be public because we need to access it - or we need to call it from another class,
and that class is the ServerMain class.
And here we are defining the object that is being forwarded, and then we're going to say this.socket
this.socket = socket.
We're using the >>this<< keyword, because our objects are named the same.
But if you're wondering which socket is which, you just need to click - or at least, if you're using Eclipse -
you just need to click on one of the objects and it's going to tell you which one of them is being referred
here.
So this is the socket we're talking about.
This socket - this object - is going to become this newly defined object in our constructor.
I'm going to press Ctrl + Shift + O to import the Socket package, and then we can move on to our run()
method.
I'm going to have to use @Override here because Java's Thread class already has its own run() method.
So in order for us to be able to use our own run() method ,we're just going to use this @Override thing.
run() is going to be - public void run() - and then we're going to have the try-catch block inside of it.
Our catch block is going to have the regular printStackTrace(), and our try block is actually going to
have all of the code that defines the protocol for the communication between the server and our client.
I'm actually going to be a bit lazy and copy that from our previous example.
I'm going to copy.
No I'm actually going to go to the first one and I'm going to copy all of this.
I'm going to edit this a bit.
I'm going to add a printout here, that a new client has connected.
And then the server is going to say to the client:
"Welcome! What's your name?"
I'm going to save that, and I'm going to go back to ServerMain to check things here.
Everything seems OK.
I'm going to save that too and then I'm going to open the client.
The client is not going to be guessing any numbers this time.
So we're going to delete all of this instead.
We're going to just accept the message from the server,
print it out in our console.
We're going to say -
and then we're going to store whatever the user types in into the same string.
And then we're going to send that out to the server.
That's it.
That should work.
I'm going to save this and then run it. We're going to run ServerMain. So we're again running only the
classes that have the main method.
And then let's run our first client.
I'm going to switch to the client's console.
It's asking me what's my name.
I'm going to say "Luke" for example, and then I'm going to run another client.
This time, I'm not going to answer to server's question, and I'm going to run another client.
So at this point we have two clients running.
Let's check that out in the console.
So we have client three here OK.
So this is the second client and this is the third client.
I'm going to type another name into the second client and now my second client has disconnected.
And then I'm going to type in something else into the third client.
Let's say "Laura" for example.
All right.
Now all of my three clients have disconnected but the server is actually still running.
If we go to "Clients" - it says "terminated" here.
So I'm going to close this console, and then I'm going to close the third client's console, and I'm only
left with my server's console. And I can see here that it's still running, because I have this "terminate"
button still available.
I'm going to click here and now we're done.
Now I can close the console for the server too.