Python socket 通信如何分包 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
just1
V2EX    Python

Python socket 通信如何分包

  •  
  •   just1 2017-04-01 21:48:37 +08:00 7043 次点击
    这是一个创建于 3160 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

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

    31 条回复    2017-04-03 15:58:22 +08:00
    wevsty
        1
    wevsty  
       2017-04-01 22:01:44 +08:00
    发一个,等几秒再发第二个
    zyEros
        2
    zyEros  
       2017-04-01 22:01:49 +08:00 via iPhone
    尾部特殊字符,或者头部用 2 字节表明 body 的长度
    just1
        3
    just1  
    OP
       2017-04-01 22:02:30 +08:00 via Android
    @wevsty
    @zyEros 服务端不可控
    wevsty
        4
    wevsty  
       2017-04-01 22:04:39 +08:00
    @just1 那就自己按照包大小或者包格式分割一下,如果没有固定格式,弃坑吧
    zyEros
        5
    zyEros  
       2017-04-01 22:05:29 +08:00 via iPhone
    @just1 服务端都不能标明你 body 的长度或者截止位置,你能怎么办,没办法
    dant
        6
    dant  
       2017-04-01 22:16:48 +08:00
    TCP 是数据流。
    just1
        7
    just1  
    OP
       2017-04-01 22:18:49 +08:00
    @zyEros
    @wevsty
    @dant TAT 那 wireshark 怎么实现分包的
    maemual
        8
    maemual  
       2017-04-01 22:24:21 +08:00
    tcp 流式数据你是分不了包的。只能加结束符或者发送 content length 之类的东西来判断。
    ifaii
        9
    ifaii  
       2017-04-01 22:41:50 +08:00 via iPhone
    tcp 是流,这种需求不如试试 udp
    lvxudong
        10
    lvxudong  
       2017-04-01 22:49:43 +08:00
    socket.recv(num) 可以指定接收字节数
    wevsty
        11
    wevsty  
       2017-04-01 23:06:57 +08:00   1
    @just1 抓包工具抓的并不只是 tcp 层面的数据。一个 tcp 包除了发送或者接收的数据还包括了很多内容,比如目标端口,原端口,也有些包不包含应用层的数据。和你理解的接收包不是一回事。解释起来很复杂,但是在应用层的层面上 TCP 应用层的应用是分不清楚包的。如果一定要按照包来处理内容,请使用 UDP 。
    当然,使用 UDP 你肯定会遇到更多麻烦。
    mooncakejs
        12
    mooncakejs  
       2017-04-01 23:17:20 +08:00 via iPhone
    tcp 不需要分包。按照应用层协议解析就好
    jimzhong
        13
    jimzhong  
       2017-04-01 23:18:32 +08:00
    如果你是 Linux 的 UNIX Socket ,可以试试 SEQPACKET 协议。
    如果是 TCP ,那么建议自己设计一个头,里面包含数据长度,就像 HTTP 的 Content-length 一样
    jimzhong
        14
    jimzhong  
       2017-04-01 23:20:21 +08:00   1
    @just1 TCP 在传递到 IP 层的时候会分成一个个 Segment , Segment 的大小由 MSS 决定。每个 Segment 被封装到一个 IP 包里面。但是 Segment 对于应用程序是不可见的,应用程序看到的就是流。
    just1
        15
    just1  
    OP
       2017-04-01 23:25:36 +08:00 via Android
    @maemual
    @ifaii
    @lvxudong
    @mooncakejs (_`)模拟某个客户端的啦,我再想办法找找他的处理模式

    @wevsty @jimzhong 感谢解惑
    raiz
        16
    raiz  
       2017-04-01 23:26:42 +08:00
    既然是tcp,本身是流,肯定要有数据协议,就是根据数据包格式,起始标识符,长度域或结束符来判断完整的一包.具体就是逐字节的读取,判断,直到一完整包,给上层,继续读取判断.
    pright
        17
    pright  
       2017-04-02 00:50:50 +08:00   1
    如果每个包长度都小于 MSS ,你也可以用 raw socket 自己收 233
    best1a
        18
    best1a  
       2017-04-02 01:40:28 +08:00
    @pright 即使每个包长度都小于 MSS ,如果服务端开启了 nagle ,一样会有这问题吧
    NoAnyLove
        19
    NoAnyLove  
       2017-04-02 04:26:18 +08:00   1
    TCP 是面向数据流的啊,你可以自己定义一个应用层的格式,比如每个包头包含这个包的大小。 recv 的时候先接收包头大小的内容,然后再根据包头接受剩下的数据。当你用直接用 TCP 协议的时候,就不用考虑下面的分包问题了。除非你想用 UDP
    ryd994
        20
    ryd994  
       2017-04-02 07:39:42 +08:00 via Android
    1.每个包以长度开头
    2.用库或者自己再实现一层 buffer ,用 deque 实现不难的
    3.SCTP
    ryd994
        21
    ryd994  
       2017-04-02 07:44:40 +08:00 via Android   1
    关了 nagle ,每次 flush ,接收端读取频率够高的话,应该不会粘
    但是不保证,毕竟
    1.操作系统可以有其他实现
    2.拥塞控制 /流控挡了一下,剩下的在发送缓冲合并了
    3.接收乱序,等到齐了的时候一起进接收缓冲
    4.服务端程序被其他事件打断,睡了一会
    huxh10
        22
    huxh10  
       2017-04-02 08:26:58 +08:00   1
    TCP 确实是一个包一个包发的, wireshark 也能看到。
    编程用的 API 是 socket , socket 是在 TCP 和 UDP 之上又提供了一层抽象。用 socket 处理 SOCK_STREAM ,是流式数据,需要自己再定义包头校验。
    momo1999
        23
    momo1999  
       2017-04-02 09:02:18 +08:00 via Android   1
    我们一般用 tlv , type , length , value ,其中 tl 大小固定,叫做包头, value 变长,由 length 决定。先只收包头,收到以后再根据长度收取 value 。
    falseen
        24
    falseen  
       2017-04-02 09:04:27 +08:00 via Android   1
    用常规方法实现不了,或许可以试试非常规方法。比如用 scapy 抓取 ip 包,然后从中拿到数据。
    magicdawn
        25
    magicdawn  
       2017-04-02 09:47:49 +08:00
    什么 content-length, 换行符等特殊字符啊都是简单的应用层协议啊
    aabbccli
        26
    aabbccli  
       2017-04-02 11:18:37 +08:00
    就像 HTTP 服务器一样,有三种方式:
    一 写完数据, flush 一下缓存
    二 用 CONTENT-LENGTH 来标明 PAYLOAD 的大小
    三 用类似于 HTTP1.1 的 TRANSFER-ENCODING 的格式来分块
    aploium
        27
    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
        28
    ryd994  
       2017-04-02 11:35:27 +08:00
    @aploium SCTP over udp?
    ihuotui
        29
    ihuotui  
       2017-04-02 14:30:41 +08:00 via iPhone
    自己定协议 然后自己分包,实现参考 netty
    sheep3
        30
    sheep3  
       2017-04-02 18:24:31 +08:00
    早在在 segmentfault 看到你的问题了。。。。。 没有做过所以也没法回答 orz
    julyclyde
        31
    julyclyde  
       2017-04-03 15:58:22 +08:00
    首先要 坚定 TCP 是流 的信念
    然后才能想到如何在流里区分数据的开始和结束
    而不是幻想着把应用层的开始结束标志和 TCP segment 对应起来
    关于   &bsp; 帮助文档     自助推广系统     博客     API     FAQ     Solana     1598 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 77ms UTC 16:22 PVG 00:22 LAX 08:22 JFK 11:22
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86