linux下socket指定网卡

本文介绍了如何根据socket号确定TCP连接所在的网卡。对于主动创建的socket,可以通过SO_BINDTODEVICE设置特定网卡;对于被动接受的socket,可以通过获取MAC地址与socket的映射关系来确定其所属网卡。
系统中存在两个网卡,如何根据socket号知道哪个连接(tcp)在哪个网卡上? 根据getpeername好像有点行不通。或者通过SIOCGARP?netlink?
   将问题进行分解,分为主动方式和被动方式两种。主动方式即是系统调用socket创建接口得到的socket号,被动方式即是通过类似accept得到的socket号。
   主动方式创建之后,可以利用setsockopt的SO_BINDTODEVICE。
 

在socket(7)中对该套接口选项的说明如下:

SO_BINDTODEVICE

      Bind this socket to a particular device like "eth0", as specified in the passed interface name. If the name is an empty string or the option length is zero, the socket  device  binding is  removed. The passed option is a variable-length null terminated interface name string with the maximum size  of  IFNAMSIZ. If a socket is bound to an interface, only packets received from that particular interface are processed by the socket. Note that this  only  works  for  some  socket types, particularly AF_INET sockets. It is not supported  for  packet  sockets  (use  normal bind(8) there).

strncpy(interface.ifr_ifrn.ifrn_name, "eth0", \
  strlen("eth0"));
if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, \
  (char *)&interface, sizeof(interface)) 0) {
       perror("SO_BINDTODEVICE failed");
      /* Deal with error... */

}

 对被动方式的socket,如何区分?一种方法是获得MAC与socket的映射关系,进一步确定是哪个网卡对应的哪些socket。

#include <stdio.h> 
#include <sys/types.h> 
#include <sys/param.h> 
#include <sys/ioctl.h> 
#include <sys/socket.h> 
#include <net/if.h> 
#include <netinet/in.h> 
#include <net/if_arp.h> 
#ifdef SOLARIS 
#include <sys/sockio.h> 
#endif 
#define MAXINTERFACES 16 
main (argc, argv) 
register int argc; 
register char *argv[]; 
{ 
   register int fd, intrface, retn = 0; 
   struct ifreq buf[MAXINTERFACES]; 
   struct arpreq arp; 
   struct ifconf ifc; 
if ((fd = socket (AF_INET, SOCK_DGRAM, 0)) >= 0) 
{ 
  ifc.ifc_len = sizeof buf; 
  ifc.ifc_buf = (caddr_t) buf; 
  if (!ioctl (fd, SIOCGIFCONF, (char *) &ifc)) 
  { 
   //获取接口信息

   intrface = ifc.ifc_len / sizeof (struct ifreq); 
    printf("interface num is intrface=%d\n\n\n",intrface); 
   //根据借口信息循环获取设备IP和MAC地址

   while (intrface-- > 0) 
   { 
    //获取设备名称

    printf ("net device %s\n", buf[intrface].ifr_name); 

    //判断网卡类型 

    if (!(ioctl (fd, SIOCGIFFLAGS, (char *) &buf[intrface]))) 
    { 
     if (buf[intrface].ifr_flags & IFF_PROMISC) 
     { 
      puts ("the interface is PROMISC" ); 
      retn++; 
     } 
    } 
    else 
    { 
     char str[256]; 
     sprintf (str, "cpm: ioctl device %s", buf[intrface].ifr_name); 
     perror (str); 
    } 
   //判断网卡状态 

            if (buf[intrface].ifr_flags & IFF_UP) 
   { 
                puts("the interface status is UP" ); 
            } 
            else 
   { 
                puts("the interface status is DOWN" ); 
            } 
   //获取当前网卡的IP地址 

            if (!(ioctl (fd, SIOCGIFADDR, (char *) &buf[intrface]))) 
            { 
                 puts ("IP address is:" ); 
                 puts(inet_ntoa(((struct sockaddr_in*)(&buf[intrface].ifr_addr))->sin_addr)); 
                 puts("" ); 
                   //puts (buf[intrface].ifr_addr.sa_data); 

            } 
            else 
   { 
               char str[256]; 
               sprintf (str, "cpm: ioctl device %s", buf[intrface].ifr_name); 
               perror (str); 
           } 
/* this section can't get Hardware Address,I don't know whether the reason is module driver*/ 
#ifdef SOLARIS 
   //获取MAC地址

            arp.arp_pa.sa_family = AF_INET; 
            arp.arp_ha.sa_family = AF_INET; 
            ((struct sockaddr_in*)&arp.arp_pa)->sin_addr.s_addr=((struct sockaddr_in*)(&buf[intrface].ifr_addr))->sin_addr.s_addr; 
            if (!(ioctl (fd, SIOCGARP, (char *) &arp))) 
            { 
                 puts ("HW address is:" ); 
    //以十六进制显示MAC地址

                 printf("%02x:%02x:%02x:%02x:%02x:%02x\n", 
                                (unsigned char)arp.arp_ha.sa_data[0], 
                                (unsigned char)arp.arp_ha.sa_data[1], 
                                (unsigned char)arp.arp_ha.sa_data[2], 
                                (unsigned char)arp.arp_ha.sa_data[3], 
                                (unsigned char)arp.arp_ha.sa_data[4], 
                                (unsigned char)arp.arp_ha.sa_data[5]); 
                 puts("" ); 
                 puts("" ); 
            } 

#else 
#if 0 
   /*Get HW ADDRESS of the net card */ 
            if (!(ioctl (fd, SIOCGENADDR, (char *) &buf[intrface]))) 
            { 
                 puts ("HW address is:" ); 
                 printf("%02x:%02x:%02x:%02x:%02x:%02x\n", 
                                (unsigned char)buf[intrface].ifr_enaddr[0], 
                                (unsigned char)buf[intrface].ifr_enaddr[1], 
                                (unsigned char)buf[intrface].ifr_enaddr[2], 
                                (unsigned char)buf[intrface].ifr_enaddr[3], 
                                (unsigned char)buf[intrface].ifr_enaddr[4], 
                                (unsigned char)buf[intrface].ifr_enaddr[5]); 
                 puts("" ); 
                 puts("" ); 
            } 
#endif 
            if (!(ioctl (fd, SIOCGIFHWADDR, (char *) &buf[intrface]))) 
            { 
                 puts ("HW address is:" ); 
                 printf("%02x:%02x:%02x:%02x:%02x:%02x\n", 
                                (unsigned char)buf[intrface].ifr_hwaddr.sa_data[0], 
                                (unsigned char)buf[intrface].ifr_hwaddr.sa_data[1], 
                                (unsigned char)buf[intrface].ifr_hwaddr.sa_data[2], 
                                (unsigned char)buf[intrface].ifr_hwaddr.sa_data[3], 
                                (unsigned char)buf[intrface].ifr_hwaddr.sa_data[4], 
                                (unsigned char)buf[intrface].ifr_hwaddr.sa_data[5]); 
                 puts("" ); 
                 puts("" ); 
             } 
#endif 
            else 
   { 
               char str[256]; 
               sprintf (str, "cpm: ioctl device %s", buf[intrface].ifr_name); 
               perror (str); 
           } 
        } //while

      } else 
         perror ("cpm: ioctl" ); 
   } else 
      perror ("cpm: socket" ); 
    close (fd); 
    return retn; 
}

