如何从C程序获取NIC详细信息?
我想获取连接到我的计算机的所有NIC的以下详细信息: 1) 接口名称(例如eth0) 2) 如果Linux中存在这样的东西,接口号(如中所示) 3) NIC带宽容量和模式(例如1Gb/s全双工) 此命令将列出有关eth1的所有详细信息,包括速度、双工、端口 您可以使用popen()获取输出并映射它 POPEN(3)Linux程序员手册如何从C程序获取NIC详细信息?,c,linux,C,Linux,我想获取连接到我的计算机的所有NIC的以下详细信息: 1) 接口名称(例如eth0) 2) 如果Linux中存在这样的东西,接口号(如中所示) 3) NIC带宽容量和模式(例如1Gb/s全双工) 此命令将列出有关eth1的所有详细信息,包括速度、双工、端口 您可以使用popen()获取输出并映射它 POPEN(3)Linux程序员手册 波本(3) 名字 popen,pclose-流程中的管道流 概要 #包括 FILE *popen(const char *command, const ch
波本(3) 名字 popen,pclose-流程中的管道流 概要 #包括
FILE *popen(const char *command, const char *type);
(一)
(2) ,
(3) 我不确定这一点,但您可能可以通过一个
SIOCGIF*
参数或从/proc
获得它。下面的链接用一个工作示例很好地解释了getifaddrs
函数
您可以使用获取所有接口的链接列表,然后使用ioctl(fd、SIOCGIFINDEX、struct ifreq*)
获取每个接口的接口索引。由于接口是连续的,并且总是列出的(无论它们是否处于启动(活动)状态),因此我选择使用ioctl(fd,SIOCGIFNAME,struct ifreq*)
来使用循环枚举它们。在所有情况下,fd
都是一个AF\u INET
socket
要获得接口的双工和速度,您需要使用ioctl(fd,SIOCETHTOOL,struct ifreq*)
和ifr\u数据
指向struct ethtool\u cmd
的cmd=ethtool\u GSET
如果IOCTL失败,则应返回-1;如果成功,则应返回非负值(我相信为零)
以下是一个示例程序:
#include <unistd.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/ip.h>
#include <net/if.h>
#include <linux/ethtool.h>
#include <linux/sockios.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
struct interface {
int index;
int flags; /* IFF_UP etc. */
long speed; /* Mbps; -1 is unknown */
int duplex; /* DUPLEX_FULL, DUPLEX_HALF, or unknown */
char name[IF_NAMESIZE + 1];
};
static int get_interface_common(const int fd, struct ifreq *const ifr, struct interface *const info)
{
struct ethtool_cmd cmd;
int result;
/* Interface flags. */
if (ioctl(fd, SIOCGIFFLAGS, ifr) == -1)
info->flags = 0;
else
info->flags = ifr->ifr_flags;
ifr->ifr_data = (void *)&cmd;
cmd.cmd = ETHTOOL_GSET; /* "Get settings" */
if (ioctl(fd, SIOCETHTOOL, ifr) == -1) {
/* Unknown */
info->speed = -1L;
info->duplex = DUPLEX_UNKNOWN;
} else {
info->speed = ethtool_cmd_speed(&cmd);
info->duplex = cmd.duplex;
}
do {
result = close(fd);
} while (result == -1 && errno == EINTR);
if (result == -1)
return errno;
return 0;
}
int get_interface_by_index(const int index, struct interface *const info)
{
int socketfd, result;
struct ifreq ifr;
if (index < 1 || !info)
return errno = EINVAL;
socketfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
if (socketfd == -1)
return errno;
ifr.ifr_ifindex = index;
if (ioctl(socketfd, SIOCGIFNAME, &ifr) == -1) {
do {
result = close(socketfd);
} while (result == -1 && errno == EINTR);
return errno = ENOENT;
}
info->index = index;
strncpy(info->name, ifr.ifr_name, IF_NAMESIZE);
info->name[IF_NAMESIZE] = '\0';
return get_interface_common(socketfd, &ifr, info);
}
int get_interface_by_name(const char *const name, struct interface *const info)
{
int socketfd, result;
struct ifreq ifr;
if (!name || !*name || !info)
return errno = EINVAL;
socketfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
if (socketfd == -1)
return errno;
strncpy(ifr.ifr_name, name, IF_NAMESIZE);
if (ioctl(socketfd, SIOCGIFINDEX, &ifr) == -1) {
do {
result = close(socketfd);
} while (result == -1 && errno == EINTR);
return errno = ENOENT;
}
info->index = ifr.ifr_ifindex;
strncpy(info->name, name, IF_NAMESIZE);
info->name[IF_NAMESIZE] = '\0';
return get_interface_common(socketfd, &ifr, info);
}
int main(int argc, char *argv[])
{
struct interface iface;
int arg;
int status = 0;
if (argc > 1 && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))) {
fprintf(stderr, "\n");
fprintf(stderr, "Usage: %s { -h | --help }\n", argv[0]);
fprintf(stderr, " %s\n", argv[0]);
fprintf(stderr, " %s INTERFACE ...\n", argv[0]);
fprintf(stderr, "\n");
return 1;
}
if (argc > 1) {
for (arg = 1; arg < argc; arg++) {
if (get_interface_by_name(argv[arg], &iface) != 0) {
fprintf(stderr, "%s: No such interface.\n", argv[arg]);
status = 1;
continue;
}
printf("%s: Interface %d", iface.name, iface.index);
if (iface.flags & IFF_UP)
printf(", up");
if (iface.duplex == DUPLEX_FULL)
printf(", full duplex");
else
if (iface.duplex == DUPLEX_HALF)
printf(", half duplex");
if (iface.speed > 0)
printf(", %ld Mbps", iface.speed);
printf("\n");
}
} else {
for (arg = 1; ; arg++) {
if (get_interface_by_index(arg, &iface) != 0)
break;
printf("%s: Interface %d", iface.name, iface.index);
if (iface.flags & IFF_UP)
printf(", up");
if (iface.duplex == DUPLEX_FULL)
printf(", full duplex");
else
if (iface.duplex == DUPLEX_HALF)
printf(", half duplex");
if (iface.speed > 0)
printf(", %ld Mbps", iface.speed);
printf("\n");
}
}
return status;
}
要查看用法,请运行iflist-h
。要列出所有接口,请在不带参数的情况下运行:
./iflist
上面将使用我描述的枚举方法。要仅列出特定的接口,请运行它命名接口:
./iflist eth0 lo
当然,双工和速度仅针对以太网接口列出
编辑以添加: 如果上面的程序不提供接口的带宽和模式,这里有一个简化版本,报告确切原因(错误)。这个函数将接口名作为命令行参数;它不枚举接口
#include <unistd.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/ip.h>
#include <net/if.h>
#include <linux/ethtool.h>
#include <linux/sockios.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
int ethernet_interface(const char *const name,
int *const index, int *const speed, int *const duplex)
{
struct ifreq ifr;
struct ethtool_cmd cmd;
int fd, result;
if (!name || !*name) {
fprintf(stderr, "Error: NULL interface name.\n");
fflush(stderr);
return errno = EINVAL;
}
if (index) *index = -1;
if (speed) *speed = -1;
if (duplex) *duplex = -1;
fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd == -1) {
const int err = errno;
fprintf(stderr, "%s: Cannot create AF_INET socket: %s.\n", name, strerror(err));
fflush(stderr);
return errno = err;
}
strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
ifr.ifr_data = (void *)&cmd;
cmd.cmd = ETHTOOL_GSET;
if (ioctl(fd, SIOCETHTOOL, &ifr) < 0) {
const int err = errno;
do {
result = close(fd);
} while (result == -1 && errno == EINTR);
fprintf(stderr, "%s: SIOCETHTOOL ioctl: %s.\n", name, strerror(err));
return errno = err;
}
if (speed)
*speed = ethtool_cmd_speed(&cmd);
if (duplex)
switch (cmd.duplex) {
case DUPLEX_HALF: *duplex = 0; break;
case DUPLEX_FULL: *duplex = 1; break;
default:
fprintf(stderr, "%s: Unknown mode (0x%x).\n", name, cmd.duplex);
fflush(stderr);
*duplex = -1;
}
if (index && ioctl(fd, SIOCGIFINDEX, &ifr) >= 0)
*index = ifr.ifr_ifindex;
do {
result = close(fd);
} while (result == -1 && errno == EINTR);
if (result == -1) {
const int err = errno;
fprintf(stderr, "%s: Error closing socket: %s.\n", name, strerror(err));
return errno = err;
}
return 0;
}
int main(int argc, char *argv[])
{
int arg, speed, index, duplex;
if (argc < 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
fprintf(stderr, "\n");
fprintf(stderr, "Usage: %s [ -h | --help ]\n", argv[0]);
fprintf(stderr, " %s INTERFACE ...\n", argv[0]);
fprintf(stderr, "\n");
return 0;
}
for (arg = 1; arg < argc; arg++) {
if (ethernet_interface(argv[arg], &index, &speed, &duplex))
return 1;
if (index == -1)
printf("%s: (no interface index)", argv[arg]);
else
printf("%s: interface %d", argv[arg], index);
if (speed == -1)
printf(", unknown bandwidth");
else
printf(", %d Mbps bandwidth", speed);
if (duplex == 0)
printf(", half duplex.\n");
else if (duplex == 1)
printf(", full duplex.\n");
else
printf(", unknown mode.\n");
}
return 0;
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
int ethernet_接口(常量字符*常量名称,
int*常数索引、int*常数速度、int*常数双工)
{
结构ifreq-ifr;
结构ethtool_cmd;
int-fd,结果;
如果(!name | |!*name){
fprintf(stderr,“错误:空接口名。\n”);
fflush(stderr);
返回errno=EINVAL;
}
如果(指数)*指数=-1;
如果(速度)*速度=-1;
如果(双工)*双工=-1;
fd=套接字(AF_INET,SOCK_STREAM,0);
如果(fd==-1){
常量int err=errno;
fprintf(stderr,“%s:无法创建AF_INET套接字:%s。\n”,名称,strerror(err));
fflush(stderr);
返回errno=err;
}
strncpy(ifr.ifr\u名称、名称、ifr的大小、ifr\u名称);
ifr.ifr_data=(void*)&cmd;
cmd.cmd=ETHTOOL\u GSET;
如果(ioctl(fd、SIOCETHTOOL和ifr)<0){
常量int err=errno;
做{
结果=关闭(fd);
}而(结果==-1&&errno==EINTR);
fprintf(标准字符,“%s:SIOCETHTOOL ioctl:%s.\n”,名称,strerror(err));
返回errno=err;
}
如果(速度)
*速度=ethtool\u cmd\u速度(&cmd);
中频(双工)
交换机(命令双工){
双联箱半:*双联箱=0;断开;
双联箱满:*双联箱=1;断开;
违约:
fprintf(stderr,“%s:未知模式(0x%x)。\n”,名称,cmd.duplex);
fflush(stderr);
*双工=-1;
}
如果(索引和ioctl(fd、SIOCGIFINDEX和ifr)>=0)
*指数=ifr.ifr\U ifindex;
做{
结果=关闭(fd);
}而(结果==-1&&errno==EINTR);
如果(结果==-1){
常量int err=errno;
fprintf(stderr,“%s:关闭套接字时出错:%s.\n”,名称,strerror(err));
返回errno=err;
}
返回0;
}
int main(int argc,char*argv[])
{
int参数、速度、索引、双工;
if(argc<2 | |!strcmp(argv[1],“-h”)| |!strcmp(argv[1],“-help”)){
fprintf(标准格式,“\n”);
fprintf(stderr,“用法:%s[-h |--help]\n”,argv[0]);
fprintf(stderr,“%s接口…\n”,argv[0]);
fprintf(标准格式,“\n”);
返回0;
}
对于(arg=1;arg
问题?,还有chekcout@Joe:它不会告诉你2和3。在你得到答案之前这是一个开始。这是我得到的输出$。/iflist lo:Interface 1,up eth0:Interface 2,upI也在其他一些机器上试用过。我没有获得带宽和模式。@布鲁斯:原因是您的接口不支持用于获取模式和带宽的
SIOCETHTOOL
ioctl。这些机器上有什么样的接口?Infiniband?ethtool eth0
能提供这些设备上的带宽和模式吗?@Bruce:Scratch;infiniband等似乎确实支持IOCTL。您能编译并运行我刚才添加的第二个示例代码吗?在检查了一个旧的RHEL系统之后,我注意到我得到了eth0:S
./iflist eth0 lo
#include <unistd.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/ip.h>
#include <net/if.h>
#include <linux/ethtool.h>
#include <linux/sockios.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
int ethernet_interface(const char *const name,
int *const index, int *const speed, int *const duplex)
{
struct ifreq ifr;
struct ethtool_cmd cmd;
int fd, result;
if (!name || !*name) {
fprintf(stderr, "Error: NULL interface name.\n");
fflush(stderr);
return errno = EINVAL;
}
if (index) *index = -1;
if (speed) *speed = -1;
if (duplex) *duplex = -1;
fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd == -1) {
const int err = errno;
fprintf(stderr, "%s: Cannot create AF_INET socket: %s.\n", name, strerror(err));
fflush(stderr);
return errno = err;
}
strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
ifr.ifr_data = (void *)&cmd;
cmd.cmd = ETHTOOL_GSET;
if (ioctl(fd, SIOCETHTOOL, &ifr) < 0) {
const int err = errno;
do {
result = close(fd);
} while (result == -1 && errno == EINTR);
fprintf(stderr, "%s: SIOCETHTOOL ioctl: %s.\n", name, strerror(err));
return errno = err;
}
if (speed)
*speed = ethtool_cmd_speed(&cmd);
if (duplex)
switch (cmd.duplex) {
case DUPLEX_HALF: *duplex = 0; break;
case DUPLEX_FULL: *duplex = 1; break;
default:
fprintf(stderr, "%s: Unknown mode (0x%x).\n", name, cmd.duplex);
fflush(stderr);
*duplex = -1;
}
if (index && ioctl(fd, SIOCGIFINDEX, &ifr) >= 0)
*index = ifr.ifr_ifindex;
do {
result = close(fd);
} while (result == -1 && errno == EINTR);
if (result == -1) {
const int err = errno;
fprintf(stderr, "%s: Error closing socket: %s.\n", name, strerror(err));
return errno = err;
}
return 0;
}
int main(int argc, char *argv[])
{
int arg, speed, index, duplex;
if (argc < 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
fprintf(stderr, "\n");
fprintf(stderr, "Usage: %s [ -h | --help ]\n", argv[0]);
fprintf(stderr, " %s INTERFACE ...\n", argv[0]);
fprintf(stderr, "\n");
return 0;
}
for (arg = 1; arg < argc; arg++) {
if (ethernet_interface(argv[arg], &index, &speed, &duplex))
return 1;
if (index == -1)
printf("%s: (no interface index)", argv[arg]);
else
printf("%s: interface %d", argv[arg], index);
if (speed == -1)
printf(", unknown bandwidth");
else
printf(", %d Mbps bandwidth", speed);
if (duplex == 0)
printf(", half duplex.\n");
else if (duplex == 1)
printf(", full duplex.\n");
else
printf(", unknown mode.\n");
}
return 0;
}