立即学习:https://edu.csdn.net/course/play/24458/296241?utm_source=blogtoedu
1.send和recv底层分析
1)不管是recv还是send都不是直接接收对方数据或者发送给对方数据,而是对自己的操作系统内存进行操作;
2)客户端与服务端并不是一个send对于一个recv;
3)send过程分析(此处以客户端向服务端发送数据为例):
#1.客户端将数据发送给自己的操作系统,即将数据给操作系统内存,这样就算是结束了send这个命令,而至于怎么将数据发送给服务端由客户端的操作系统决定;
#2.send需要经历的阶段:产生数据——将数据copy给客户端自己的操作系统内存
4)recv过程分析(以服务端接收客户端数据为例)
#1.服务端首先是等待客户端的数据,然后接收数据即可
#2.recv经历的阶段:wait data(耗时较长)——copy data(首先是客户端的操作系统内存的数据通过网关发送给服务端的操作系统内存,然后再由服务端的程序从自身的操作系统内存中copy data,再进行执行,这就完成recv的过程)
2.粘包产生的原因:由TCP协议中的优化算法nagle算法决定的。TCP协议存在的问题,在UDP协议中不会出现这种问题
1)产生粘包的条件:数据小且两次或多次发送数据的间隔小的情况下会产生粘包现象,所以使用TCP协议不是一定会发生粘包,只有满足条件才会
2)在TCP协议中,send是一条一条消息地发送数据,而recv却可以一次性接收多条消息发送的数据,即接收到的数据是一个整体,因为在时间间隔较短的时间内发送的小数据会在客户端的操作系统内存中会被合并成一个数据包,再发送给服务端的操作系统内存,因此无法判断出哪些数据是哪条消息的,TCP时面向流的
3)TCP是面向流的,为了减少IO传输
的次数进而增加传输数据的效率,采用了nagle算法,将间隔时间短的小数据合并成一个大的数据块进行接收处理,然后将处理后的大的数据块返回给客户端,而客户端无法识别出哪些数据是哪条信息的,故产生了粘包!
4)在客户端粘包的情况,在客户端时间间隔短的情况下发送两次数据,导致客户端发送的数据产生粘包现象
#客户端产生粘包的情况'''
客户端
'''
import socket
phone = socket.socket((socket.AF_INET,socket.SOCK_STREAM))
phone.connect(('127.0.0.1',8080))
phone.send('hello')
phone.send('world')'''
服务端
'''
import socket
phone = socket.socket((socket.AF_INET,socket.SOCK_STREAM))
phone.bind(('127.0.0.1',8080))
conn,client = phone.accept()res1 = conn.recv(1024)
#b'helloworld'
print('第一次接收的数据:',res1)res2 = phone.recv(1024)
#b''
print('第二次接收的数据:',res2)#客户端不存在粘包的现象,只需要在客户端的两次send之间加入一个time.sleep(2)即可,即破坏粘包产生的条件之一:间隔时间短的情况下发送多次数据
4)服务端产生粘包现象
#客户端
......
phone.send('hello'.encode('utf-8'))
time.sleep(5)
phone.send('world'.encode('utf-8'))
......#服务端
......
res1 = conn.recv(1)
#b'h'
print('第一次接收的数据',res1)
time.sleep(6)#服务器端比客户端多睡一秒钟,因此上一次的发送的未接收的数据‘ello’会和这次发送的world在服务器端的操作系统内存中合并在一起
res2 = conn.recv(1024)
#b'elloworld'
print('第二次接收的数据:',res2)
注:上述只是便于理解才用time.sleep()来解决粘包,实际上是非常不支持这样来解决粘包问题