产生粘包:
1. 发送端需要等缓冲区满才发送出去, 造成粘包 (发送数据时间间隔很短, 数据了很小, 会合到一起, 产生粘包)
2. 接收方不及时接收缓冲区的包, 造成多个包接收 (客户端发送了一段数据, 服务端只收了一小部分,
服务端下次再收的时候还是从缓冲区拿上次遗留的数据, 产生粘包)
所谓粘包问题主要还是因为接收方不知道消息之间的界限, 不知道一次性提取多少字节的数据所造成的.
补充:
recv 里指定的 1024 意思是从缓存里一次拿出 1024 个字节的数据
send 的字节流是先放入己端缓存, 然后由协议控制将缓存内容发往对端, 如果待发送的字节流大小大于缓存剩余空间, 那么数据丢失, 用 sendall 就会循环调用 send, 数据不会丢失
1. 解决方法:
先发送消息的长度, 再发送消息, 接收的时候可以根据消息的长度循环取数据
或者发送的数据量比较小时, 可以把消息加载在一个长字符串中传递, 填充满缓存
服务端:
- #_*_coding:utf-8_*_
- from socket import *
- import subprocess
- import struct
- ip_port=('127.0.0.1',8080)
- BUFSIZE=1024
- tcp_socket_server=socket(AF_INET,SOCK_STREAM)
- tcp_socket_server.bind(ip_port)
- tcp_socket_server.listen(5)
- while True:
- conn,addr=tcp_socket_server.accept()
- print('客户端',addr)
- while True:
- cmd=conn.recv(BUFSIZE)
- print(cmd.decode('utf-8'))
- if len(cmd) == 0:break
- res=subprocess.Popen(cmd.decode('utf-8'),shell=True, #本地执行客户端传过来的命令
- stdout=subprocess.PIPE,
- stdin=subprocess.PIPE,
- stderr=subprocess.PIPE)
- stderr=res.stderr.read()
- if stderr:
- back_msg=stderr
- else:
- back_msg=res.stdout.read()
- print(len(back_msg))
- conn.send(struct.pack('i',len(back_msg))) #先发送长度 i 4 个字节
- conn.sendall(back_msg) #再发送内容
- # conn.close()
- #_*_coding:utf-8_*_
- import socket
- import struct
- BUFSIZE=100 #故意设小一点, 一次取不完
- ip_port=('127.0.0.1',8080)
- s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
- res=s.connect_ex(ip_port)
- while True:
- msg=input('>>:').strip() #输入命令
- if len(msg) == 0:continue
- if msg == 'quit':break
- s.sendall(msg.encode('utf-8'))
- head_info=s.recv(4) #和服务端对应起来, pack i 是 4 个字节
- head_len=struct.unpack('i',head_info)[0] #解压 pack 的内容
- print("head_len",head_len)
- res=0
- data=b''
- while res < head_len: #循环取数据
- data+=s.recv(BUFSIZE)
- res=len(data)
- # print('res',res)
- # r_d=s.recv(BUFSIZE)
- # print('r_d',len(r_d))
- # data+=r_d
- # print('data',len(data))
- # res+=len(r_d)
- print(data.decode('gbk'))
来源: http://www.bubuko.com/infodetail-2850115.html