Python socket recv 老是收不全数据怎么办? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
userlol
V2EX    程序员

Python socket recv 老是收不全数据怎么办?

  •  
  •   userlol 2018 年 9 月 17 日 8988 次点击
    这是一个创建于 2765 天前的主题,其中的信息可能已经有所发展或是发生改变。

    部分代码:

    #平台限制,只能用 Python2.x 实现 import socket sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.bind(('0.0.0.0',80) sock.listen(1) 

    下面是 recv 应该收到的完整数据(HTTP 请求):

    POST /data/fetchdata HTTP/1.1 Host: www.demo.com Accept: application/json Accept-Encoding: gzip, deflate Content-Length: 8 Cookie: debug=1 Connection: closed result=1 

    一开始为了接收数据写的的代码:

    buf='' While True: buf = buf + client.recv(1024) if not buf or len(buf)==0: break #结果是从来不 break 

    再试

    buf = client.recv(4096) 

    这个只能收到一部分数据(HTTP response body 收不到)。这里有个问题,无论把 buffer 调整多大,第一次 recv 的返回值总是 HTTP response header 部分的数据,很奇怪

    后来试了

    buf = client.recv(1024) #成功接收 HTTP response header print "123" buf = client.recv(1024) #应该接收 HTTP response body,但是一直 blocking print "456" 

    这样的,发现 456 根本不输出。

    快速 Google 之后也没发现什么适合的解决方法,唯一一个靠谱点的是用 try except 配合自定义 timeout 来检测是否 blocking,缺点就是在网络环境比较恶劣的情况下(比如我现在的)也会丢数据。

    向大家求教,谢谢!

    第 1 条附言    2018 年 9 月 17 日
    谢谢各位,不一一回了,已经做好了,回复有空再看。本来打算找无限 recv,recv 不到数据被动想办法断开的办法的,刚才做好了,是从 HTTP 协议入手的,代码根据协议规定 recv 到一定次数主动跳出,避免 recv 到空数据而进入 blocking 状态。
    第 2 条附言    2018 年 9 月 17 日
    PS:
    虽然问题解决了,但是很好奇有时候第一次 recv(8192 或者 1024)时数据只能收到 HTTP request header,body 还得再获取一次,body 是很短的,更奇怪的是,第二次 recv 只收到了几字节的 body,第三次 recv 才把剩下的几个字节收全,很奇怪。
    13 条回复    2018-09-18 09:37:19 +08:00
    neoblackcap
        1
    neoblackcap  
       2018 年 9 月 17 日   1
    你自己不 parse 就想读出来? tcp 又不保证你一次就收到全部数据
    userlol
        2
    userlol  
    OP
       2018 年 9 月 17 日
    @neoblackcap 求教,循环执行 recv 收所有数据没关系,但是如果最后一次数据收空了,recv 就又进入等待状态了,这个怎么解决?
    Tyanboot
        3
    Tyanboot  
    PRO
       2018 年 9 月 17 日 via Android   1
    @userlol 这就是流的处理问题了。HTTP 还行,可以读一部分就解析一部分,拿到 content-length 之后就立刻再算你还需要接受多少。
    neoblackcap
        4
    neoblackcap  
       2018 年 9 月 17 日 via iPhone   1
    @userlol 如 3 楼所说,你必须先循环读出头部,然后才按长度去读剩下的部分。
    还有就是你读到尾部,也有可能是一部分尾部,一部分是另外一个请求,记得将他们分开
    neoblackcap
        5
    neoblackcap  
       2018 年 9 月 17 日 via iPhone
    而且你想性能好些应该用 epoll 来监听 socket 是否可读,用另外一个线程去读
    sampeng
        6
    sampeng  
       2018 年 9 月 17 日
    content-length 就是干这个用的。。。
    miniliuke
        7
    miniliuke  
       2018 年 9 月 17 日 via Android   1
    http 应该是短链接( http2 除外,我不太了解),你循环读把数据拼接起来就行,直到服务器关闭连接结束......一般一次连接不会传两个 http 数据的......你直接读到 socket 关闭就行
    misaka19000
        8
    misaka19000  
       2018 年 9 月 17 日   1
    最近刚刚用 go 写过一个程序,里面包含了对 HTTP 请求的简单解析,楼主可以参考下,Python 实现起来也差不多

    https://gist.github.com/RitterHou/e77b38acdd30d30ee3b9f19004940d3c
    ysc3839
        9
    ysc3839  
       2018 年 9 月 17 日 via Android   1
    buf=''
    While True:
    . recv = client.recv(1024)
    . if not recv or len(recv) == 0:
    . break
    . else:
    . buf += recv
    Jamy
        10
    Jamy  
       2018 年 9 月 17 日   1
    >buf = client.recv(1024) #应该接收 HTTP response body,但是一直 blocking
    >print "456"
    这说明缓冲区里没数据了,
    检查一下发送端是不是没发送完整.
    需要注意下.send 方法可能会只发送部分数据,要自己检查返回值.
    lcj2class
        12
    lcj2class  
       2018 年 9 月 17 日 via Android   2
    之前总结过这类情况,可参考:
    https://liujiacai.net/blog/2016/10/31/socket-programming/
    BingoXuan
        13
    BingoXuan  
       2018 年 9 月 18 日 via Android
    tcp 又不保证你的数据能快速按顺序到达缓存区,所以一直接收直到识别到 eof 或特定结束符就可以了。我还遇过收数据收到前面一部分数据,后面死活收不了,一关闭就收到剩下的
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     976 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 25ms UTC 22:30 PVG 06:30 LAX 15:30 JFK 18:30
    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