【问题标题】:UDP server socket IP assignmentUDP 服务器套接字 IP 分配
【发布时间】:2013-04-08 20:37:34
【问题描述】:

我运行下面的服务器代码来打开一个 UDP 套接字。我的 linux 机器上有两个网络接口,两个接口连接到两个不同的网络。我希望程序监听指定的网络(通过分配 IP 地址),因此我在 UDP 套接字上分配了一个 IP 地址。

如果我使用servaddr.sin_addr.s_addr = htonl(INADDR_ANY);,服务器能够接收广播和单播消息。但是,如果我定义了servaddr.sin_addr.s_addr =inet_addr("10.0.0.6");,那么服务器可以接收来自10.0.0.6 的消息,但不能接收广播10.0.0.255 消息(网络掩码是/24)。 here是广播消息的代码,单播代码是here

是我分配的IP地址错误还是广播代码错误?

服务器代码是:

#define BUFSIZE 512
char *SERVER_IP = "10.0.0.6";

int main() {
    int error_count=0, r=0, n=0;
    int sockfd = 0;
    struct sockaddr_in servaddr, cliaddr ,a ;
    socklen_t len; //integer type of width of at least 32 bits
    char mesg[1000];

    sockfd = socket(AF_INET, SOCK_DGRAM, 0); // for datagram
    while(sockfd < 0){ //error handling for socket opening
        usleep(500000);
        if (++error_count == 20){//10 times itteration
             fprintf(stderr, "errno:%s - socket opening error - line 223\n ", strerror(errno));
            exit(1);
        }
         sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    }
error_count = 0;

    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(33333); //server listens on this port


   // servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
     servaddr.sin_addr.s_addr =inet_addr(SERVER_IP);
    printf("servaddr.sin_addr:%lu\n",servaddr.sin_addr );
    printf("a.sin_addr:%lu\n",a.sin_addr );

    r = bind(sockfd,(struct sockaddr *) &servaddr, sizeof(servaddr));
    while(r < 0){ //error handling for socket binding
        usleep(500000);
        if (++error_count == 20){//10 times itteration
             fprintf(stderr, "errno:%s - socket binding error - line 239\n ", strerror(errno));
            exit(1);
        }
          r = bind(sockfd,(struct sockaddr *) &servaddr, sizeof(servaddr));
    }
error_count = 0;


    while(1){
       len = sizeof(cliaddr);
    next:
printf("server is listening\n");
       n = recvfrom(sockfd, mesg, 1000, 0, (struct sockaddr *) &cliaddr, &len);
printf("line195: packet is received: %s\n", mesg);
       if(n < 0){
           fprintf(stderr, "recvfrom error occured - line254\n");
           n = 0;
           goto next;
       }
}
  return 0;
}

这是我的ifconfig -a wlan8

wlan8     Link encap:Ethernet  HWaddr 64:70:02:18:1f:b6  
          inet addr:10.0.0.6  Bcast:10.0.0.255  Mask:255.255.255.0
          inet6 addr: fe80::6670:2ff:fe18:1fb6/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:206 errors:0 dropped:0 overruns:0 frame:0
          TX packets:297 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:37857 (37.8 KB)  TX bytes:54526 (54.5 KB)

【问题讨论】:

    标签: c linux sockets posix


    【解决方案1】:

    可以使用INADDR_ANY 和正确调用setsockopt 让您的服务器按照您的需要工作。

    应该是这样的,就在套接字创建之后:

    memset(&ifr, 0, sizeof(ifr));
    snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "wlan8");
    if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,
                (void *)&ifr, sizeof(ifr)) < 0) {
         fprintf(stderr, "error at setsockopt, ensure it is running as root.\n");
         exit(1);
    }
    

    显然,您还必须#include &lt;net/if.h&gt; 并在main 的开头定义struct ifreq ifr;

    这样,您的服务器将接收以wlan8 接口(广播和单播)的任何地址为目标的每个数据报,但它会忽略其他接口。

    SO_BINDTODEVICE 已被引入 linux 用于 DHCP 客户端和服务器,但需要 root 权限。您可以使用sudo 或从root 执行以下命令来设置SUID(因此您可以通过组关联控制程序执行)

    chmod 4750 server_name
    

    显然你应该小心这类程序,否则你会在你的系统中打开一个安全漏洞。

    最后我建议你阅读

    【讨论】:

    • 谢谢Giacomo,我还有一个问题,snprintf 有必要吗?使用memcpy而不是snprintf会不会很好
    • 我更喜欢 snprintf 以避免与空终止相关的问题。您可以使用 memcpy,但您必须手动处理 null 终止。
    【解决方案2】:

    你没有做错任何事。除非套接字绑定到广播地址或 INADDR_ANY,否则 Linux 不会接收广播数据报。您需要将一个套接字绑定到单播地址,将另一个套接字绑定到广播地址,或者如果绑定到 INADDR_ANY,则可以使用 IP_PKTINFO 查找目标地址。 Get destination address of a received UDP packet 有一些示例代码。

    【讨论】:

      【解决方案3】:

      如果您希望它只监听接口wlan8,请尝试监听整个网络 - 在这种情况下为10.0.0.0。如果您绑定到接口的 IP,它可能只会接收以它为目标的消息。

      【讨论】:

      • 我把char char *SERVER_IP = "10.0.0.6";换成了char *SERVER_IP = "10.0.0.0";,但还是收不到广播包和单播包。
      猜你喜欢
      • 1970-01-01
      • 2012-07-22
      • 1970-01-01
      • 2011-08-15
      • 1970-01-01
      • 1970-01-01
      • 2012-07-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多