• Welcome to Valhalla Legends Archive.
 

Multithreading: Accepting Clients while Listening to Them

Started by Ender, January 08, 2006, 10:43 AM

Previous topic - Next topic

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:

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();
}

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:

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();
}


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. !!!

Kp

Quote from: Ender on January 08, 2006, 10:43 AMI know that these two things can't take place at exactly the same time

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.
[19:20:23] (BotNet) <[vL]Kp> Any idiot can make a bot with CSB, and many do!

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.

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();
}
}
...
}



Joe[x86]

QuoteWhat 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 was going to link you to RabbiChat's server to show you that, but I guess you don't need me to! =p
Quote from: brew on April 25, 2007, 07:33 PM
that made me feel like a total idiot. this entire thing was useless.

iago

Quote from: Kp on January 08, 2006, 10:52 AM
Quote from: Ender on January 08, 2006, 10:43 AMI know that these two things can't take place at exactly the same time

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.

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:
http://www.x86labs.org/forum/index.php/topic,4475.0.html

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.
This'll make an interesting test for broken AV:
QuoteX5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*


Ender

Thanks guys. And thanks iago for the classes and recommendations. I'll look into it.