views:

176

answers:

3

Hello,

I'm having problems with sockets in java. I have a ServerSocket that is listening with accept() and spawns threads for each client-request. Communication between clients and the server works fine. I am using an inputstream to read data from clients in the serverthreads, like:

inputStream = mySocket.getInputStream();
bytes = inputStream.read(buffer);

My problem is that if I call socket.close() from the clients, nothing happens to the blocking call of bytes = inputStream.read(buffer);, it continues to block. But it works if I close the socket from the server, then the inputStream.read(buffer); of the client returns "-1".

Hope you understand what I mean :)

Thanks, James Ford

SERVER-MAINTHREAD:

//SERVER MAIN THREAD, SPAWNS CLIENT THREADS
ServerSocket serverSocket = new ServerSocket(SERVERPORT);
while (listening){

new ServerThread(serverSocket.accept(), monitor).start();
}

SERVER-CLIENTTHREADS:

public class ServerThread extends Thread{

public ServerThread(Socket socket, Monitor monitor) {
        this.socket = socket;
        this.monitor = monitor;
    }

    public void run(){
        byte[] buffer = new byte[1024];
        int bytes;
        //Listen
        while(true){
            try {
                InputStream inputStream = socket.getInputStream();
                monitor.doStuffWithOtherThreads(Object myObject);
                bytes = inputStream.read(buffer); //Problem
                if (bytes == -1){
                    System.out.println("breaks");
                    break;
                }

                byte[] readBuf = (byte[]) buffer;
                String readMessage = new String(readBuf, 0, bytes);
                System.out.println(readMessage);
                System.out.println(bytes);


            } catch (IOException e) {
                System.out.println("Connection closed");
                break;
            }
        }
    }

CLIENT:

InetAddress serverAddr = InetAddress.getByName("serverhostname");

socket = new Socket(serverAddr, PORT);

socket.close(); //Close the socket connection from client. Nothing happens in the serverthread
A: 

Try setting socket read timeout on a server side client socket by Socket.setSoTimeout() and see if it helps

bobah
Will not fix this problem. What I could do is sending some dummydata to the socket before calling Socket.close() so the blocking call releases, and then handle the situation depending on the data. But I don't like that.
James Ford
A: 

I don't know if I understand your issue, but I would say that it is normal that it's up to the server to close the socket.

On server side (in an independent thread) you have the listening socket :

ServerSocket socketServeur = new ServerSocket(port);

Then probably (in the same thread if it is a small server) a loop accepting incoming connections (no exception management, probably the socket.close is in a finally block) :

while (! askedToClose) {
    Socket socket = socketServeur.accept();
    doSomethingWithRequest(socket);
    socket.close();
}

On the client side, you have :

Socket clientSocket = new Socket();
clientSocket.connect(new InetSocketAddress(port));
OutputStream output = clientSocket.getOutputStream();
// send something to server
InputStream input = clientSocket.getInputStream(); // will block until data is available
// reading response

The server should know when it has reached the end of the request. For example in http it could be (taken from a mockHttpServer in scala so there might be some errors but the process is the same):

void doSomethingWithRequest(Socket socket) {
    BufferedReader inputReader = new BufferedReader(new InputStreamReader(socket.getInputStream));
    StreamWriter outputWriter = new OutputStreamWriter(socket.getOutputStream);

    StringBuilder requestBuilder = new StringBuilder();
    do {
        requestBuilder.append(inputReader.read().toChar());
    } while (!requestBuilder.toString().endsWith("\r\n\r\n"));

    saveUri(getUriFromRequest(requestBuilder.toString()));

    outputWriter.write("HTTP/1.1 200 OK\r\n\r\n");
    outputWriter.flush();

    inputReader.close();
    outputWriter.close();
}

EDIT : I read the code added and I still don't get it :

  • you call Socket.close(), but this method is not static
  • you loop forever in the "server"
  • I have the impression that you use the same socket for client and server

You have 3 "sockets" :

  • the listening socket (object ServerSocket)
  • the accept socket (Object Socket sent by socketServer.accept())
  • the client socket (like above in the example)

The server open and close listening and "accept" socket, and should have no impact of bad client socket management.

Then if you want your server to accept serveral concurrent connections, you may add a ThreadPool for accepting connections and treating requests and responses.

Bruno Thomas
I must admin too that java is not the most simple language for socket programming...
Bruno Thomas
Ofc Socket is not static? It was just an example. Its not like I try to call it that way in my clients. It's not like I posted my real code. I just tried to make myself clear. The only question is "why doesnt InputStream.read() release when the socket gets close clientside.
James Ford
It is not 'normal that it's up to the server to close the socket'. The situation is completely symmetrical. Either end may close, and the other end then gets -1 or null or EOFException, depending on what method it's calling.
EJP
@James, ok, but I was confused about which socket was closed. Now it is clearer. I ran your code on my machine (Ubuntu 9.10) with java 1.5.0.20 and it is not blocking. I see "breaks" at each client connection.
Bruno Thomas
@EJP it is true that it is symetric but it is better if the server do not rely on clients for closing the sockets.
Bruno Thomas
@James I tried also with a netcat connection sending data, closing the socket and i see "breaks". What is your environment ?
Bruno Thomas
I coded a simulation of my android device on my workstation, and it worked. The socket gets closed and returns -1. Must be a bug in android? I noticed if I kill my android app it does close like it should. But not with close()
James Ford
@James from a pure threading point, it is better to use concurrency package (with executors) than the "low level" thread objects (thread life cycle facilities encapsulated). See Brian Goetz "Concurrency In Practice" for example.
Bruno Thomas
@Bruno this is still nonsense. Many protocols rely on the client closing first, and most others are robust whoever closes first.
EJP
@EJP you're right, maybe I'm working too much with http... the only thing I had in mind is that the connection management has too be well written on the server side because it can run 24/7.
Bruno Thomas
Well either side can close an HTTP connection too. I don't know where that came from at all.
EJP
+2  A: 

The server code you posted doesn't check for -1. So either that is the problem or that isn't the real code, in which case you should post the real code for comment.

EJP
Updated with code now.
James Ford
Your code works for me. And closing a socket created by the same JVM that is blocked in a read() doesn't cause that read() to return -1, it causes an IOException.
EJP
Weird. It does not work for me. I am closing the socket with an android device. Maybe that is the problem? I will try to connect and close() with a computer.
James Ford
Don't know anything about Android but closing the socket should send a TCP FIN which is received as EOS by the peer. If it doesn't do that it is a bug. Can you sniff the network? That would-be my next step. But I'm concerned about your statement that closing at the server causes the server's read)) method to return -1. It doesn't. Are youmsure you saw that? I'm wondering whether you're running the code you think you're running.
EJP
What I tried to say was that if I close the socket serverside. The read() method in the client(Yes I have one in client) returns -1 like it should.
James Ford
Ok i coded a simulation of my android device on my workstation, and it worked. The socket gets closed and returns -1. Must be a bug in android? I noticed if I kill my android app it does close like it should. But not with close()
James Ford
Closing your own socket while you have another thread reading it doesn't make it return -1. It causes an IOException. So there is something very wrong with your observations.Re Android, it does indeed look ike a bug. Is there another way to close? E.g. in Java you can close the input or output stream.
EJP
Yeah I tried to close the output stream also, nothing happened.
James Ford
Then you're going to have to sniff the network to see what if anything Android is sending when it closes.
EJP