1

I've made a simple server application for sending images to the connected clients. I have a loop in the main thread, which accepts the incoming connections, and make a Client object from the corresponding socket. I have a list for the active clients. Every time a new picture is available, I iterate through the clients, and send them the new data. If everybody stays connecting, everything is going well. But as soon as one of the clients disconnects, the DataOutputStream's write method will stuck forever. I assumed it have to throw an exception or something, but this is not the case. I think I miss something simple, but I can't find out what. Here's my Client class' code:

package hu.rothens.webcam;

import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;

public class Client {

    private static int next_id = 0;
    private int id;
    private Socket socket;
    private WebcamServer ws;
    private DataOutputStream dos;

    public Client(Socket socket, WebcamServer ws, int width, int height) throws IOException {
        this.socket = socket;
        this.ws = ws;
        id = next_id++;
        while (!socket.isConnected());
        dos = new DataOutputStream(socket.getOutputStream());
        dos.writeInt(width);
        dos.writeInt(height);
    }

    public synchronized void sendImage(byte[] array) {
        try {
            System.out.println(id);
            //the code will stuck somewhere after this line
            dos.writeByte(0xFF);
            dos.flush();
            dos.writeInt(array.length);
            dos.write(array);
            dos.flush();
        } catch (IOException e) {
            System.out.println(e); //it won't get here
            ws.removeClient(this);
            try {
                socket.close();
            } catch (Exception ex) {
            }
        }    
    }
}
Rothens
  • 755
  • 7
  • 18
  • Have you considered using a higher level API like Jersey or possibly Netty? Both of those can be used for high-performance async server scenarios. – user2684301 Jan 28 '14 at 21:23
  • I never used them yet. Maybe I'll give it a go :) – Rothens Jan 28 '14 at 21:26
  • I notice that your method is synchronized - do you perhaps have a deadlock somewhere? – Jon Skeet Jan 28 '14 at 21:26
  • @JonSkeet : even if it is synchronized, it should fall into the catch case, no? – Rothens Jan 28 '14 at 21:28
  • @Rothens: Well are you getting in there at all? (Are you seeing the first System.out.println for example?) If you can post a short but *complete* program demonstrating the problem, that would really help. – Jon Skeet Jan 28 '14 at 21:29
  • @JonSkeet: yes, I get the first println. I also placed a println _after_ the write methods, and I didn't get that message. I couldn't send a complete program without mayor rewriting, it uses many libraries currently. But I'll try to make a sscce version from it. – Rothens Jan 28 '14 at 21:34
  • What has the server read? If your write buffer is full then the write call will block until it can send more data. If the server is not reading then it does not take a lot to fill the write buffer. – BevynQ Jan 28 '14 at 21:34

1 Answers1

0

It doesn't block forever. It will throw an IOException: 'connection reset' eventually. 'Forever' implies a deadlock on your part.

The 'while (!socket.isConnected());' loop is completely pointless: the socket is connected, by virtue of having been accepted. And if it wasn't, this is no way to handle it.

You shouldn't flush the stream after writing the 0xff, but you should flush it in the constructor for Client.

I don't see any reason for synchronization in Client, if it is running on its own thread, which it should be.

You should be sending to all the clients simultaneously, not iteratively, so that they all get serviced at the same time, and so that errors or slowness in one doesn't affect the others.

user207421
  • 305,947
  • 44
  • 307
  • 483