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

问个 socket 相关问题recv 接收数据

  •  
  •   bbsfoo 2023-04-16 19:44:56 +08:00 2295 次点击
    这是一个创建于 913 天前的主题,其中的信息可能已经有所发展或是发生改变。

    recv 不保证能收到参数里缓冲区大小的数据,譬如说

    int n = recv(client_socket, buffer, sizeof(buffer), 0);

    假设 buffer 的大小是 16 个字节,如果客户端发送 8 个字节,recv 就返回 8

    现在我的包结构是 包长度( 2 个字节) + 包体(可变长度) 程序先接读 2 字节包长度 ushort package_size; int n = recv(client_socket, ( byte *) package_size, sizeof(package_size), 0);

    这个 n 会不会少于 2 如果有这个可能,那么岂不是要重复 recv ?好像很麻烦

    12 条回复    2023-04-17 11:30:05 +08:00
    codehz
        1
    codehz  
       2023-04-16 19:49:53 +08:00 via iPhone
    所以不是有 MSG_WAITALL 选项给你用吗)
    不过一般来说不会只给 2 字节就 wait ,因为这意味着至少要读取两次才能把一个包读完(
    通常是给个足够大的 buffer ,然后不停的调用 recv ,直到够用为止,很多时候反而会减少总 syscall 数量
    eastphoton
        2
    eastphoton  
       2023-04-16 21:25:41 +08:00
    可能
    hankai17
        3
    hankai17  
       2023-04-16 21:37:27 +08:00
    if n < 2 就继续监听读 直到读到长度
    cnbatch
        4
    cnbatch  
       2023-04-16 21:50:30 +08:00
    TCP 是流,消息边界需要自己拆。n 确实可以少于 2 。

    数据量少的时候,也许收 /发的数据看起来都是老老实实的,不多不少刚刚好。但数据量大或者受到网络延迟、丢包重传等因素的影响,这就难以保证每次 recv 收到的数据大小都一样。

    例如发送端分两次分别发出“8ABCD” “EFGH”,接收端既有可能会分两次收到“8ABCD” “EFGH”这两段,也有可能会一次性收到“8ABCDEFGH”拼起来的一长串,甚至还可以是“8ABCDEFG” “H”。

    所以最稳妥的做法就是循环调用 recv ,自己设好边界规则逻辑,自己从 TCP 流拆出并重新组合成实际想要的数据。
    liuguangxuan
        5
    liuguangxuan  
       2023-04-16 21:53:28 +08:00
    是这样的。
    不止包长度( 2 个字节)有这个问题,包体也有这个问题,都需要不断的重复调用 recv 来等到所需要的字节长度数。

    或者建议直接使用成熟的通信库或者一些消息队列,如 libevent 、grpc 、brpc 等。
    alikesi
        6
    alikesi  
       2023-04-16 22:37:17 +08:00 via Android
    没必要分开读,这样的话就是理想情况下你都要读两次才能拼成一个完整的包。
    artnowben
        7
    artnowben  
       2023-04-16 22:44:50 +08:00
    TCP 数据是按照 IP 报文来发送 /接收的,IP 报文的 MTU 是 1.5K ,所以大概一次通讯后,数据头部和部分 body 已经在内核里了,至于上层一次调用 recv 取出多少是你自己的事情。
    如果想要更多的了解 TCP/IP 的细节,可以读一读实现的源码,dperf 是专门正对性能测试的一个实现版本,比较精简,容易读,方便调试,国内大厂都在用。
    https://github.com/baidu/dperf/
    bg7lgb
        8
    bg7lgb  
       2023-04-16 23:03:02 +08:00
    开缓冲区,把数据接收读进缓冲区,再进行解包。
    darkengine
        9
    darkengine  
       2023-04-16 23:49:07 +08:00   1
    又到经典的 TCP 分包与粘包问题时间。
    yolee599
        10
    yolee599  
       2023-04-17 08:59:45 +08:00 via Android
    1 楼正解,一般是用一个 512 或者 1024 的 buffer ,反复读取,用状态机,读取到数据的时候就取出来解析更新状态机
    emperinter
        11
    emperinter  
       2023-04-17 09:53:52 +08:00
    发送端可以发送两次,一次发送数据长度用于数据接收判断,一次发送完整数据
    julyclyde
        12
    julyclyde  
       2023-04-17 11:30:05 +08:00
    https://docs.python.org/zh-cn/3/library/asynchat.html
    虽然这个马上要淘汰了,不过还是建议学习一下
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2710 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 35ms UTC 15:14 PVG 23:14 LAX 08:14 JFK 11:14
    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