dharam
dharam

Reputation: 8096

Socket Programming : Client Disconnection keeps server hanging

I am trying to build a sample TCP Forwarder. Here is the functionality in brief:

  1. The forwarder will listen at a given port.
  2. It contains a map of clients to servers
  3. Clients will connect to the forwarder and the forwarder will lookup the map and create a 2-way-forwarding-connection.
  4. To achieve this, it creates two threads per client.
  5. Thread 1: reads from the client and writes to the target server
  6. Thread 2: reads from the target server and write to the client.

All this is written in C. The Client and Target servers can be written in any language, right now its Java.

When I run a client for the first time, it works as expected. However, if I kill the client and restart it, the server never receives the new connection.

Here is my server code which I suspect is fault.

Socket clientSocket = serverSocket.accept();
InputStream inputStream = clientSocket.getInputStream();
OutputStream outputStream = clientSocket.getOutputStream();

while (true) {
    byte[] bArray = new byte[2048];
    try {
        System.out.println(String.format("SERVER:%s: Attempting to read", this.name));
        inputStream.read(bArray);
        System.out.println(String.format("SERVER:%s: Received %s", this.name, new String(bArray)));
        byte[] bytes = (name + ":" + counter).getBytes();
        counter++;
        outputStream.write(bytes);
        System.out.println(String.format("SERVER:%s: Sent %s", this.name, new String(bytes)));
    } catch (IOException e) {
        System.out.println(String.format("SERVER:%s: Client Disconnected ", this.name));
        clientSocket = serverSocket.accept();
        inputStream = clientSocket.getInputStream();
    }
}

In the C program, I detect the disconnection and close the socket as shown below:

LOGINFO("Reading from Client Socket.");
iResult = read(readSocket, buff, recvbuflen);
if (iResult <= 0) {
    LOGERROR("Receiving failed");
    close(readSocket);          
    break;
}

Upvotes: 1

Views: 319

Answers (2)

Ruslan Akhundov
Ruslan Akhundov

Reputation: 2216

You should use

   shutdown(socket_fd, SHUT_WR);

instead of close(socket_fd) in order to properly close socket.

If you use SHUT_WR, a FIN packet will be sent to another side to inform them we don't have more data to send.

Upvotes: 0

Khrn
Khrn

Reputation: 342

Try to modify your server logic by using concurrency to manage each request. In this way, server will be able to handle each client separately in a thread. Reading and writing data must be performed in the related thread. A pool thread paradigm is often used to avoid thread overhead[1].

For example:

ExecutorService threadPool = Executors.newFixedThreadPool(n);
ServerSocket serverSocket = null;

//...

while(!isStopped()){
   Socket clientSocket = null;
   try {
       clientSocket = this.serverSocket.accept();
       threadPool.execute(new WorkerRunnable(clientSocket));
       // Process data in the WorkerRunnable class
   } catch (IOException e) {
       if(isStopped()) {
           System.err.println("Server Stopped.") ;
           break;
       }
       throw new RuntimeException("Error accepting client connection", e);
   } 
}

A well designed example can be found here: http://tutorials.jenkov.com/java-multithreaded-servers/thread-pooled-server.html

Upvotes: 1

Related Questions