2

This is a bit of a "further down the track now" extension to a question I asked a while ago... I have a better understanding of sockets now, and have some working code but need to improve it...

Ok, so I have currently got UDP multicasting working to send short strings of text from a Java 'server' application to several Android phones (which will potentially become several hundred Android phones). This works fine most of the time, but it does tend to lose the odd string on the odd phone, and randomly it will just go total loss for a short period and nothing will get through to any of them, which can be a little frustrating.

Since, as I understand, there is no way to broadcast on TCP - my idea is to have the phones initially 'connect' to the server app using a ServerSocket. This will do nothing more than harvest client IP addresses which are to be stored in a Set<InetAddress> called clients. Then I will want to iterate over these addresses and send the string to each phone individually - but I don't want to block the code, nor do I want to spend forever waiting for sends to occur if, say, the phone has gone to sleep and can't / won't accept connections. The information will need to get to all phones within a few seconds of starting to send (even with 2-300 clients).

My initial code is below, and the questions I have regarding it are:

  • Is this code in one thread enough?
  • Would a modern CPU make good use of several threads with the address set split evenly amongst them (say 4 threads?)
  • Is it (as I believe) a bad idea to spin every connection/send off in its own thread?
  • Does setting the socket timeout allow the thread to work through its list faster? Or will this cause problems?
  • If socket timeout setting is a good idea, then what is a sensible time? Or do I need to just test to get this right?

Thanks in advance for any help you guys can provide...

for (InetAddress client : clients) {
try {
    Socket sendQuestionSocket = new Socket(client, portSend);
    // Theory: 50 milliseconds is enough to connect, and could allow 200 clients 
    // to get their questions in around 10 seconds.  Maybe?
    sendQuestionSocket.setSoTimeout(50);
    PrintWriter outStream = new PrintWriter(sendQuestionSocket.getOutputStream());
    outStream.println(question.toString());
    outStream.flush(); // Do I need this line?
    sendQuestionSocket.close();
    outStream.close();
} catch (InterruptedIOException e) {
    logger.log(Level.WARNING, "Couldn't connect in time... passing this one over");
    e.printStackTrace();
} catch (UnknownHostException e) {
    logger.log(Level.SEVERE, "Unable to find that client");
    e.printStackTrace();
} catch (IOException e) {
    logger.log(Level.SEVERE, "Unable to create question sending port");
    e.printStackTrace();
}

}

Steve
  • 1,439
  • 2
  • 14
  • 27
  • Just wonder how you manage to send data *to* the phones as their IP addresses are not visible from the internet in general. A lot of GSM providers have their customers in private networks and use NAT (or something similiar). – Andreas Dolk May 17 '11 at 11:36
  • Hi Andreas, the phones are connecting to the local WIFI network, its totally independent of the GSM network... to try and use the GSM data network here in New Zealand would be very expensive... – Steve May 17 '11 at 21:03

2 Answers2

1

I would go with threads here: one thread for every client. It is ok for modern cpu, and it won't make you block for execution. So, the live clients will get the answer as soon as possible even if there are a lot of dead clients.

Vladimir Ivanov
  • 42,730
  • 18
  • 77
  • 103
  • Thanks for that - I just had a look around at that aspect and found this thread: http://stackoverflow.com/questions/763579/how-many-threads-can-a-java-vm-support so you might be right there. I'll give it a go when I get a chance today and see how many connecting threads I can run up to missing clients before things go to heck on the 'server'... Cheers – Steve May 17 '11 at 21:15
1

I'm not sure what you're trying to do will work. ServerSocket is not there to allow you to gather remote IP addresses and just connect back when you want. In order to connect back to those devices they would have to have a server listening on a particular port and accept your incoming connection.

Since it seems like you already have the clients connecting to your server socket i would just tell them whatever they need to know once they have connected - unless you really can have a server on each phone.

Another option would be to use (connectionless) UDP but the client code would still have to be actively waiting for datagram packets.

When doing anything Socket related in Java i highly recommend Netty. Netty will handle all the asynchronous network IO for you and let you focus on what to do once the client has connected.

alpian
  • 4,668
  • 1
  • 18
  • 19
  • Thanks, but I don't understand what you mean by ServerSocket not being there to allow me to gather IP addresses - it works perfectly this way. The clients are actually actively listening for the text to come through all the time - I have a receiver thread listening for UDP multicast packets at the moment - but the issue is reliability as I stated above. I will have a look at Netty but I am using this as a Java networking learning exercise, so replacing my networking code with a 'black box' isn't ideal for me. Cheers – Steve May 17 '11 at 21:06
  • While you **can** gather remote addresses using ServerSocket, this is not it's main purpose. Why are you establishing a TCP connection just to gather the remote client's IP address? You are already using UDP back to the "client" phones. Just use UDP for the server registration step. Netty is not a black box. It is a Facade put on top of Java NIO classes to hide the complexity of the Java NIO API which i've found is difficult to work with. It's extremely powerful and allows you to do things asynchronously very easily. Using it is just a suggestion. :) – alpian May 17 '11 at 22:56
  • Thanks for the response... I'm using it to actually ensure the client apps are talking to the correct server. Its part of an authentication system that is not quite complete yet... but it makes sure the client app is using the correct port to listen on, as well as knowing the servers IP address to send responses to. I've started to read up on Netty, and it looks interesting - and I agree about NIO - I began looking at that and gave up some time back :) – Steve May 18 '11 at 05:45