发布网友 发布时间:2022-04-24 08:06
共12个回答
懂视网 时间:2022-04-22 14:32
本文主要讲述的是怎么去解决tcp粘包问题,其一是分两次通讯分别传递内容大小和内容,其二是一次通讯直接传递内容大小和内容。想了解的朋友可以详细看看本篇文章,希望对你有所帮助。原理解析图:
1 socket通信过程如图所示:首先客户端将发送内容通过send()方法将内容发送到客户端计算机的内核区,然后由操作系统将内容通过底层路径发送到服务器端的内核区,然后由服务器程序通过recv()方法从服务器端计算机内核区取出数据。
2 因此我们可以了解到,send方法并不是直接将内容发送到服务器端,recv方法也并不是直接将从客户端发来的内容接收到服务器程序内存中,而是操作自己机器的内核区。
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"))
上述两种方式均可以解决粘包问题。
热心网友 时间:2022-04-22 11:40
一、回答这个问题之前,要考虑TCP协议为什么会丢包,在什么样的情况下会丢包。
1、TCP协议定义(Transimission Control Protocol)是以一种面向连接的、可靠的、基于字节流的传输层通信协议。
2、TCP是基于不可靠的网路实现可靠传输,肯定会存在丢包问题。
3、如果在通信过程中,发现缺少数据或者丢包,那边么最大的可能性是程序发送过程或者接受过程中出现问题。
例如:我有2台服务器 ,A和B服务器。
A服务器发送数据给B服务器频率过高时,B服务器来不及处理,造成数据丢包。(原因可能是程序逻辑问题,多线程同步问题,缓冲区溢出问题)
如果A服务器不对发送频率进行控制,或者数据进行重发的话,那么B服务器收到数据就会少。就会造成丢失数据
二、TCP协议丢包后,如何解决丢包的问题
为了满足TCP协议不丢包。TCP协议有如下规定
1、数据分片:发送端对数据进行分片,接受端要对数据进行重组,由TCP确定分片的大小并控制分片和重组
2、到达确认:接收端接收到分片数据时,根据分片数据序号向发送端发送一个确认
3、超时重发:发送方在发送分片时设置超时定时器,如果在定时器超时之后没有收到相应的确认,重发分片数据
4、滑动窗口:TCP连接的每一方的接受缓冲空间大小固定,接收端只允许另一端发送接收端缓冲区所能接纳的数据,TCP在滑动窗口的基础上提供流量控制,防止较快主机致使较慢主机的缓冲区溢出
5、失序处理:作为IP数据报来传输的TCP分片到达时可能会失序,TCP将对收到的数据进行重新排序,将收到的数据以正确的顺序交给应用层;
6、重复处理:作为IP数据报来传输的TCP分片会发生重复,TCP的接收端必须丢弃重复的数据;
7、数据校验:TCP将保持它首部和数据的检验和,这是一个端到端的检验和,目的是检测数据在传输过程中的任何变化。如果收到分片的检验或有差错,TCP将丢弃这个分片,并不确认收到此报文段导致对端超时并重发
热心网友 时间:2022-04-22 12:58
TCP是一个“流”协议,一个详细的包将会被TCP拆分为好几个包上传,也是将会把小的封装成大的上传,这就是说TCP粘包和拆包难题。热心网友 时间:2022-04-22 14:33
1.确认网络链路问题,ping测和traceroute确认链路是否健康。如果链路有问题,找对应网络管理员排查网络。热心网友 时间:2022-04-22 16:24
从tcp应用本身排查,通过在程序上添加调试代码,核查是否应用逻辑处理问题热心网友 时间:2022-04-22 18:32
确认网络链路问题,确认系统问题,从tcp应用本身排查热心网友 时间:2022-04-22 20:57
将一个大的拆成好几个小的传输热心网友 时间:2022-04-22 23:38
看看网络是否卡顿,是否流畅热心网友 时间:2022-04-23 02:36
可以通过代码调试,从而解决丢包热心网友 时间:2022-04-23 05:51
这个你给加固它的传输通道。热心网友 时间:2022-04-23 09:22
这个得看你的网络是否稳定热心网友 时间:2022-04-23 13:10
确认网络链路问题,ping测和traceroute确认链路是否健康。如果链路有问题,找对应网络管理员排查网络