### 获取 Linux 系统中指定网卡的详细信息 在 Linux 系统中,获取特定网络接口(网卡)的详细信息是系统管理和自动化脚本开发中的常见需求。可以通过多种方式实现这一目标,包括使用 shell 命令、读取 `/proc` 或 `/sys` 文件系统内容,以及通过编程语言如 Python 编写脚本来获取和处理数据。 #### 使用 Python 获取指定网卡的 IP 地址 Python 提供了对底层系统调用的支持,可以用于获取网卡的 IP 地址。以下是一个基于 Python 的示例,展示如何获取指定网络接口的 IPv4 地址: ```python import socket import fcntl import struct def get_ip_address(ifname): s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) return socket.inet_ntoa(fcntl.ioctl( s.fileno(), 0x8915, # SIOCGIFADDR struct.pack('256s', ifname[:15]) )[20:24]) # 示例:获取 eth0 接口的 IP 地址 ip_address = get_ip_address('eth0') print("IP Address of eth0: {}".format(ip_address)) ``` 该方法利用了 `socket` 模块创建一个 UDP 套接字,并使用 `fcntl.ioctl` 调用来获取指定网卡的 IP 地址信息[^1]。 #### 使用 Shell 命令获取网卡信息 Linux 提供了一系列命令行工具来查询和配置网络接口的状态和属性。常用的命令包括 `ip`, `ifconfig`, 和 `ethtool`。 - **使用 `ip` 命令** 获取指定网卡的信息: ```bash ip addr show dev eth0 ``` 此命令将显示 `eth0` 接口的所有地址信息,包括 IPv4 和 IPv6 地址、子网掩码等。 - **使用 `ethtool` 命令** 获取网卡的硬件和驱动程序信息: ```bash ethtool -i eth0 ``` 这条命令会输出 `eth0` 接口所使用的驱动程序名称、版本号以及其他相关信息。 #### 从 `/proc` 和 `/sys` 文件系统中提取信息 Linux 内核通过 `/proc` 和 `/sys` 文件系统提供了丰富的运行时系统信息。例如,可以从 `/proc/net/dev` 中读取每个网络接口的数据统计信息,如接收和发送的数据包数量及字节数: ```bash cat /proc/net/dev ``` 对于更详细的网卡状态信息,可以查看 `/sys/class/net/` 目录下的文件。例如,要获取 `eth0` 接口的速度和双工模式设置: ```bash cat /sys/class/net/eth0/speed cat /sys/class/net/eth0/duplex ``` 这些文件通常包含只读信息,适用于监控目的。 #### 结合 C 语言使用 `ioctl` 获取网卡信息 在 C 语言中,也可以使用 `ioctl` 系统调用来获取网卡的详细信息。以下是一个简单的示例代码,展示了如何获取指定网络接口的 MAC 地址: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/ioctl.h> #include <net/if.h> #include <netinet/in.h> int main() { int sockfd; struct ifreq ifr; // 创建 UDP 套接字 sockfd = socket(AF_INET, SOCK_DGRAM, 0); if (sockfd < 0) { perror("socket"); exit(EXIT_FAILURE); } // 设置网卡名称 strcpy(ifr.ifr_name, "eth0"); // 获取 MAC 地址 if (ioctl(sockfd, SIOCGIFHWADDR, &ifr) < 0) { perror("ioctl"); close(sockfd); exit(EXIT_FAILURE); } // 打印 MAC 地址 printf("MAC Address of %s: ", ifr.ifr_name); for (int i = 0; i < 6; ++i) { printf("%02X%s", (unsigned char)ifr.ifr_hwaddr.sa_data[i], (i < 5) ? ":" : ""); } printf("\n"); // 关闭套接字 close(sockfd); return 0; } ``` 此代码段使用 `SIOCGIFHWADDR` ioctl 请求来检索 `eth0` 接口的硬件地址(即 MAC 地址)。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值