• 欢迎访问搞代码网站,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏搞代码吧

粘包问题以及解决方法

python 搞java代码 3年前 (2022-05-21) 16次浏览 已收录 0个评论

一、粘包问题

1、问题一:无法确认对方发送过来数据的大小,对数据接收有影响

 

  server.py文件内容:

<span>"""</span><span>
先启动套接字服务端
    注意:
        客户端一次发送,服务端先一次接收,再发送
</span><span>"""</span>
<span>import</span><span> <a href="https://www.gaodaima.com/tag/socket" title="查看更多关于socket的文章" target="_blank">socket</a>
</span><span>import</span><span> subprocess


server </span>=<span> socket.socket()

server.bind((</span><span>"</span><span>127.0.0.1</span><span>"</span>, 9527<span>))

server.listen(</span>5<span>)

</span><span>while</span><span> True:
    conn, addr </span>=<span> server.accept()
    </span><span>print</span><span>(addr)
    </span><span>while</span><span> True:
        </span><span>try</span><span>:
            </span><span>#</span><span> 从内存中获取数据</span>
            data = conn.recv(1024<span>)

            </span><span>if</span> len(data) ==<span> 0:
                </span><span>continue</span><span>

            data </span>= data.decode(<span>"</span><span>utf-8</span><span>"</span><span>)
            </span><span>if</span> data == <span>"</span><span>q</span><span>"</span><span>:
                </span><span>break</span>

            <span>#</span><span> 调用subprocess,对终端进行操作,并获取操作后正确或错误的结果</span>
            <span>#</span><span> 接收转码后的字符串</span>
            obj = subprocess.Popen(data, shell=True, stdout=subprocess.PIPE, stderr=<span>subprocess.PIPE)

            </span><span>#</span><span> 将结果交给result变量</span>
            result = obj.stdout.read() +<span> obj.stderr.read()
            </span><span>print</span>(result.decode(<span>"</span><span>gbk</span><span>"</span><span>))

            </span><span>#</span><span> 将结果返回给客户端</span>
<span>            conn.send(result)

        </span><span>except</span><span> Exception as e:
            </span><span>print</span><span>(e)
            </span><span>break</span><span>



    conn.close()</span>

www#gaodaima.com来源gao@!dai!ma.com搞$$代^@码网搞代码

  client.py文件内容:

<span>"""</span><span>
启动服务端后再启动客户端
</span><span>"""</span>
<span>import</span><span> socket


client </span>=<span> socket.socket()

client.connect((</span><span>"</span><span>127.0.0.1</span><span>"</span>, 9527<span>))

</span><span>while</span><span> True:

    cmd </span>= input(<span>"</span><span>请输入服务端命令:</span><span>"</span><span>)

    client.send(cmd.encode(</span><span>"</span><span>utf-8</span><span>"</span><span>))

    data </span>= client.recv(1024<span>)    <span># 这里只接受到1024字节数据,可以调整,但是对内存有影响

    </span></span><span>if</span> len(data) ==<span> 0:
        </span><span>continue</span>

    <span>if</span> data == <span>"</span><span>q</span><span>"</span><span>:
        </span><span>break</span>

    <span>print</span>(data.decode(<span>"</span><span>gbk</span><span>"</span>))

  server.py执行结果:

  client.py执行结果:

 

 

2、问题二:在发送数据间隔短并且数据量小的情况下,会将所有数据一次性传入

 

  server.py文件内容:

<span>"""</span><span>
先启动套接字服务端
    注意:
        客户端一次发送,服务端先一次接收,再发送
</span><span>"""</span>
<span>import</span><span> socket


server </span>=<span> socket.socket()

server.bind((</span><span>"</span><span>127.0.0.1</span><span>"</span>, 9527<span>))

server.listen(</span>5<span>)

conn, addr </span>=<span> server.accept()

data </span>= conn.recv(1024<span>)

</span><span>print</span>(data)

  client.py文件内容:

<span>"""</span><span>
启动服务端后再启动客户端
</span><span>"""</span>
<span>import</span><span> socket


client </span>=<span> socket.socket()

client.connect((</span><span>"</span><span>127.0.0.1</span><span>"</span>, 9527<span>))
<br><span>"""</span><br><span>发送三次请求,理论上结果应该是</span><br><span>b"hello"</span><br><span>b"hello"</span><br><span>b"hello"</span><br><span>"""</span>
client.send(b</span><span>"</span><span>hello</span><span>"</span><span>)

client.send(b</span><span>"</span><span>hello</span><span>"</span><span>)

client.send(b</span><span>"</span><span>hello</span><span>"</span>)

  server.py执行结果:

 

 

3、解决粘包问题(struct模块)

1、struct模块是什么

  struct模块是一个python内置模块,他可以将固定长度的数据,打包成固定格式的长度

  ” i “模式:可以将数据打包成 4 个bytes

 

2、struct模块的作用

  可以将真实数据,做成一个固定长度的报头,客户端发送给服务端,服务端可以接受报头,然后对报头进行解包,获取真实数据的长度,进行接收即可

 

3、struct模块的使用

