【问题标题】:Can a read to a raw socket return multiple packets at once?读取原始套接字可以一次返回多个数据包吗?
【发布时间】:2013-10-06 11:53:45
【问题描述】:

读取原始套接字时,它总是返回正好 0 或 1 个数据包吗?

更具体地说,是这样的情况:

  1. linux/win32 用户空间 API?
  2. boost::asio basic_raw_socket.async_receive()

【问题讨论】:

    标签: c++ sockets boost


    【解决方案1】:

    Boost basic_raw_socket::async_receive 不支持接收原始套接字,它仅适用于已连接的套接字,并且无法连接到原始套接字——为此您需要 basic_raw_socket::async_receive_from。这个函数明确支持接收到多个缓冲区,所以你不能保证你一次只能得到零个或一个数据报。

    但请注意,不能严格保证您将(或可以)一次接收多个数据报。这是库的 API 明确允许 的(因为您可以提供多个缓冲区),但它没有说明库 需要 才能真正使用它们。因此,即使您提供多个缓冲区,库在技术上也可能始终只返回一个数据报。如果您在“一个”异步接收操作中获得多个数据报,这可能会通过操作系统层上的多个读取操作来模拟(除非操作系统支持套接字上的分散/收集 I/O,并且这是在您平台的 Boost 版本中实现的)。

    在套接字层,“原始”意味着一个数据报套接字(没有像原始流套接字这样的东西!),并且读取数据报套接字总是1 返回一个完整的数据报(或其中的一部分,如果提供的缓冲区太小,在这种情况下其余的被丢弃)或错误。此行为在 Linux 和 Windows 以及所有其他平台上是相同的,假设实现未中断。
    请注意,您通常需要管理权限才能在原始套接字上发送和接收,对于 Windows,您需要早期的、未打补丁的 Windows XP 或服务器版本(原始套接字被禁用以防止地址欺骗、伪造的 TCP 重置和其他攻击)。

    澄清以上内容:原始套接字将接收“网络层”(第 3 级)数据报。即使这些数据包确实属于 TCP 流或者是 UDP 数据包,对于您的原始套接字,它们仍然只是 IP 数据包。因此,它们没有端口号(它们有,但作为有效负载,而不是作为标头的一部分),并且没有可连接的内容,也没有其他信息,例如一个序列号,用于精确定位数据包在流中的位置。因此,不存在非数据包原始套接字之类的东西,也没有任何东西可以连接。


    1分散/聚集豁免

    【讨论】:

    • 根据文档,它只能与 connected 套接字一起使用。没有“将 绑定到 套接字”之类的东西。
    • 为什么 async_receive 不能与 raw_sockets 一起使用?我已经使用了 2 年多了,没有任何问题。
    • @KilianDS: async_receive(没有from)假定连接的套接字。你在原始套接字上连接什么?在原始 IP 数据报中,没有要连接的流,甚至没有端口号。
    【解决方案2】:

    如果您使用数据报套接字(例如:原始数据包套接字或 UDP 套接字),那么您将得到正好 0(无)或 1 个数据包。

    如果您使用面向连接的套接字(例如:TCP 套接字),那么您可以从任何 API 获取的消息数量与实际接收的数据包数量没有任何强制性关系。

    【讨论】:

      猜你喜欢
      • 2018-11-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-01
      相关资源
      最近更新 更多