【问题标题】:Getting the destination port of incoming UDP packet获取传入 UDP 数据包的目的端口
【发布时间】:2017-09-26 08:02:01
【问题描述】:

我已经阅读了 ip 手册页和 socket 手册页,我只能找到标题中 IP_PKTINFO 控制消息中的目标 IP 地址,似乎无法提取目标端口从数据包的头部。或者有吗?

如果没有,有没有办法从数据包到达的套接字中获取端口?

【问题讨论】:

  • 你说的是原始套接字吗?普通的 UDP 套接字绑定到地址和端口。
  • 不,不是原始套接字,是的,它绑定到绑定到许多端口的线程池中的 ip/port。也在使用 boost。
  • 我正在使用 boost_socket.native() 来访问标头等。

标签: c++ linux sockets c++11 udp


【解决方案1】:

当您使用普通套接字时,您可以在套接字 fd 上使用 recvfrom。 recvfrom 的手册页:

RECV(2)

名字

   recv, recvfrom, recvmsg - receive a message from a socket

概要

        #include <sys/types.h>
        #include <sys/socket.h>

        ssize_t recv(int sockfd, void *buf, size_t len, int flags);

        ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
                         struct sockaddr *src_addr, socklen_t *addrlen);

        ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);

描述

   The  recv(),  recvfrom(),  and recvmsg() calls are used to receive messages from a socket.  They
   may be used to receive data on both connectionless and connection-oriented sockets. 

recvfrom() recvfrom() 将接收到的消息放入缓冲区 buf。调用者必须指定大小 len 中的缓冲区。

   If src_addr is not NULL, and the underlying protocol provides the source address of the message,
   that source address is placed in the buffer pointed to by src_addr.  In this case, addrlen is  a
   value-result  argument.   Before  the  call,  it should be initialized to the size of the buffer
   associated with src_addr.  Upon return, addrlen is updated to contain the  actual  size  of  the
   source  address.  The returned address is truncated if the buffer provided is too small; in this
   case, addrlen will return a value greater than was supplied to the call.

   If the caller is not interested in the source address, src_addr and addrlen should be  specified
   as NULL.

beej 指南中的示例:

// datagram sockets and recvfrom()

struct addrinfo hints, *res;
int sockfd;
int byte_count;
socklen_t fromlen;
struct sockaddr_storage addr;
char buf[512];
char ipstr[INET6_ADDRSTRLEN];

// get host info, make socket, bind it to port 4950
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;  // use IPv4 or IPv6, whichever
hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = AI_PASSIVE;
getaddrinfo(NULL, "4950", &hints, &res);
sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
bind(sockfd, res->ai_addr, res->ai_addrlen);

// no need to accept(), just recvfrom():

fromlen = sizeof addr;
byte_count = recvfrom(sockfd, buf, sizeof buf, 0, &addr, &fromlen);

printf("recv()'d %d bytes of data in buf\n", byte_count);
printf("from IP address %s\n",
    inet_ntop(addr.ss_family,
        addr.ss_family == AF_INET?
            ((struct sockadd_in *)&addr)->sin_addr:
            ((struct sockadd_in6 *)&addr)->sin6_addr,
        ipstr, sizeof ipstr);

Example of recvfrom, man page of recvfrom

希望对你有帮助

【讨论】:

  • 感谢您的意见。我已经出于多种原因使用recvfromrecvmsg。但是,sockadd_in 结构的 sin_addrsin_port 保存源 IP 和端口,而不是目标。无论如何,我通过使用boost::asio::socket_base::reuse_address option(true); 设置SO_REUSE 标志来解决我的问题,从而允许多个套接字使用同一个端口。但是,我仍然很难理解为什么目标端口在传入的数据包上不容易访问......它一定在某个地方。
  • 当你创建一个普通套接字时,你应该在绑定该套接字时指定端口和 ip,这样你就已经知道消息到达的端口(因为你在绑定套接字)。你能更详细地解释一下你的情况吗?
  • 这是真的,但我们可以对目标 IP 说同样的话,它在 msghdr 中可用。我们的线程池设计意味着我们可能会面临无法正确匹配端口与其对应的传入数据包的风险,读取数据包标头将是一种更安全的方式。
猜你喜欢
  • 2020-06-28
  • 1970-01-01
  • 2012-03-03
  • 2018-09-28
  • 1970-01-01
  • 1970-01-01
  • 2013-02-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多