问个 socket 相关问题recv 接收数据 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
请不要在回答技术问题时复制粘贴 AI 生成的内容
bbsfoo

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

  •  
  •   bbsfoo Apr 16, 2023 2672 views
    This topic created in 1110 days ago, the information mentioned may be changed or developed.

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

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

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

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

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