1

I created 2 Java programs with sockets in it. I want the client to send continuous data to the server. But after the message sent to the server, the client keeps sending 'null' value to the server (it happens when I close the socket in client program). Here is my codes:

import ...
public class MainClient {
    private Socket serverSock;
    private PrintStream clientOutput;

    public static void main(String[] args) {
        MainClient client = new MainClient();
        client.runClient();
    }
    public void runClient() {
        try {
            serverSock = new Socket("127.0.0.1",8282);
            clientOutput = new PrintStream(serverSock.getOutputStream());
            clientOutput.println("Hello, I'm Connected.");

            for (int i=0;i<5;i++) {
                clientOutput.println(i + "");
                clientOutput.flush();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
//          try {
//              serverSock.close(); It will keeps sending 'null' data to the server if I use this line.
//          } catch (IOException e) {
//              e.printStackTrace();
//          }
        }
    }
}

The Server Side:

public class MainServer {

    private ServerSocket serverSocket;
    private int listenPort = 8282;
    private InputStream inps;
    private Socket clientSocket;
    private BufferedReader clientInput;

    private MainServer() {
        String clientMsg = "";
        try {
            serverSocket = new ServerSocket(listenPort);
            System.out.println("Server is Listening on " + listenPort);
            clientSocket = serverSocket.accept();
            clientInput = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
            while(clientSocket.isConnected()) {
                clientMsg = clientInput.readLine();
                System.out.println("Client : " + clientMsg);                
            }
        }catch(IOException ex) {
            ex.printStackTrace();
        }finally {
            try {
                clientSocket.close();
            } catch (IOException e) {}
        }
    }
    public static void main(String[] args) {
        new MainServer();
    }
}

I tried to close the OutputStream on the Client side with clientOutput.close(); but it sends nulls to the server after it sends the 0-4 loop. To make it stop and avoid the client sends null data, i should not insert the serverSock.close(); on the Client, but it will returns SocketException. I wanted the client to send 'Closed' message after its done.

Summary, the output on the server is:

Client: 0
Client: 1
Client: 2
Client: 3
Client: 4
Client: null
Client: null
//And so on..

I think there is something missing on the Client Program, i guess? Thank you for the help :)

Evan Gunawan
  • 387
  • 4
  • 17

3 Answers3

2

As the comment noted, the client is not sending a null value.

The isConnected() method does not do what you think it does, namely it does not tell you if the socket is currently "connected" to its peer, at least in the way you think it should. isConnected() becomes true as soon as the socket transitions into the connected state, and stays true thereafter, even after the socket is shutdown. See this discussion and others on stackoverflow.

The correct way to determine if the peer has shutdown the connection is to attempt to read from the socket and then examine the result for evidence of closure. Please read the Javadocs for the method you are using, they will tell you what the various return values mean. For the BufferedReader.readLine() method, it says:

Returns:
A String containing the contents of the line, not including any line-termination characters, or null if the end of the stream has been reached
Throws:
IOException - If an I/O error occurs

Thus you need to check for a null return value to detect a normal socket closure, and if you receive an IOException that indicates some kind of network anomaly.

President James K. Polk
  • 40,516
  • 21
  • 95
  • 125
  • I see. Thank you for the explanation. So to is it better to use `clientInput.readLine()!=null` condition like the answer below explained to determine that the peer has shutdown/closed the connection? – Evan Gunawan Feb 03 '19 at 16:49
  • 1
    @motionfrog That's exactly what he already said. It's not merely 'better', it is the only valid choice. – user207421 Feb 03 '19 at 18:33
-1

Your MainClient() have no problem.

clientSocket.isConnected() function in MainServer() always check the status of the client and which results an infinite loop, so after the message 'client:4', clientInput.readLine() should return 'null'.

So instead of checking the client socket is connected or not you can check the client socket is closed or not using function 'clientSocket.isClosed()'.

replace the while loop in MainServer() with below code,

       while(!clientSocket.isClosed()) {

                clientMsg = clientInput.readLine();
                System.out.println("Client : " + clientMsg);

                if(clientMsg.equals("Closed")){
                     clientSocket.close();
                //  serverSocket.close();
                }
            }

this will help you to close the client socket at the time of receiving 'Closed' message from server and this avoid the infinite execution of while loop as well as null statement printing. The code "serverSocket.close()" help you to close the server socket and you can use this at 'MainServer()' if you need to stop the port listening.

  • 1
    `isConnected()` in the server *never* checks the status of the client. `isClosed()` doesn't either detect the client closure or 'help you close the client socket' here. It doesn't work any better here than `isConnected()`. Clearly you've never tried it. – user207421 Feb 03 '19 at 00:36
-2

typically the code should be something similar

private MainServer() {
  String clientMsg = "";
  try {
    serverSocket = new ServerSocket(listenPort);
    System.out.println("Server is Listening on " + listenPort);
    clientSocket = serverSocket.accept();
    clientInput = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
    while ((clientMsg = clientInput.readLine()) != null) {
      if(isTerminationString(clientMsg)) { 
        break;
      }
      System.out.println("Client : " + clientMsg);
    }
  } catch (IOException ex) {
    ex.printStackTrace();
  } finally {
    try {
      clientSocket.close();
    } catch (IOException e) {
    }
  }
}

boolean isTerminationString(String msg) {
  return msg.equals("DONE!");
}

where in isTerminationString you check if the msg is a termination msg, the communication protocol should be shared between the client and the server . i gave the example of sending a DONE message, but it could more complex than that . as closing the close method on the socket does not guarantee that the socket on the other part gets closed as well, using the isClosed method might not be effective and results in the same problem you have .

mehdi maick
  • 325
  • 3
  • 7