Socket连接数据报文与TCP协议理论的对应

本文基于Java代码构建了一个网络通信的模型.模拟客户端和服务器通信的全流程,从连接到数据传输再到断开连接。一个基于TCP协议网络连接的全流程。然后运行这个模型,进行网络数据交换,同时使用WireShark抓取数据报文进行分析,以此论证TCP协议

1.网络通信模型

这里服务端创建绑定的端口为8090,在SocketServer的bind绑定ip+port方法中指定。形成了一个二元组。执行了accept()方法阻塞等待,直到接收到客户端的消息后才会继续执行,将客户端发送的消息从内存缓冲区中读取出来。
客户端只需要创建一个Socket套接字,传入目标主机ip和port端口号,客户端的port由操作系统进行分配,这里调用wirte方传输了一个”hello world”字符串数据到内存缓冲区,然后需要执行flush方法将内存缓冲区的数据刷新到网卡中,即经过了OS的协议栈进行封包后再传输。

package com.lwl.socket;
import java.io.*;
import java.net.*;
import java.util.concurrent.CountDownLatch;

/**
 * @author lwl
 * @create 2023/5/8 14:20
 */
public class socket_comm {

    static CountDownLatch countDownLatch = new CountDownLatch(1); //计时锁,1个长度单位,控制两个线程的时序

    public static void main(String[] args) {
        //客户端
        new Thread(()->{
            Socket socket = null;
            OutputStream ops = null;
            BufferedWriter bufferedWriter = null;
            try {
                countDownLatch.await();  //需要等服务器启动!
                socket = new Socket("172.220.52.238",8090);  //往主机服务器连
                ops = socket.getOutputStream();
                bufferedWriter = new BufferedWriter(new OutputStreamWriter(ops));
                bufferedWriter.write("hello world");
                bufferedWriter.flush();
            }catch (IOException e){
                e.printStackTrace();
            }catch (InterruptedException e1)
            {
                e1.printStackTrace();
            }
            finally {
                try {
                    bufferedWriter.close();
                    ops.close();
                    socket.close();
                }catch (IOException e){
                    e.printStackTrace();
                }
            }
        }).start();

        //服务端
        ServerSocket serverSocket = null;
        Socket accept = null;
        InputStream inputStream = null;
        BufferedReader bufferedReader = null;
        try {
            serverSocket = new ServerSocket();
            serverSocket.bind(new InetSocketAddress(8090));
            countDownLatch.countDown();
            accept = serverSocket.accept();
            inputStream = accept.getInputStream();
            bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
            String temp = null;
            while((temp = bufferedReader.readLine())!=null){
                System.out.println(temp);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                bufferedReader.close();
                inputStream.close();
                if(accept!=null){ accept.close();}
                serverSocket.close();
            }catch (IOException e){
                e.printStackTrace();
            }
        }
    }
}

2.WireShark抓包

Java使用的Socket套接字对应的协议为TCP协议,所以我们在使用WireShark进行抓包时,只需要知道src源ip和 目的ip 以及协议TCP,即可通过过滤筛选获取到指定的数据报文。如下图,使用WireShark抓取到网络通信的数据报文有9个,代表了一个完整的TCP报文的生命周期。分别为:三次握手建立连接,数据传输阶段,四次挥手断开连接。
在这里插入图片描述
接下来,我们开始对这9条报文进行分解吧。

2.1 TCP三次握手建立连接

第一条数据报文为客户端主动发送携带SYN标识符的连接请求给服务器,Seq=0,Len=0即代表这条数据报文的序号为0,长度为0,并没有任何的数据传输。只是作为连接请求的数据报文。
第二条数据报文为服务器响应客户端的连接请求,携带了SYN和ACK标识符,SYN表示服务器也发送了一个建立连接的请求,ACK是对上一条数据客户端发送给服务器数据报文的回复。Seq=0,ACK=1,表示当前报文的序号=0,同时ACK=1,表示客户端发送给服务器的seq序号<1的数据报文我都接受到了,也就是告诉客户端,你的第一条数据报文我接受到了,后面的所有ACK确认字符都同理。一般除了第一条客户端主动向服务器发送的连接请求没有ACK意外,这次TCP连接的所有数据报文都有ACK确认字符的。表示对让一条数据报文的确认接收。
在这里插入图片描述
而第三条数据报文为客户端对服务器连接请求的ACK确认,Seq=1,Ack=1,表示当前数据报文的序号为1以及ACK确认你(服务器)向我(客户端)发送的Seq<1的数据报文我都接收到了。
至此,所有SYN表示的连接请求都已发送,且都被ACK确认,客户端和服务器的TCP连接建立成功。图解如下,可抽象为“在吗?” “在啊,你还在吗?”“我也在啊!”,原图来源谢希仁教授的计算机网络一书。
在这里插入图片描述

2.2 数据传输阶段

在连接建立完成之后,就可以开始数据传输了。后面的两条数据报文正是数据传输的过程。数据传输阶段的第一条报文的详细信息如下图所示,"hello world"数据信息被顺利抓取。
在这里插入图片描述
可以发现这一条报文的除了ACK描述符对服务器报文的确认外,还多了一个PSH描述符,这个是将内存缓冲区中的”hello world”字符串数据经过OS协议栈封包传入网卡,由网卡对该数据报进行发送。它的序号Seq=1,长度Len=11(对应上字符串的长度),这条报文要被服务端完整接受的话,那么下一条服务端回发报文的ACK必须大于12,而下一条报文如下图所示:
在这里插入图片描述
这条报文的ACK=12只确认了客户端传过来的序号Seq小于12的数据报,而客户端发送过来Seq=12的数据报文没有接收到。所以理论上,客户端接下来需要重传Seq=12的数据报文。

2.3 TCP四次挥手断开连接

请看最后四条数据报文。
在这里插入图片描述
可以发现,客户端发送给服务端的第一条报文的Seq=12的报文,重传漏发的数据报文,验证了上面所述,同时携带了断开连接的描述符FIN,表示客户端主动向服务端发送一个FIN关键字表明断开连接操作。
而第二条数据报文服务端回发给客户端的数据报文中的描述符只有ACK,只对客户端的断开报文进行确认,并没有也发出FIN描述符表明我也可以断开了,这是因为可能此时服务器的内存中还有数据没有flush到网卡中,由网卡进行传输,这里是等待服务端把缓冲区中的数据发送完毕。
第三条报文仍然是服务端回发给客户端的数据报文,这次携带了FIN描述符,表明我数据也发完了,可以断开了。
最后一条报文是客户端对服务端断开请求的ACK确认。至此,TCP的连接就断开了。
整个TCP挥手流程如下图所示,原图同样来源于谢希仁教授的计算机网络,这里进行了抽象笔记表达。
在这里插入图片描述

3.后言

该文从网络通信代码,理论,网络中实际传输数据报三个方面进行学习。在整个过程中,实际都是对计算机网络中阐述的理论的辩证,让TCP连接-数据交流-断开的全流程在实际网络数据报的传输中得到充分的,立体的体现,从而突显理论的正确性。
最后我们在互联网中的交流并不是完全保密的,虽然有加密算法的机制,但破解机制依然强大,所以希望谨言,你的不当言语可能也会在某天被有心人抓取,读取到你的"hello world"。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值