V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
fyyz
V2EX  ›  C

boost::asio 中, async_read_some() 如何判断包是否读完了

  •  
  •   fyyz · 2017-08-01 22:56:43 +08:00 · 4361 次点击
    这是一个创建于 2670 天前的主题,其中的信息可能已经有所发展或是发生改变。
    17 条回复    2017-08-02 21:36:31 +08:00
    owt5008137
        1
    owt5008137  
       2017-08-01 23:09:35 +08:00 via Android
    很久没碰过 boost::asio 了。不过一般情况下,如果是 tcp,你得自己加包头。判定是否读完了一整个包,你要自己做黏包。
    我不记得他是来一个包回调一次还是一定要收到你指定的长度才回调。如果是后者,你在调用这个函数前就要保证传入的长度小于等于总长度
    woshixiaohao1982
        2
    woshixiaohao1982  
       2017-08-01 23:16:18 +08:00
    去网上找一个 lineparse 就好了,一般可以采取 /r/n 等作为结束符
    alqaz
        3
    alqaz  
       2017-08-01 23:36:03 +08:00
    不是发送每个数据包之前发送一个固定长度的表示数据包长度的数据吗?
    fyyz
        4
    fyyz  
    OP
       2017-08-02 02:01:43 +08:00 via Android
    @owt5008137 包头是类似整个包 size 的东西吗?
    fyyz
        5
    fyyz  
    OP
       2017-08-02 02:02:40 +08:00 via Android
    @woshixiaohao1982 这个方法我在不少地方看到过,但是我这里不行,因为我要传二进制数据,可能数据内部正好出现这个字符
    fyyz
        6
    fyyz  
    OP
       2017-08-02 02:03:07 +08:00 via Android
    @alqaz 你是指 tcp 的包头中的吗?
    AngelCriss
        7
    AngelCriss  
       2017-08-02 08:25:53 +08:00 via Android
    @fyyz 同学,你知道为什么 HTTP 头里面有一个长度吗?
    fyyz
        8
    fyyz  
    OP
       2017-08-02 08:28:04 +08:00 via Android
    @AngelCriss 我当然知道,可是我现在写的是 proxy,可能会收到各种各样的包,不可能为每种包都写一个获取长度的方法啊。
    newkedison
        9
    newkedison  
       2017-08-02 08:53:51 +08:00
    这个问题我也很纠结,现在用 asio 写串口和 TCP,由于传输的是二进制,所以无法用包头包尾或者长度的办法,只能通过接收时间间隔判断。

    目前的做法是 async_read_some 传入的 buffer 小一点(比如 10 ),然后在 handler 里面再次 async_read_some,同时启动一个定时器,定时一小段时间(比如 10ms ),时间到了就调用 cancel() ,从而表示一包结束。

    不过这样做的话,通讯速率肯定就上不去了
    owt5008137
        10
    owt5008137  
       2017-08-02 08:55:36 +08:00 via Android
    @fyyz 包头包含长度。proxy 的话可以提供某种机制让被代理方定这个包头。要么或者你就用流的转发
    1423
        11
    1423  
       2017-08-02 09:01:58 +08:00
    转义字符
    shibingsw
        12
    shibingsw  
       2017-08-02 09:31:14 +08:00
    tcp 是字节流,没有包的概念,你可以自己在每个消息头部加上消息的长度,比如用 4 个自己做长度,每次接收消息的时候先接收 4 个字节,算出长度,然后根据这个长度调用 async_read_some,每次得到的长度累加起来,直到算出的长度。
    alqaz
        13
    alqaz  
       2017-08-02 10:18:12 +08:00 via Android
    @fyyz 当然不是,就是你的发送端要发送多少数据之前面加一个表示长度的字段。
    araraloren
        14
    araraloren  
       2017-08-02 10:29:53 +08:00
    @fyyz 就算你只传输一个长度值都能实现一个非常简单的协议,不会有什么内部出现某某字符的问题

    1 a 2 bc 3 c3s

    因为按照协议来,你的数据就是完全对应的,不可能读到 c 的时候,或者读到倒数第二个 3 的时候,代码逻辑会误判为长度
    hjc4869
        15
    hjc4869  
       2017-08-02 10:50:05 +08:00
    用 socket::available()?
    sc3263
        16
    sc3263  
       2017-08-02 13:50:21 +08:00
    @fyyz proxy ?各种各样的数据?
    只转发不做处理的话,把 async_read_some 读出来的数据再发出去就行了。
    如果需要过滤内容的话,又或者说,你需要读取完整的一个包然后再整个发送出去。你肯定得知道对应的协议,协议里面肯定约定了长度字段。那你就按照那个协议做处理就行了。
    如果和$$一样,读取数据,加密一下转发给服务器。那就自己定义一个协议,上面也有人说了,最简单的,开头 4 个字节表示这个包的长度,然后是包的剩余内容,读完长度之后读取剩余的部分。你打包一下,服务器解包一下。
    mathgl
        17
    mathgl  
       2017-08-02 21:36:31 +08:00
    @fyyz 你的 proxy 处理的什么格式的数据?有没有通信协议。如果都没有统一标准那是很麻烦的事。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1132 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 18:39 · PVG 02:39 · LAX 10:39 · JFK 13:39
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.