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


本文摘自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》频道 >>




打赏

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,您说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

分享从这里开始,精彩与您同在

评论

管理员已关闭评论功能...