欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

浅谈java socket的正确关闭姿势

程序员文章站 2022-03-11 12:40:58
java socket对应的是网络协议中的tcp,tcp的三次握手、四次挥手、11中状态什么的这里就不说了,不知道大家平常使用socket的时候如果不注意的情况下,会不会遇到各种异常报错。例如:jav...

java socket对应的是网络协议中的tcp,tcp的三次握手、四次挥手、11中状态什么的这里就不说了,不知道大家平常使用socket的时候如果不注意的情况下,会不会遇到各种异常报错。

例如:

java.net.socketexception:socket is closed

错误提示的出现场景:

自己主动关闭了socket,但是之后还从里面读写数据

software caused connection abort: socket write error

错误提示的出现场景:

对方已经关闭socket,依旧向对方写数据

connection reset (by peer)

错误提示出现的场景:

一端socket被关闭,另一端仍然发送数据,发送的第一个数据包 connection reset by peer

一端socket退出,退出时为关闭连接,另一端读数据 connection reset

所以在使用socket时,需要约定好双方读写完成的条件,然后关闭输入输出流:

socket.shutdowninput();
socket.shutdownoutput();

即当一方写入完成后,调用shutdownoutput关闭输出流,这时候对方的read方法就会返回-1,这时候对方就知道你写完了,对方可以关闭输入流,然后等待对方写入完成调用shutdownoutput后己方再调用shutdowninput,双方就正常关闭了输入输出流,这时候socket就不会出现异常了。

下面是一个socket交互的例子:

server端

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端

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 - 半关闭

通常,使用关闭输出流来表示输出已经结束。但在进行网络通信时则不能这样做。因为我们关闭输出流时,该输出流对应的socket也将随之关闭,这样程序将无法再从该socket中读取数据。

为了应付这种情况,socket提供了两个半关闭的方法用来只关闭socket的输入流或者输出流,用以表示输出数据已经发送完成。

方法详情:

shutdowninput():关闭该socket的输入流,程序还可以通过该socket的输出流输出数据;

shutdownoutput():关闭该socket的输出流,程序还可以通过该socket的输入流读取数据。

当调用shutdowninput()或shutdownoutput()方法关闭输入流或输出流后,该socket处于半关闭状态。

此时可以使用isinputshutdown()或isoutputshutdown()来判断该socket是否处于半读状态或半写状态。

需要注意的是,即使同一个socket先后调用shutdowninput()和shutdowninput()方法,该socket实例仍然没有被关闭,只是该socket既不能输出数据也不能读取数据而已。

当调用shutdowninput()或shutdownoutput()方法关闭了输入流或输出流之后,该socket无法再次打开输出流或输入流,因此这种做法不适合需要保持持久通信状态的交互式应用。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持。