zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    CSS input
    CSS 伪类选择器
    input placeholder 文字颜色修改
    css flex弹性布局学习总结
    jqGrid使用方法
    GridView控件RowDataBound事件的一个实例
    GridView控件RowDataBound事件中获取列字段值的几种途径 !!!
    .net中ckeditor的应用
    博客第一天
    用python实现数学多元数学方程式计算
  • 原文地址:https://www.cnblogs.com/lwmp/p/15187403.html
Copyright © 2011-2022 走看看