【问题标题】:After I do a UDP broadcast, how do I know what port I broadcasted on?进行 UDP 广播后,我如何知道我在哪个端口上广播?
【发布时间】:2020-04-29 02:10:38
【问题描述】:

我有一个必须使用 UDP 的 Linux C 应用程序。服务器广播一个“发现数据包”,然后监听任何连接的客户端以类似的回声来回答。通过使用端口,客户端和服务器可以使用不同的端口进行通信。

以下是服务器广播其发现数据包的方式:

int main() {
  puts("starting");
  int sock;
  int yes = 1;
  struct sockaddr_in broadcast_addr;
  int addr_len;
  int count;
  int ret;
  fd_set readfd;
  char buffer[1024];
  char outbound_buffer[63];
  int i;

  sock = socket(AF_INET, SOCK_DGRAM, 0);
  if (sock < 0) {
    perror("sock error");
    return -1;
  }
  ret = setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char*)&yes, sizeof(yes));
  if (ret == -1) {
    perror("setsockopt error");
    return 0;
  }
  memset(outbound_buffer,0,sizeof(outbound_buffer));

  addr_len = sizeof(struct sockaddr_in);

  memset((void*)&broadcast_addr, 0, addr_len);
  broadcast_addr.sin_family = AF_INET;
  broadcast_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
  broadcast_addr.sin_port = htons(PORT);

  outbound_buffer[0] = 0xEF;
  outbound_buffer[1] = 0xFE;
  outbound_buffer[2] = 0x02;

    ret = sendto(sock, outbound_buffer, 63, 0, (struct sockaddr*) &broadcast_addr, addr_len);

这很好用;客户端收到发现并获取服务器的IP和端口:

int main() {

  stoplink = 0;
  stopData = 0;
  int addr_len;
  int count;
  int ret;
  fd_set readfd;
  char buffer[1024];
  sock = socket(AF_INET, SOCK_DGRAM, 0);
  if (sock < 0) {
    perror("sock error\n");
    return -1;
  }
  addr_len = sizeof(struct sockaddr_in);
  memset((void*)&server_addr, 0, addr_len);
  server_addr.sin_family = AF_INET;
  server_addr.sin_addr.s_addr = htons(INADDR_ANY);
  server_addr.sin_port = htons(PORT);

  ret = bind(sock, (struct sockaddr*)&server_addr, addr_len);
  if (ret < 0) {
    perror("bind error\n");
    return -1;
  }
  while (1) {

  puts("Initialized; await discovery");

    FD_ZERO(&readfd);
    FD_SET(sock, &readfd);

    ret = select(sock+1, &readfd, NULL, NULL, 0);
    if (ret > 0) {
      if (FD_ISSET(sock, &readfd)) {
        count = recvfrom(sock, buffer, 1024, 0, (struct sockaddr*)&client_addr, &addr_len);
        if((buffer[0] & 0xFF) == 0xEF && (buffer[1] & 0xFF) == 0xFE) {
      fprintf(stderr,"discovery packet detected\n"); 
          cmdport = ntohs(client_addr.sin_port);
          printf("\nClient connection information:\n\t IP: %s, Port: %d\n", 
            inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));

       count = sendto(sock, buffer, strlen(buffer), 0, (struct sockaddr*)&client_addr,
         sizeof(client_addr));
        }
      }
    }

  puts("Now starting command processing loop");

这也可以正常工作......但它会将回复发送到广播来自的服务器上的端口 - 这是由服务器自动随机选择的;那么如何知道服务器端监听哪个端口来接收客户端的回复呢?

【问题讨论】:

  • 这就是为什么你应该bind“服务器”端的套接字,所以它不会得到随机端口,你可以自己选择。
  • 你标题中问题的答案是getsockname(),但你不需要它。

标签: c linux sockets udp


【解决方案1】:

感谢所有输入。 getsockname() 是我需要的。

【讨论】:

    【解决方案2】:

    您已经交换了“客户端”和“服务器”这两个词的正常含义——通常 服务器 将绑定到特定端口并侦听(广播)数据包,而 client 将广播一个发现数据包来查找服务器。当服务器接收到广播时,它会回复客户端,客户端只会在它的(单个)套接字上执行一个接收以获取回复,该回复将具有服务器的 IP 地址。如果可能有多个服务器,那么它们都会回复客户端,因此客户端会看到多个回复并需要从中进行选择。但是,最重要的是,客户端永远不需要知道它正在使用哪个端口——它只是让系统为它选择一个其他未使用的端口。

    【讨论】:

      【解决方案3】:

      服务器不需要做任何额外的事情。一旦它发送一个数据包,服务器端的端口就会被设置。

      例如,如果客户端看到服务器消息来自端口 34567,那么服务器套接字正在使用端口 34567。那么任何通过端口 34567 发送到服务器的消息都可以被同一个服务器套接字读取。

      所以服务器只需要调用recvfrom,它就会得到客户端的响应。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-07-30
        • 1970-01-01
        • 2010-10-15
        • 2010-09-25
        相关资源
        最近更新 更多