粘包问题
TCP遗留问题--粘包
TCP发送数据的四种情况:
假设客户端分别发送了两个数据包D1和D2给服务端,由于服务端一次读取到的字节数是不确定的,故可能存在以下4种情况。
- 服务端分两次读取到了两个独立的数据包,分别是D1和D2,没有粘包和拆包;
- 服务端一次接收到了两个数据包,D1和D2粘合在一起,被称为TCP粘包;
- 服务端分两次读取到了两个数据包,第一次读取到了完整的D1包和D2包的部分内容,第二次读取到了D2包的剩余内容,这被称为TCP拆包;
- 服务端分两次读取到了两个数据包,第一次读取到了D1包的部分内容D1_1,第二次读取到了D1包的剩余内容D1_2和D2包的整包。
特例:如果此时服务端TCP接收滑窗非常小,而数据包D1和D2比较大,很有可能会发生第五种可能,即服务端分多次才能将D1和D2包接收完全,期间发生多次拆包。
-
发送端需要等缓冲区满才发送出去,造成粘包(发送数据时间间隔很短,数据很小,会合道一起,产生粘包)
客户端:
import socket client = socket.socket(socket.AF_INET,socket.SOCK_STREAM) addr = ('127.0.0.1',8000) client.connect(addr) while True: # 发送消息 msg = input("请输入你要讲的话>>>>") client.send(bytes(msg.encode('utf8'))) # 接受消息 leng = client.recv(10) print(leng.decode('gbk'))
服务端:
import socket import subprocess service = socket.socket(socket.AF_INET,socket.SOCK_STREAM) addr = ('127.0.0.1',8000) service.bind(addr) service.listen(5) conn,addr = service.accept() while True: # 接受消息 client_msg = conn.recv(1024) print(client_msg) common = client_msg.decode('utf8') print(common) obj = subprocess.Popen(common, shell=True, stderr=subprocess.PIPE, stdout = subprocess.PIPE ) stderr = obj.stderr.read() stdout = obj.stdout.read() conn.send(stdout+stderr)
-
接收方不及时接受缓冲区的包,造成多个包接受(客户端发送了一段数据,服务端只收了一小部分,服务端下次再收的时候还是从缓冲区拿上次遗留的数据,产生粘包)
客户端:
# _*_coding:utf-8_*_ __author__ = 'nickchen121' import socket BUFSIZE = 1024 ip_port = ('127.0.0.1', 8080) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) res = s.connect_ex(ip_port) s.send('hello feng'.encode('utf-8'))
服务端:
# _*_coding:utf-8_*_ __author__ = 'nickchen121' from socket import * ip_port = ('127.0.0.1', 8080) TCP_socket_server = socket(AF_INET, SOCK_STREAM) TCP_socket_server.bind(ip_port) TCP_socket_server.listen(5) conn, addr = TCP_socket_server.accept() data1 = conn.recv(2) # 一次没有收完整 data2 = conn.recv(10) # 下次收的时候,会先取旧的数据,然后取新的 print('----->', data1.decode('utf-8')) print('----->', data2.decode('utf-8')) conn.close()