简体   繁体   中英

manage socket connection in Java over tcp

I wrote a client which basically just open a socket and send content over the connection. ( the content follows the Http protocol)

The problem I'm facing regards to the question - how and when should i close the connection. The issue is that the connection sometime closes too early ("FIN" is sent to the server before the server answered).

in this case the server's answer is lost.
I tried to use Thread.sleep before closing the connection but nothing seems to affect the time between the content is sent and the "FIN" message is sent. (viewed in Wireshark)

The answer sometimes arrive and sometimes not ( race condition).

How can i delay the "FIN" message so i won't miss the server's response?

i added the relevant class. The relevant function is sendContentOverSocket

public class SocketClient {

           private String hostName;
           private int portNumber;
           private Socket ConnectionSocket;

           public void init(String hostName, int portNumber){
                          this.hostName = hostName;
                          this.portNumber = portNumber;
                          this.ConnectionSocket=createSocketConnection();

           }

           private Socket createSocketConnection() {
                          Socket socket = null;
                          try {
                                         socket = new Socket(this.hostName, this.portNumber);
                                         return socket;
                          } catch (UnknownHostException e) {
                                         e.printStackTrace();
                          } catch (IOException e) {
                                         e.printStackTrace();
                          }

                          return socket;
           }

           public void sendContentOverSocket(String content) {
                          try {
                                         PrintWriter out = new PrintWriter(
                                                                       ConnectionSocket.getOutputStream(), true);
                                         BufferedReader in = new BufferedReader(new InputStreamReader(
                                                                       ConnectionSocket.getInputStream()));
                                         out.print(content);

                                         try {
                                                        Thread.sleep(2000);
                                         } catch (InterruptedException e) {
                                                        // TODO Auto-generated catch block
                                                        e.printStackTrace();
                                         }

                                         out.close();
                                         in.close();                           
                                         ConnectionSocket.close();

                          } catch (IOException e) {
                                         e.printStackTrace();
                          }
           }

}

在此处输入图片说明

TCP works with a concept called a half close. When you close the socket that is an indication that you are not going to send anymore. In your explanation I see "FIN is sent to the server before the server answered", if you are the client, that would mean that you have performed a close on the socket. If you expect a result from a server within a certain time frame you need some kind of timing mechanism, possibly making use of select in combination with a timeout. If the server closes his end of the connection, you detect this by receiving bytes in receive. Usually this means that you have to close the socket too. So in conclusion there is 3 reasons for you to close the socket :

  • the server closes his end of the socket basically saying i am not going to send anymore
  • you have waited for a while and you are tired of waiting and decide to close the socket yourself.
  • any other error conditions but usually they all appear like receiving 0 bytes or a negative number.

You should close the connection after you've read the response, of course. Difficult to see the mystery here. No sleeps. If you don't read the response (a) you can't know whether the request succeeded or failed, and (b) the server is liable into encounter an exception as well.

Your code is poor quality. All those methods should propagate exceptions instead of catching them internally and returning null.

In case of Java 7, since all three classes, ie Socket , PrintWriter , BufferedReader , implement AutoCloseable and based on the fact, that you want to close socket right after you invoke sendContentOverSocket(String content) try to use the following code:

    public class SocketClient {

    private String hostName;
    private int portNumber;

    public void init(String hostName, int portNumber) {
        this.hostName = hostName;
        this.portNumber = portNumber;
    }

    public void sendContentOverSocket(String content) {
        try (Socket socket = new Socket(this.hostName, this.portNumber);
            PrintWriter out = new PrintWriter(socket.getOutputStream(), true); 
            BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {
            out.print(content);
        } catch(IOException e) {
            //Appropriate exception handler
        }
    }
}

In this case Java will close all resources properly by itself.

If you use Java 6 or earlier try to use try-finally block instead:

solved.

i now understand how it works. what i was missing in the client is the attempt to read from the input Stream. When you try to read

while ((inputFromServer = in.readLine()) != null)

the client waits for input. The only thing that will break this loop is the server closing the connection.

after that happens you can safely close the connection on the client side. No need to delay the FIN and such...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM