解决tcp粘包问题的两种办法

互联网 19-4-30
本文主要讲述的是怎么去解决tcp粘包问题,其一是分两次通讯分别传递内容大小和内容,其二是一次通讯直接传递内容大小和内容。想了解的朋友可以详细看看本篇文章,希望对你有所帮助。

第一部分:简介tcp socket通信的底层原理

原理解析图:

第二部分:产生粘包的原因(只针对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"))

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

以上就是解决tcp粘包问题的两种办法的详细内容,更多内容请关注技术你好其它相关文章!

来源链接:
免责声明:
1.资讯内容不构成投资建议,投资者应独立决策并自行承担风险
2.本文版权归属原作所有,仅代表作者本人观点,不代表本站的观点或立场
标签: HTTP
上一篇:php获取远程图片并下载保存到本地的方法分析 下一篇:快速了解UI组件功能设计

相关资讯