<span>import</span><span> struct

data </span>= b<span>"</span><span>11111111111111</span><span>"</span>
<span>#</span><span> 打包制作报头</span>
header = struct.pack(<span>"</span><span>i</span><span>"</span><span>, len(data))
</span><span>print</span><span>(header)

</span><span>#</span><span> 解包获取真实数据长度 ---> 得到一个元组,元组中第一个值是真实数据的长度</span>
res = struct.unpack(<span>"</span><span>i</span><span>"</span><span>, header)[0]
</span><span>print</span>(res)

  执行结果:

b<span>"</span><span>x0ex00x00x00</span><span>"</span>
14

 

4、粘包问题解决方法

  只要确认对方数据的大小(长度),根据大小进行接收即可解决

 

  - 无论哪一端先发送数据(例  客户端先行发送数据)

    - 客户端

      - 先制作报头并发送  struct.pack()

      - 发送真实数据  

    - 服务端:

      - 接收报头,并解包获取真实数据长度  struct.unpack()

      - 根据真实数据长度 接收真实数据

 

  server.py文件内容:

<span>import</span><span> socket
</span><span>import</span><span> subprocess
</span><span>import</span><span> struct


server </span>=<span> socket.socket()

server.bind((</span><span>"</span><span>127.0.0.1</span><span>"</span>, 8001<span>))

server.listen(</span>5<span>)

</span><span>while</span><span> True:
    conn, addr </span>=<span> server.accept()
    </span><span>#</span><span> print(addr)</span>
    <span>while</span><span> True:
        </span><span>try</span><span>:
            </span><span>#</span><span> 获取客户端传过来的报头</span>
            client_headers = conn.recv(4<span>)
            </span><span>#</span><span> 解包获取真实数据长度</span>
            data_len = struct.unpack(<span>"</span><span>i</span><span>"</span><span>, client_headers)[0]
            </span><span>#</span><span> 准备接收真实数据</span>
            data =<span> conn.recv(data_len)

            </span><span>if</span> len(data) ==<span> 0:
                </span><span>continue</span><span>

            data </span>= data.decode(<span>"</span><span>utf-8</span><span>"</span><span>)
            </span><span>if</span> data == <span>"</span><span>q</span><span>"</span><span>:
                </span><span>break</span>

            <span>#</span><span> 调用subprocess,对终端进行操作,并获取操作后正确或错误的结果</span>
            <span>#</span><span> 接收转码后的字符串</span>
            obj = subprocess.Popen(data, shell=True, stdout=subprocess.PIPE, stderr=<span>subprocess.PIPE)
            </span><span>#</span><span> 将结果交给result变量</span>
            result = obj.stdout.read() +<span> obj.stderr.read()

            </span><span>#</span><span> 服务端做一个报头发送给客户端</span>
            server_headers = struct.pack(<span>"</span><span>i</span><span>"</span><span>, len(result))
            </span><span>#</span><span> 传送报头数据</span>
<span>            conn.send(server_headers)
            </span><span>#</span><span> 待客户端确认长度后,发送真实数据返回给客户端</span>
<span>            conn.send(result)

        </span><span>except</span><span> Exception as e:
            </span><span>print</span><span>(e)
            </span><span>break</span><span>


    conn.close()</span>

  client.py文件内容:

<span>import</span><span> socket
</span><span>import</span><span> struct


client </span>=<span> socket.socket()

client.connect((</span><span>"</span><span>127.0.0.1</span><span>"</span>, 8001<span>))

</span><span>while</span><span> True:

    cmd </span>= input(<span>"</span><span>请输入服务端命令:</span><span>"</span><span>)

    cmd_bytes </span>= cmd.encode(<span>"</span><span>utf-8</span><span>"</span><span>)

    </span><span>#</span><span> 做一个报头</span>
    client_headers = struct.pack(<span>"</span><span>i</span><span>"</span><span>, len(cmd_bytes))
    </span><span>#</span><span> 想服务端传送报头</span>
<span>    client.send(client_headers)
    </span><span>#</span><span> 待服务端确认数据长度后,发送真实数据</span>
<span>    client.send(cmd_bytes)

    </span><span>#</span><span> 获取服务端的传过来的报头</span>
    server_headers = client.recv(4<span>)
    </span><span>#</span><span> 解包获取数据的真实长度</span>
    data_len = struct.unpack(<span>"</span><span>i</span><span>"</span><span>, server_headers)[0]
    </span><span>#</span><span> 准备接受真实数据</span>
    data =<span> client.recv(data_len)

    </span><span>if</span> len(data) ==<span> 0:
        </span><span>continue</span>

    <span>if</span> data == <span>"</span><span>q</span><span>"</span><span>:
        </span><span>break</span>

    <span>print</span>(data.decode(<span>"</span><span>gbk</span><span>"</span>))

 

  可自行测试。


搞代码网(gaodaima.com)提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发送到邮箱[email protected],我们会在看到邮件的第一时间内为您处理,或直接联系QQ:872152909。本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:粘包问题以及解决方法

喜欢 (0)
[搞代码]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址