视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
解决tcp粘包问题的两种办法
2020-11-27 19:26:34 责编:小采
文档
 本文主要讲述的是怎么去解决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()来阻止连续发送的情况发生。代码就不用展示了。

思路二:由于产生粘包的原因是接收方的无边界接收,因此发送端可以在发送数据之前向接收端告知发送内容的大小即可。代码示例如下:

  方式一:分两次通讯分别传递内容大小和内容

  服务器端代码:

# __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

 客户端代码:

# __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"))

  方式二:一次通讯直接传递内容大小和内容

  服务器端:

# __author__:Kelvin
# date:2019/4/28 21:36
from socket import *
import subprocess
import struct

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(struct.pack("i", length))
 conn.send(cmd_msg)
 except Exception as e:
 print(e)
 break

  客户端:

# __author__:Kelvin
# date:2019/4/28 21:36
from socket import *
import struct

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 = struct.unpack("i",client.recv(4))[0]
 lengthed = 0
 cmd_msg = b""
 while lengthed < length:
 cmd_msg += client.recv(1024)
 lengthed = len(cmd_msg)
 print(cmd_msg.decode("gbk"))

上述两种方式均可以解决粘包问题。

下载本文
显示全文
专题