Day 29 网络编程3
网络编程3
粘包问题
tcp协议才会有粘包问题,udp协议没有粘包问题
粘包问题的几种情况
- D1和D2间隔时间长,两者数据量小,不会发生粘包问题
- D1和D2间隔时间非常短,数据量小,会发生粘包问题,tcp协议本身规定的
- D2比较大,D1比较小,间隔时间短,服务端一次性读取D1和D2的一部分,出现了粘包问题
- D1比较大,D2比较小,间隔时间短,服务端先获取一部分D1,然后获取D1的剩余部分和D2,出现粘包问题
如何解决粘包问题
- 两个数据间的发送间隔变长
- 发送数据之前告诉客户端数据的大小
解决粘包问题
问题的根源在于,接收端不知道发送端将要传送的字节流的长度,所以解决粘包的问题就是为让如何让发送端在发书数据前,吧自己将要发送的字节流总大小让接收端知晓,然后接收端来一个死循环接收完所有数据
解决粘包问题的核心就是:为字节流加上自定义固定长度的报头,报头中含有字节流长度没然后一次send到对端,对端在界首市,先从缓存中取出定长的报头没然后再取真实数据
struct模块
通过pack和unpack把一串数字压缩成4个字节,通常使用的格式是'i'
服务端
from socket import *
import struct,subprocess
server = socket(AF_INET,SOCK_STREAM)
server.bind(('127.0.0.1',8000))
server.listen(5)
print('start...')
while True:
conn,client_addr=server.accept()
while True:
try:
cmd = conn.recv(1024)
print(cmd)
pipeline=subprocess.Popen(cmd.decode('utf-8'),
shell=True,
stderr=subprocess.PIPE,
stdout=subprocess.PIPE)
stderr=pipeline.stderr.read()
stdout=pipeline.stdout.read()
count_len=len(stderr)+len(stdout)
guding_bytes=struct.pack('i',count_len)
conn.send(guding_bytes)
conn.send(stdout+stderr)
except ConnectionResetError:
break
客户端
from socket import *
import struct
client=socket(AF_INET,SOCK_STREAM)
client.connect(('127.0.0.1',8000))
while True:
cmd=input('please input your cmd')
client.send(cmd.encode('utf-8'))
guding_bytes=client.recv(4)
count_len=struct.unpack('i',guding_bytes)[0]
data=client.recv(count_len)
print(data.decode('gbk'))
TCP协议粘包问题分析
- nagle算法规定,TCP协议会将数据量较小,时间间隔短的数据合并为一条发送给客户端
- 接受法不及时接收缓冲区的包,造成了多个包接收(客户端发送了一段数据,服务端只收了一小部分,服务端下次在手的时候还是从缓冲区拿上次遗留的数据,
UDP套接字
UDP是无链接的,先启动哪一端都不会报错
UDP协议是数据包协议,发空的时候也会自带报头,因此客户端输入空,服务端也能收到
UDP协议一般不用于传输大数据
UDP套接字虽然没有粘包问题,但是不能替代TCP套接字,因为UDP协议有一个缺陷,如果数据发送的途中,数据丢失,则数据就丢失了,而TCP协议则不会有这种缺陷,因此一般UDP套接字用于无关紧要的数据发送