一、粘包
什么是粘包
只有TCP只有粘包现象,UDP永远不会粘包
所谓粘包问题主要还是因为接收方不知道之间的界限,不知道一次性提取多少字节的数据所造成的
两种情况发生粘包:
1、发送端需要等缓冲区满才发送出去,造成粘包(发送数据时时间间隔短,数据很小,会合在一起,产生粘包)
from socket import * phone=socket(AF_INET,SOCK_STREAM) phone.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) phone.bind(('127.0.0.1',8080)) phone.listen(5) conn,client_addr=phone.accept() data1=conn.recv(1024) print('data1: ',data1) data2=conn.recv(1024) print('data2:',data2)
from socket import * import time phone=socket(AF_INET,SOCK_STREAM) phone.connect(('127.0.0.1',8080)) phone.send('hello'.encode('utf-8')) # time.sleep(5) phone.send('world'.encode('utf-8'))
2、接收方不及时接收缓冲区的包,造成多个包接收(客户端发送一段数据,服务端之接收了一小部分,服务端下次在接受的时候还是
从缓冲区拿上上次遗留的数据,产生粘包)
from socket import * phone=socket(AF_INET,SOCK_STREAM) phone.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) phone.bind(('127.0.0.1',8080)) phone.listen(5) conn,client_addr=phone.accept() data1=conn.recv(10) print('data1: ',data1) data2=conn.recv(4) print('data2:',data2)
from socket import * import time phone=socket(AF_INET,SOCK_STREAM) phone.connect(('127.0.0.1',8080)) phone.send('helloworld'.encode('utf-8')) phone.send('egon'.encode('utf-8'))
二、解决粘包问题
struct模块
import struct res=struct.pack('i',111112) print(res,len(res),type(res)) unpack_res=struct.unpack('i',res) print(unpack_res[0])
struct.error: 'i' format requires -2147483648 <= number <= 2147483647 #这个是范围
import socket import struct phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #买手机 phone.connect(('127.0.0.1',8082)) #绑定手机卡 #发,收消息 while True: cmd=input('>>: ').strip() if not cmd:continue phone.send(cmd.encode('utf-8')) #先收报头 header_struct=phone.recv(4) unpack_res = struct.unpack('i', header_struct) total_size=unpack_res[0] #再收数据 recv_size=0 #10241=10240+1 total_data=b'' while recv_size < total_size: recv_data=phone.recv(1024) recv_size+=len(recv_data) total_data+=recv_data print(total_data.decode('gbk')) phone.close()
import socket import subprocess import struct phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #买手机 phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) #就是它,在bind前加 phone.bind(('127.0.0.1',8082)) #绑定手机卡 phone.listen(5) #开机 print('starting...') while True: #链接循环 conn,client_addr=phone.accept() #等电话 (链接,客户的的ip和端口组成的元组) print('-------->',conn,client_addr) #收,发消息 while True:#通信循环 try: cmd=conn.recv(1024) if not cmd:break #针对linux #执行cmd命令,拿到cmd的结果,结果应该是bytes类型 #。。。。 res = subprocess.Popen(cmd.decode('utf-8'), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout=res.stdout.read() stderr=res.stderr.read() #先发报头(转成固定长度的bytes类型) header = struct.pack('i',len(stdout)+len(stderr)) conn.send(header) #再发送命令的结果 conn.send(stdout) conn.send(stderr) except Exception: break conn.close() #挂电话 phone.close() #关机