Discussion on the correct closing posture of java socket

  • 2021-09-16 07:05:24
  • OfStack

java socket corresponds to three handshakes and four waves of tcp and tcp in the network protocol, and the state in 11 will not be mentioned here. I don't know if you will encounter various abnormal errors when you don't pay attention to socket.

For example:

java.net.SocketException:socket is closed

Error prompt occurrence scenario:

I voluntarily shut down socket, but then read and write data from it

Software caused connection abort: socket write error

Error prompt occurrence scenario:

The other party has closed socket and still writes data to the other party

connection reset (by peer)

Scenarios where error prompts appear:

End 1 socket is turned off, and the other end still sends data. The first data packet sent is connection reset ES40peer

socket at one end exits, closing the connection when exiting, and connection reset at the other end reads data

Therefore, when using socket, it is necessary to agree on the conditions for both parties to complete reading and writing, and then close the input and output streams:


socket.shutdownInput();
socket.shutdownOutput();

That is, when one party writes, call shutdownOutput to close the output stream, and then the other party's read method will return-1. At this time, the other party will know that you have finished writing, and the other party can close the input stream, and then wait for the other party to write and call shutdownOutput, and then call shutdownInput, and both parties will normally close the input and output stream. At this time, socket will not be abnormal.

Here is an example of an socket interaction:

server terminal


public class OioServer {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(8080);
        while (true) {
            Socket socket = serverSocket.accept();
            System.out.println("socket = " + socket);
            new Thread(() -> {
                try {
                    InputStream in = socket.getInputStream();
                    OutputStream out = socket.getOutputStream();
                    out.write("hello! I get your message that is follow".getBytes(Charset.forName("UTF-8")));
                    byte[] buf = new byte[1024];
                    int len;
                    while ((len = in.read(buf)) != -1) {
                        System.out.print(new String(buf, 0, len, Charset.forName("UTF-8")));
                        out.write(buf, 0, len);
                    }
                    out.write("\n end \n".getBytes(Charset.forName("UTF-8")));
                    out.flush();
                    socket.shutdownInput();
                    socket.shutdownOutput();
                } catch (IOException e) {
                    e.printStackTrace();
                }finally {
                    try {
                        socket.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }
    }
}

client terminal


public class OioClient {
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket("127.0.0.1", 8080);
        InputStream in = socket.getInputStream();
        new Thread(() -> {
            BufferedInputStream bufferIn = new BufferedInputStream(in);
            byte[] buf = new byte[1024];
            try {
                int len;
                while ((len = bufferIn.read(buf)) != -1) {
                    System.out.print(new String(buf, 0, len, Charset.forName("UTF-8")));
                }
            }catch (Exception e) {
                e.printStackTrace();
            }
            try {
                socket.shutdownInput();
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }).start();
        OutputStream out = socket.getOutputStream();
        int cout = 10;
        while (cout-- > 0) {
            out.write(("this time is " + System.currentTimeMillis() + "\n").getBytes("UTF-8"));
        }
        socket.shutdownOutput();
    }
}

java socket-Half off

Typically, the output stream is closed to indicate that the output has ended. However, this cannot be done when communicating on the network. Because when we close the output stream, the corresponding Socket of the output stream will also close, so the program will no longer be able to read data from the socket.

In order to cope with this situation, socket provides two semi-closed methods to close only the input stream or output stream of socket, which is used to indicate that the output data has been sent.

Method details:

shutdownInput (): The input stream of the socket is closed, and the program can also output data through the output stream of the socket;

shutdownOutput (): The output stream of the socket is closed, and the program can also read data through the input stream of the socket.

When the shutdownInput () or shutdownOutput () method is called to close the input stream or output stream, the socket is in a semi-closed state.

isInputShutdown () or isOutputShutdown () can be used to determine whether the socket is in a half-read state or a half-write state.

Note that even if the shutdownInput () and shutdownInput () methods are called one after another with the same socket, the socket instance is still not closed, except that the socket can neither output nor read data.

When the shutdownInput () or shutdownOutput () method is called to close the input stream or output stream, the socket cannot open the output stream or input stream again, so this practice is not suitable for interactive applications that need to maintain persistent communication state.


Related articles: