【问题标题】:Linux UDP recvfrom: What do I get at the start of my buffer?Linux UDP recvfrom:我在缓冲区的开头得到了什么?
【发布时间】:2020-02-27 00:18:31
【问题描述】:

如果我对recvfrom 的调用返回有效字节数(例如1400),我会在缓冲区的开头得到什么?

我会收到ethhdr 吗?例如,即使我应该接收 UDP 数据包,此代码也不起作用:

void read_packets(struct config *cfg) {

    int64_t read_bytes = recvfrom(cfg->socket_fd, buffer, BUFFER_SIZE, 0, NULL, NULL);
    if(read_bytes == -1) {
        return;
    }

    cfg->stats.amnt_of_packets += 1;
    cfg->stats.amnt_of_bytes += read_bytes;

    struct ethhdr *eth = (struct ethhdr*)(buffer);
    if(ntohs(eth->h_proto) == ETH_P_IP) {
        struct iphdr *iph = (struct iphdr*)(buffer + sizeof(struct ethhdr));
        if(iph->protocol == IPPROTO_UDP) {
            /* doesn't work */
        }
    }
}

socket_fd 被创建为:

cfg->socket_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

【问题讨论】:

  • @JeremyFriesner 我将此信息添加到我的原始帖子中
  • SOCK_DGRAM 类型的套接字将仅获取 UDP 有效负载数据。如果您想访问较低级别的网络标头(在大多数情况下,您不需要),您需要实例化一个 SOCK_RAW 套接字。 (另见:stackoverflow.com/questions/26896944/…
  • @JeremyFriesner 所以这意味着在我的情况下我得到一个struct udphdr?
  • 不,在您的情况下,您只能获得发送程序传递给其 sendto() 调用的任何 UDP 有效负载数据。任何类型的系统定义的标头数据都不会暴露给正常的网络程序(使用原始套接字时除外)。

标签: c linux sockets


【解决方案1】:

在 UDP 套接字上使用 recvfrom 只会返回 UDP 数据包的有效负载,即发送端传递给 sendto 的内容。您不会看到以太网标头、IP 标头或 UDP 标头作为其中的一部分。

但是,您确实为最后两个参数传递了 NULL 值。这些可用于填充 struct sockaddr_in 结构,该结构将包含发送方的 IP 地址和 UDP 端口。

此外,如果您使用recvmsg,您可以从 IP 标头中获取某些字段的值,例如目标 IP 地址(在套接字接收多播数据包时很有用)、TOS/DSCP 字段、或可以设置的各种 IP 选项。

【讨论】:

  • 即使您不处理多播数据包的广播,目标 IP 地址也很重要。一旦服务器拥有多个 IP 地址,绑定到 0.0.0.0 或 :: 的套接字上的传统 sendto/recvfrom 就会从根本上被破坏。
猜你喜欢
  • 1970-01-01
  • 2021-04-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多