解决socket TCP粘包
前言
在socket网络程序中,TCP和UDP分别是面向连接和非面向连接的。因此TCP的socket编程,收发两端(客户端和服务器端)都要有成对的socket,因此,发送端为了将多个发往接收端的包,更有效的发到对方,使用了优化方法(Nagle算法),将多次间隔较小、数据量小的数据,合并成一个大的数据块,然后进行封包。这样,接收端,就难于分辨出来了,必须提供科学的拆包机制。
对于UDP,不会使用块的合并优化算法,这样,实际上目前认为,是由于UDP支持的是一对多的模式,所以接收端的skbuff(套接字缓冲区)采用了链式结构来记录每一个到达的UDP包,在每个UDP包中就有了消息头(消息来源地址,端口等信息),这样,对于接收端来说,就容易进行区分处理了。所以UDP不会出现粘包问题。
拔剑神曲βios:
正文
server端:
import socket
import subprocess
import struct
import json
def server(host,port):
servers=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
servers.bind((host,port))
servers.listen(1)
while True:
shargs,args=servers.accept()
print('[+] ソースIP:{}'.format(args[0]))
while True:
try:
msg=shargs.recv(1024)
res=subprocess.Popen(msg.decode('utf-8'),shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
out_read=res.stdout.read()
err_read=res.stderr.read()
data_size=len(out_read)+len(err_read) /获取数据长度
head_dic={"data_size":data_size} //打包成json
head_json=json.dumps(head_dic) //为str类型
head_bytes=head_json.encode('utf-8') //报文编码为utf8
head_len=len(head_bytes) //报文长度
shargs.sendall(struct.pack("i",head_len)) //先发送报文长度
shargs.sendall(head_bytes) //发送报文
shargs.sendall(out_read) //发送真实数据
shargs.sendall(err_read)
except:
pass
if __name__ == '__main__':
host='127.0.0.1'
port=4448
server(host,port)
client段
import socket
import struct
import json
def client(host,port):
clients=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
try:
clients.connect((host,port))
print('[+] 接続が成功する')
except:
print('[-] 接続失敗')
exit()
while True:
user=input('コマンドを入力してください:')
if not user:
continue
clients.sendall(bytes(user,encoding='utf8'))
head_rec=clients.recv(4) //读取4个字符
print('head_rec',head_rec)
head_len=struct.unpack("i",head_rec)[0] //解开报文第一个字符为16进制(获取长度)
print(head_len)
head_byte=clients.recv(head_len) //读取指定长度的数据
print('head_byte:',head_byte)
head_json=head_byte.decode('utf8') //获取到json并解码为utf8
head_dic=json.loads(head_json) //解析josn
data_size=head_dic["data_size"] //得到字节总
recv_size=0
recv_data=b''
while recv_size<data_size:
js=clients.recv(1024) //读取数据
print(js)
recv_size+=len(js) //字节和返回数据长度加在一起
print(recv_size)
print('recv_data:',recv_data) //b''+返回数据
recv_data+=js
print(recv_data.decode('utf-8')) //解码为utf-8
clients.close()
if __name__ == '__main__':
host='127.0.0.1'
port=4447
client(host,port)
转载请声明:转自422926799.github.io
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。
文章标题:解决socket TCP粘包
本文作者:九世
发布时间:2018-11-16, 19:40:24
最后更新:2019-04-19, 20:36:16
原始链接:http://jiushill.github.io/posts/ee45ea9a.html版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。