Valhalla Legends Forums Archive | Java Programming | Multithreading: Accepting Clients while Listening to Them

AuthorMessageTime
Ender
I have a problem with a particular multithreading situation. In my chat program, my server has a thread for accepting clients and a thread for listening to clients. I want to be constantly accepting and constantly listening. I know that these two things can't take place at exactly the same time, so I have to somehow synchronize these two threads. The problem is that the Thread for accepting clients calls the ServerSocket.accept() method, which in itself has a while loop in which it WAITS for a client to connect before moving on in the code.

So my thread for accepting clients looks like this:
[code]
public void accept() {
    acceptThread = new Thread(new Runnable() {
        public void run() {
                while (server != null) {
                      Socket client = null;
                      try {
                            client = server.accept();
                      }
                      // Parse clients logon packets before adding to client list (clients)
                      ...
                }
        }
    });
    acceptThread.setPriority(Thread.NORM_PRIORITY);
    acceptThread.start();
}
[/code]
Note that I have a while loop within a while loop within a Thread, since ServerSocket's accept method waits until a client is connected to move on.

My thread for listening to clients looks like this:
[code]
public void listen() {
      listenThread = new Thread(new Runnable() {
            public void run() {
                  while (server != null) {
                        for (User client : clients) {
                              InputStream in = null;
                              try {
                                      in = client.getSocket().getInputStream();
                              }
                              catch ( IOException e) {
                                      // ...
                              }
                              // Read packet header, determine if its valid, and if it is read rest of packet then parse
                              ...
                        }
                  }     
            }
      });
      listenThread.setPriority(Thread.MAX_PRIORITY);
      listenThread.start();
}
[/code]

When I run my program the Thread for accepting clients basically takes hold (even though I set it to lower priority) and never lets up. My logon packets go through fine, and are parsed, and my client is added to the client list... but then when I loop through my client list to receive data I never receive the data. I put a System.out.println() statement at the top of the listen thread and I never got the output. So my listen thread is never run in the first place. =( I've tried everything, from making my accept Thread sleep after accepting a client, interrupt itself, yield, etc. !!!
January 8, 2006, 4:43 PM
Kp
[quote author=Ender link=topic=13839.msg141069#msg141069 date=1136738587]I know that these two things can't take place at exactly the same time[/quote]

This is not true.  It's quite possible (at least in native languages, probably even in something like Java) to block until the system is ready to supply data or to supply a client, then handle whichever occured and return to sleeping -- all within the same thread.
January 8, 2006, 4:52 PM
Ender
Nvm, it works now. What I ended up doing is making a "master" thread that listens for client connections and creates new "worker" threads for parsing each client's packets once a client does connect. I got this suggestion of the Sun site, and it has worked out very well.
[code]
class Server extends Thread {
...
public void run() {
while (!timeToQuit) {
// Accept client
Socket clSock = null;
try {
clSock = svrSock.accept();
}
catch (IOException e) {
System.out.println("Unable to establish socket with  client.");
}
// Create a thread to do the parsing for this client
new Thread(new ClientHandler(clSock, clients)).start();
}
}
...
}
[/code]

January 8, 2006, 9:47 PM
JoeTheOdd
[quote]What I ended up doing is making a "master" thread that listens for client connections and creates new "worker" threads for parsing each client's packets once a client does connect.[/quote]

I was going to link you to RabbiChat's server to show you that, but I guess you don't need me to! =p
January 8, 2006, 11:17 PM
iago
[quote author=Kp link=topic=13839.msg141073#msg141073 date=1136739149]
[quote author=Ender link=topic=13839.msg141069#msg141069 date=1136738587]I know that these two things can't take place at exactly the same time[/quote]

This is not true.  It's quite possible (at least in native languages, probably even in something like Java) to block until the system is ready to supply data or to supply a client, then handle whichever occured and return to sleeping -- all within the same thread.
[/quote]

I actually wrote a nice little class that uses Java's equivalent of select() to look after sockets.  It can accept, connect, send, and receive. 

The only problem I have is that it blocks on connecting, I'd like to find a way to fix that, but I'm not sure if there is. 

My code is now Java 1.5, and my complete rant on it can be found here:
[url]http://www.x86labs.org/forum/index.php/topic,4475.0.html[/url]

Or, if you just want to pick through the code:
http://www.javaop.com/~iago/nonblocking.tgz

I strongly recommend moving to java.nio.channels.SocketChannel and using a java.nio.channels.Selector to multiplex them instead of using multiple threads.
January 9, 2006, 3:39 AM
Ender
Thanks guys. And thanks iago for the classes and recommendations. I'll look into it.
January 10, 2006, 9:17 PM

Search