【问题标题】:How can I prevent SIOCGIFADDR from failing?如何防止 SIOCGIFADDR 失败?
【发布时间】:2014-01-09 18:31:35
【问题描述】:

我想获取 eth0 的 IP。这是我写的(也许有办法解决它?):

int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
check(sockfd > 0, "cannot create socket\n");

#define INTERFACE_NAME "eth0"
#define INTERFACE_NAME_LENGTH 4

char *opt = INTERFACE_NAME;
rc = setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, opt, INTERFACE_NAME_LENGTH);
check(rc == 0, "BINDTODEVICE failed");

struct ifreq req;
strncpy(req.ifr_name, INTERFACE_NAME, IFNAMSIZ);
rc = ioctl(sockfd, SIOCGIFADDR, (unsigned long)&req);
check(rc == 0, "SIOCGIFADDR failed");
server_ip = ((struct sockaddr_in*)&req.ifr_addr)->sin_addr.s_addr;
char str[50];
inet_ntop(AF_INET, &(server_ip), str, INET_ADDRSTRLEN);
debug("serverip: %s", str);

return sockfd;

error:
if (sockfd) close(sockfd);
exit(1); 

我收到以下错误:

[错误] (src/server/server.c:43: errno: 无法分配请求的地址) SIOCGIFADDR 失败

如果我对 wlan0 使用相同的方法,我会得到预期的结果。

这是 netstat 的输出:

netstat -tulpn:

Proto | Local Address   |  PID

udp   | 0.0.0.0:16313   | 4666/dhclient   
udp   | 0.0.0.0:68      | 4687/dhclient   
udp   | 0.0.0.0:68      | 4666/dhclient 

所以,我认为我无法分配地址是因为 dhclients?为什么有这么多?为什么在 16313 端口上有一个?

更新:

我加了

auto eth0
iface eth0 inet static
        address 192.168.1.1
        netmask 255.255.255.0

到 /etc/network/interfaces 并重新启动网络并取得了一些进展:

DEBUG src/server/server.c:50: serverip: 192.168.1.1

然后我可以成功绑定套接字,但是连接会在几秒钟内无缘无故地死掉。

【问题讨论】:

  • 我认为你需要一个req.ifr_addr.sa_family = AF_INET 来告诉 SIOCGIFADDR 调用你想要什么类型的地址。
  • @MarkPlotnick 不幸的是,它没有帮助!我使用了这段代码:man7.org/linux/man-pages/man3/getifaddrs.3.html,据说eth0是AF_PACKET。不知道为什么!
  • 在看到您的问题的更新后,答案似乎是“当没有为接口分配 IP 地址时,SIOCGIFADDR 将失败”。对于您的新问题-为什么几秒钟后连接失败-您可能应该将此作为单独的问题发布。包括ifconfig 的输出和执行connect 并传输数据的代码。我的猜测:路由器通常使用以.1 结尾的地址。您选择的地址 192.168.1.1 可能已被您网络上其他地方的路由器使用。
  • @MarkPlotnick 奇怪的是,重启后问题就消失了。但我确信这与路由器无关,因为我没有连接到任何路由器。

标签: c sockets ioctl


【解决方案1】:

由于我一直在寻找原始问题的答案,因此我将根据提出问题的人的进一步研究,正式写下 Mark Plotnick 在上面给出的答案作为评论:

如果没有为接口分配地址,SIOCGIFADDR 将失败,errno 设置为 EADDRNOTAVAIL。正如最初的提问者所发现的那样,要阻止它失败,请设置接口的 IP 地址。

strerror() 将 EADDRNOTAVAIL 转换为“无法分配请求的地址”,在这种情况下,您正在读取地址而不是分配地址,这会误导到错误的地步。

【讨论】:

    【解决方案2】:

    几年前我就使用过这个代码。这应该会有所帮助。

    #include <stdio.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <sys/ioctl.h>
    #include <netinet/in.h>
    #include <net/if.h>
    #include <unistd.h>
    #include <arpa/inet.h>
    
    int main()
    {
        int sock;
        struct ifreq ifr;
    
        char ifname[10] = "eth0";
    
        sock = socket(AF_INET, SOCK_STREAM, 0);
    
        //Type of address to retrieve - IPv4 IP address
        ifr.ifr_addr.sa_family = AF_INET;
    
        //Copy the interface name in the ifreq structure
        strncpy(ifr.ifr_name , ifname , 30);
    
        ioctl(sock, SIOCGIFADDR, &ifr);
    
        close(fd);
    
        //display result
        printf("%s - %s\n" , iface , inet_ntoa(( (struct sockaddr_in *)&ifr.ifr_addr )->sin_addr) );
    
        return 0;
    }
    

    【讨论】:

    • 跟我上面发的不一样吗?
    • 正如上面提到的其他人,您错过了 req.ifr_addr.sa_family = AF_INET 这一行
    • 正如我在上面写的,这条线没有帮助:-(
    【解决方案3】:

    我要获取eth0的IP

    请改用getifaddrs

    ifaddrs* pList = NULL;
    ifaddrs* pAdapter = NULL;
    ifaddrs* pAdapterFound = NULL;
    const char* pszAdapterName = "eth0";
    int family = AF_INET; // can be AF_INET6 if you want ipv6
    
    int result = getifaddrs(&pList);
    if (result > 0)
    {
        pAdapter = pList;
    
        while (pAdapter)
        {
            if ((pAdapter->ifa_addr != NULL) && (pAdapter->ifa_name != NULL) && (family == pAdapter->ifa_addr->sa_family))
            {
                if (strcmp(pAdapter->ifa_name, pszAdapterName) == 0)
                {
                    pAdapterFound = pAdapter;
                    break;
                }
            }
            pAdapter = pAdapter->ifa_next;
        }
    
        if (pAdapterFound)
        {
            if (family == AF_INET)
            {
                sockaddr_in addr4 =  *(sockaddr_in*)(pAdapter->ifa_addr);
            }
            else if (family == AF_INET6)
            {
                sockaddr_in6 addr6 =  *(sockaddr_in6*)(pAdapter->ifa_addr);
            }
        }
    
        if (pList)
        {
            freeifaddrs(pList);
            pList = NULL;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-10-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-09
      • 1970-01-01
      • 2011-02-09
      • 2020-01-16
      相关资源
      最近更新 更多