Python socket 通信如何分包

2017-04-01 21:48:37 +08:00
 just1

比如服务端发送 00 01 ; 00 02 两个包 客户端用 python socket.recv()的函数会接收到 00 01 00 02 (粘连在一起) 如何分包? 服务端我无法控制。 客户端用 python3

之前发在 segmentfault 没人理。。。 https://segmentfault.com/q/1010000008888222

6499 次点击
所在节点    Python
31 条回复
ryd994
2017-04-02 07:44:40 +08:00
关了 nagle ,每次 flush ,接收端读取频率够高的话,应该不会粘
但是不保证,毕竟
1.操作系统可以有其他实现
2.拥塞控制 /流控挡了一下,剩下的在发送缓冲合并了
3.接收乱序,等到齐了的时候一起进接收缓冲
4.服务端程序被其他事件打断,睡了一会
huxh10
2017-04-02 08:26:58 +08:00
TCP 确实是一个包一个包发的, wireshark 也能看到。
编程用的 API 是 socket , socket 是在 TCP 和 UDP 之上又提供了一层抽象。用 socket 处理 SOCK_STREAM ,是流式数据,需要自己再定义包头校验。
shuax
2017-04-02 09:02:18 +08:00
我们一般用 tlv , type , length , value ,其中 tl 大小固定,叫做包头, value 变长,由 length 决定。先只收包头,收到以后再根据长度收取 value 。
falseen
2017-04-02 09:04:27 +08:00
用常规方法实现不了,或许可以试试非常规方法。比如用 scapy 抓取 ip 包,然后从中拿到数据。
magicdawn
2017-04-02 09:47:49 +08:00
什么 content-length, 换行符等特殊字符啊都是简单的应用层协议啊
aabbccli
2017-04-02 11:18:37 +08:00
就像 HTTP 服务器一样,有三种方式:
一 写完数据, flush 一下缓存
二 用 CONTENT-LENGTH 来标明 PAYLOAD 的大小
三 用类似于 HTTP1.1 的 TRANSFER-ENCODING 的格式来分块
aploium
2017-04-02 11:22:07 +08:00
1. 最简单的是强制规定每个包都是固定长度, 比如 64bytes 每次 .recv(64) 就是一个包

2. 稍微复杂一点, 用一小段序列作为包之间的分隔两个包,比如 b'\xff\xee\xcc\xaa\xbb\xdd\x00'
收到的东西先存到 buffer 里, 然后根据这段序列自己分隔
优点是很简单, 缺点是可能会误分隔, 以及安全问题. 需要自己处理转义

3. 更复杂的是自己设计一个简单的协议(参考 HTTP) 在协议头部标明内容的长度等一些元信息, 接收端 buffer 后进行分割, 不容易出错

不知道有没有现成的库能做这种事情, 有的话请[at]我
ryd994
2017-04-02 11:35:27 +08:00
@aploium SCTP over udp?
ihuotui
2017-04-02 14:30:41 +08:00
自己定协议 然后自己分包,实现参考 netty
sheep3
2017-04-02 18:24:31 +08:00
早在在 segmentfault 看到你的问题了。。。。。 没有做过所以也没法回答 orz
julyclyde
2017-04-03 15:58:22 +08:00
首先要 坚定 TCP 是流 的信念
然后才能想到如何在流里区分数据的开始和结束
而不是幻想着把应用层的开始结束标志和 TCP segment 对应起来

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/352066

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX