Wireshark理解粘包和粘包

前言

博主写的目的一是把自己所学的知识做一个记录方便复习,二是让更多的人看到并指出其中的错误指出,参考内容在文章末尾如有侵权请告知马上删除,不喜勿喷。

通过学习,我们知道基于传输层开发通讯程序,会出现粘包和粘包,所以今天通过Wireshark抓包工具来看看具体的传输内容。

TCP可靠传输的建立

socket套接字

首先来介绍几个相关的API函数

socket函数

	sd = socket(protofamily,type,proto);
  • 方法:创建一个套接字,用于传输层和应用层中的应用进程做数据交互
  • 返回值:调用方法返回一个套接字描述符sd
  • 参数1:protofamily为协议族,protofamily = PF_INET(TCP/IP)
  • 参数2:type为类型:SOCK_STREAM,SOCK_DGRAM or SOCK_RAW
    – SOCK_STREAM表示TCP传输,特点:可靠、面向连接、字节流传输、点对点
    – SOCK_DGRAM表示UDP传输,特点:不可靠、非连接、数据报传输
  • 参数3:proto为协议号,默认为0
    示例代码
	struct protoent *p; 
	p=getprotobyname("tcp"); 
	SOCKET sd=socket(PF_INET,SOCK_STREAM,p->p_proto); 

在这里插入图片描述

bind函数

	int bind(sd,localaddr,addrlen);
  • 方法:给socket函数创建的sd描述符绑定一个端点地址(通常客户端是不需要我们自己来绑定)
  • 返回值:调用方法返回一个套接字描述符sd
  • 参数1:套接字sd描述符
  • 参数2:绑定的本地端点地址
    – 端点地址:本地IP地址+端口号
  • 参数3:

listen函数

	int listen(sd,queuesize);
  • 方法:设置服务器端的流套接字处于监听状态(仅被服务器端调用,仅用于面向连接的流套接字,不能用于UDP类型的套接字
  • 返回值:0:成功 SOCKET_ERROR :失败
  • 参数1:套接字sd描述符
  • 参数2:queuesize为请求队列大小,用于设置连接请求队列大小的

在这里插入图片描述

connect函数

	connect(sd,saddr,saddrlen);
  • 方法:客户端调用connect函数来使客户套接字(sd)与指定服务器端的套接字进行连接(仅用于客户端,可用于TCP客户端和UDP客户端
  • 返回值:0:成功 SOCKET_ERROR :失败
  • 参数1:套接字sd描述符
  • 参数2:saddr 可以理解为指定服务器的特定端口

accept函数

	newsock = accept(sd,caddr,caddrlen);
  • 方法:服务器端用accept函数从处于监听状态的流套接字sd的客户端请求队列中取出排在最前的一个客户端连接(该队列是存放已完成三次握手的客户端连接,未完成三次握手的客户端连接存放另外一个队列),并创建一个新的套接字newsock来与客户套接字创建连接通道(仅用于TCP服务端切仅用于服务器
  • 返回值:服务端创建的新的套接字,用来与客户端建立连接进行通讯
  • 参数1:服务端套接字sd描述符
  • 参数1:caddr 可以理解为客户端的指定端口
    在这里插入图片描述

setsockopt、setsockopt函数

	int setsockopt(int sd, int level, int optname, *optval, int optlen);
	int getsockopt(int sd, int level, int optname,  *optval, socklen_t *optlen);
  • setsockopt()函数用来设置套接字sd的选项参数
  • getsockopt()函数用于获取任意类型、任意状态套接口的选项当前值,并把结果存入optval

总结

在这里插入图片描述

TCP的三次握手

三次握手是发生在客户端向服务器发送TCP连接请求,当三次握手成功完成,则把该客户端连接放到握手完成队列中,然后服务端通过accept方法来获取该客户端连接并创建新的socket来与客户端通讯。

一开始主机A和主机B 处于close(关闭)状态,然后B的TCP服务器进程先创建传输控制块(TCP),处于LISTEN状态来监听客户机A的连接,当客户端和服务端处于ESTABLISHED状态,客户端就可以调用send方法向服务器端发送消息,服务端可以通过recv方法获取消息,反之服务端也可以调用send方法给客户端发送数据。

三次握手图

在这里插入图片描述
三次握手的大概流程

  • A的TCP客户进程也是首先创建传输控制块TCB,然后打算建立TCP连接时,向B发送请求报文段,这时候首部的同步位SYN=1,同时选择一个初始序号seq=x,TCP规定,SYN报文段(SYN=1的报文段)不能携带数据,但是必须消耗掉一个序号,这时候,客户端进入了SYN-SEND(同步已发送)状态
  • B收到连接请求的时候,如果同意建议连接,则会向A发送确认。在确认报文中应把SYN和ACK置为1,确认号是ack=x+1(表示下次B期待收到A的seq为x+1),同时也会为自己选择一个最初的seq=y,也不能携带数据且消耗一个序列号。这时候服务器进入SYN-RCVD状态。
  • 客户端收到B的确认后,还要给服务器发送确认已收到确认。确认报文段的ACK置1,确认号ack=y+1,而自己的序号ack=x+1.TCP的标准规定,ACK报文段可以携带数据,单如果不携带数据则不消化序号,在这种情况,下一个数据报文段的序号仍是seq=x+1,这时,TCP已建立连接。A进入ESTABLISHED(已经建立连接)状态。

利用工具查看

在这里插入图片描述
第5~7 是TCP的三次握手
第8行客户端发送数据
在这里插入图片描述

第9行服务器端回复数据
在这里插入图片描述
第10和第11,客户端连续发送2次数据
在这里插入图片描述
10和11两次连续发到TCP缓冲区中,但是从socket从缓冲区中读到的数据并不一点是上面那种情况

服务器发送和服务器接收

客户端发送内容

        String xml = "hi,blueheart,hello world";
        while (true){
            out.write(xml.getBytes());
            out.flush();
        }

服务器端收到的打印内容
在这里插入图片描述
客户端从套接字写入到TCP缓冲区中,然后TCP 中通过的某些机制,发送到服务器中TCP的缓冲区中,最好通过套接字读到服务器程序里,输出为上面的内容。通过上面,我们可以知道客户端发送的数据和服务器接收的数据不是一样的,这就是我们下面要讨论的粘包和粘包的现象。

粘包和粘包

handler组件会根据分隔符或者长度从缓冲区里面读出数据

参考资料
哈尔滨大学李金龙老师的计算机网络 链接: https://www.icourse163.org/course/HIT-154005?from=searchPage.

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值