本文摘自PHP中文网,作者little bottle,侵删。
本文主要讲述的是怎么去解决tcp粘包问题,其一是分两次通讯分别传递内容大小和内容,其二是一次通讯直接传递内容大小和内容。想了解的朋友可以详细看看本篇文章,希望对你有所帮助。第一部分:简介tcp socket通信的底层原理
原理解析图:

1 socket通信过程如图所示:首先客户端将发送内容通过send()方法将内容发送到客户端计算机的内核区,然后由操作系统将内容通过底层路径发送到服务器端的内核区,然后由服务器程序通过recv()方法从服务器端计算机内核区取出数据。
2 因此我们可以了解到,send方法并不是直接将内容发送到服务器端,recv方法也并不是直接将从客户端发来的内容接收到服务器程序内存中,而是操作自己机器的内核区。
第二部分:产生粘包的原因(只针对tcp)
产生粘包的情况有两种:
1 1:当连续发送数据时,由于tcp协议的nagle算法,会将较小的内容拼接成大的内容,一次性发送到服务器端,因此造成粘包2 3 2:当发送内容较大时,由于服务器端的recv(buffer_size)方法中的buffer_size较小,不能一次性完全接收全部内容,因此在下一次请求到达时,接收的内容依然是上一次没有完全接收完的内容,因此造成粘包现象。
也就是说:接收方不知道该接收多大的数据才算接收完毕,造成粘包。
相关教程:TCP/IP视频教程
第三部分:如何解决上述两种粘包现象?
思路一:对于第一种粘包产生方式可以在两次send()直接使用recv()来阻止连续发送的情况发生。代码就不用展示了。
思路二:由于产生粘包的原因是接收方的无边界接收,因此发送端可以在发送数据之前向接收端告知发送内容的大小即可。代码示例如下:
方式一:分两次通讯分别传递内容大小和内容
服务器端代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | # __author__:Kelvin
# date:2019/4/28 21:36
from socket import *
import subprocess
server = socket(AF_INET, SOCK_STREAM)
server.bind(( "127.0.0.1" , 8000))
server.listen(5)
while True:
conn, addr = server.accept()
print( "创建了一个新的连接!" )
while True:
try :
data = conn.recv(1024)
if not data: break
res = subprocess.Popen(data.decode( "utf-8" ), shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE,
stderr=subprocess.PIPE)
err = res.stderr.read()
if err:
cmd_msg = err
else :
cmd_msg = res.stdout.read()
if not cmd_msg: cmd_msg = "action success!" .encode( "gbk" )
length = len(cmd_msg)
conn.send(str(length).encode( "utf-8" ))
conn.recv(1024)
conn.send(cmd_msg)
except Exception as e:
print(e)
break
|
客户端代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | # __author__:Kelvin
# date:2019/4/28 21:36
from socket import *
client = socket(AF_INET, SOCK_STREAM)
client.connect(( "127.0.0.1" , 8000))
while True:
inp = input( ">>:" )
if not inp: continue
if inp == "quit" : break
client.send(inp.encode( "utf-8" ))
length = int(client.recv(1024).decode( "utf-8" ))
client.send( "ready!" .encode( "utf-8" ))
lengthed = 0
cmd_msg = b ""
while lengthed < length:
cmd_msg += client.recv(1024)
lengthed = len(cmd_msg)
print(cmd_msg.decode( "gbk" ))
|
方式二:一次通讯直接传递内容大小和内容
阅读剩余部分
相关阅读 >>
解决tcp粘包问题的两种办法
http和html分别指什么
angular8如何封装http服务
什么是http,http请求方式和传递数据类型是什么?
http状态代码是什么
nodejs http请求相关的总结介绍
[tcp/ip] 数据链路层-ethereal 抓包分析数据帧
前端开发紧密相关的http协议知识
一次性搞懂 http、https、spdy、http2
[http] tcp/ip详解 链路层 网络层 传输层 应用层
更多相关阅读请进入《tcp/ip》频道 >>
人民邮电出版社
本书对 Vue.js 3 技术细节的分析非常可靠,对于需要深入理解 Vue.js 3 的用户会有很大的帮助。——尤雨溪,Vue.js作者
转载请注明出处:木庄网络博客 » 解决tcp粘包问题的两种办法