java socket

前言

本文主要包含以下内容:

  1. 代码示例
  2. wireshark抓包内容,帮助理解
  3. 一些自己的简单理解和胡乱想法

才疏学浅,如有错误欢迎指证。

正文

Part - 1

先从一个最简单的代码开始:

展开Server代码

public class ServerOne {

    public static void main(String[] args) {
        try {
            ServerSocket serverSocket = new ServerSocket(9999);
            Socket socket = serverSocket.accept();
            BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));

            String line = reader.readLine();
            System.out.println(line);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

展开client代码

public class ClientOne {

    public static void main(String[] args) {
        try {
            Socket socket = new Socket("127.0.0.1", 9999);
            BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
            bufferedWriter.write("Hello, this is my first socket");

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

注意,先起Server服务,再运行Client的代码,这时你会发现:server并没有打印本应收到的message,而是报了一个异常java.net.SocketException: Connection reset

我们用wireshark抓一下包,看看都发生了什么

展开图片

从上图中可以看到,三次握手之后,本应发送一个PSH标志的报文段,但是却并没有,而是直接发了一个RST的报文。

找了一个RST标志位的解释:

RST标志位用来复位一条连接。当RST=1时,表示出现严重错误,必须释放连接,然后再重新建立。

我以自己的小脑子理解了一下,大概就是非正常关闭的情况下,会给对方发一个RST的报文,告诉对方:我要挂了,你要想继续跟我玩儿的话,得重新建立一次连接(我妈拿着棍子让我回家吃饭了,你要想找我玩儿的话,下午再找个理由来叫我)。

既然这样的话,那我们改动一下client的代码,让它在结束的时候,正常关闭连接,看看这个时候会发生什么,代码如下:

展开client代码

public class ClientOne {

    public static void main(String[] args) {
        try {
            Socket socket = new Socket("127.0.0.1", 9999);
            BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
            bufferedWriter.write("Hello, this is my first socket");

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

从上面client的代码看出,好,我现在正式通知你,我要关闭连接了。
再重新运行一下代码,发现:咦,没有报错了,但是server仍然没有打印任何message呀。

我们再来看一下抓包内容:

展开图片

观察上面图片,发现:咦,这次client倒是正常的发送了FIN报文告诉server,我要关闭了,但是server端没有正常关闭,没有发送FIN给client,这好办,我们再改造一下server端的代码。

展开server代码

public class ServerOne {

    public static void main(String[] args) {
        try {
            ServerSocket serverSocket = new ServerSocket(9999);
            Socket socket = serverSocket.accept();
            BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));

            String line = reader.readLine();
            System.out.println(line);

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

我们再看看这次的报文:

展开图片

三次握手,四次挥手倒是一切正常,但是丫的没数据呀。。。仔细一看,噢,忘了flush缓冲区了,继续改代码:

展开client代码

public class ClientOne {

    public static void main(String[] args) {
        try {
            Socket socket = new Socket("127.0.0.1", 9999);
            BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
            bufferedWriter.write("Hello, this is my first socket");
            bufferedWriter.flush();
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

我发誓这一定是最后一次看这该死的报文:

展开图片

后记

这里补充一下不用缓冲区的代码:

server

public class ServerTwo {
    public static void main(String[] args) {
        try {
            ServerSocket serverSocket = new ServerSocket(9999);
            Socket socket = serverSocket.accept();

            DataInputStream dataInputStream = new DataInputStream(socket.getInputStream());
            System.out.println(dataInputStream.readUTF());
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

client

public class ClientTwo {
    public static void main(String[] args) {
        try {
            Socket socket = new Socket("127.0.0.1", 9999);
            OutputStream outputStream = socket.getOutputStream();
            DataOutputStream dataOutputStream = new DataOutputStream(outputStream);
            dataOutputStream.writeUTF("Hello, this is my second socket");

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


参考:
https://www.jianshu.com/p/cde27461c226

posted on 2021-08-25 22:57  斜月三星一太阳  阅读(26)  评论(0编辑  收藏  举报