跳至主要內容

网卡与网口

LincZero大约 15 分钟

网卡与网口

目录

对应关系

  • 一台机器上可能不只有一个网卡(如平常的笔记本电脑中,就会有无线网卡和有线网卡(网线接口)两种)
  • 每一个网卡只有一个MAC地址
  • 每一个网卡可能配置有多个IP地址

基本信息的查看 - Windows

常用命令行

ipconfig
ipconfig /all

net

# Windows 端口占用和杀进程
netstat -ano|findstr 8090
taskkill /pid 13420 -t -f

程序

(注意cygwin和wsl输出内容不同)

void unit_test_STNetDevice() {
    // 获取所有的网卡设备和 IP 地址
    struct ifaddrs *ifaddr, *ifa;
    int family, s;
    char host[NI_MAXHOST];

    if (getifaddrs(&ifaddr) == -1) {
        perror("getifaddrs");
        // exit(EXIT_FAILURE);
        return;
    }

    // 遍历网卡设备,并选择合适的网口
    printf("检查网卡设备:\n");
    for (ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) {
        if (ifa->ifa_addr == nullptr) {
            continue;
        }
        family = ifa->ifa_addr->sa_family;
        if (family == AF_INET || family == AF_INET6) {
            s = getnameinfo(ifa->ifa_addr, (family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6),
                            host, NI_MAXHOST, nullptr, 0, NI_NUMERICHOST);
            if (s != 0) {
                printf("    getnameinfo() 失败: %s\n", gai_strerror(s));
                // exit(EXIT_FAILURE);
                return;
            }
            printf("    接口名: <%s>, 地址: <%s>\n", ifa->ifa_name, host);
        }
    }
    freeifaddrs(ifaddr);

    // 在选择的网口上创建 socket
    int sockfd;
    struct sockaddr_in server_address;

    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) {
        perror("socket创建失败");
        exit(EXIT_FAILURE);
    }

    memset(&server_address, 0, sizeof(server_address));
    server_address.sin_family = AF_INET;
    server_address.sin_port = htons(8080);

    // 使用已选择的IP地址替换 "selected_ip_address"
    // const char* selected_ip_address = "127.0.0.1";
    // inet_pton(AF_INET, selected_ip_address, &(server_address.sin_addr));
    pause();
}

输出大概是这样的:(可能和cygwin环境有关,这里的接口名几乎不能用……wsl那边倒是正常)

检查网卡设备:
    接口名: <{EC26D318-93D2-4224-A35D-00494EC2838D}>, 地址: <fe80::904e:adc6:4c5f:4039%27>
    接口名: <{EC26D318-93D2-4224-A35D-00494EC2838D}>, 地址: <10.198.75.60>
    接口名: <{EC26D318-93D2-4224-A35D-00494EC2838D}:1>, 地址: <169.254.64.57>
    接口名: <{772DD5EB-BE75-4667-87A9-F9D32AF2FEA1}>, 地址: <fe80::2974:13e1:dcd2:887%16>
    接口名: <{772DD5EB-BE75-4667-87A9-F9D32AF2FEA1}>, 地址: <169.254.8.135>
    接口名: <{1392C1BB-9CE8-4E4C-8A3B-48E7483DD0FB}>, 地址: <fe80::28e8:86ab:5640:de44%7>
    接口名: <{1392C1BB-9CE8-4E4C-8A3B-48E7483DD0FB}>, 地址: <192.168.56.1>
    接口名: <{19AA720B-BC3C-4FE0-8759-B953837FB785}>, 地址: <fe80::98a0:8648:ee8a:89bb%8>
    接口名: <{19AA720B-BC3C-4FE0-8759-B953837FB785}>, 地址: <169.254.137.187>
    接口名: <{5BB4863B-284D-4CC3-B73F-037089DA605C}>, 地址: <fe80::1d7d:cb85:25d5:4918%11>
    接口名: <{5BB4863B-284D-4CC3-B73F-037089DA605C}>, 地址: <169.254.73.24>
    接口名: <{5BB4863B-284D-4CC3-B73F-037089DA605C}:1>, 地址: <192.168.137.1>
    接口名: <{766B55FC-4808-4EE4-B39F-C45C6DBC9204}>, 地址: <fe80::dc96:3a5f:4cca:1588%15>
    接口名: <{766B55FC-4808-4EE4-B39F-C45C6DBC9204}>, 地址: <192.168.134.1>
    接口名: <{5EDF573D-10B0-414D-85D2-377B7EC2451C}>, 地址: <fe80::c1f0:c30:8295:40b9%12>
    接口名: <{5EDF573D-10B0-414D-85D2-377B7EC2451C}>, 地址: <192.168.195.1>
    接口名: <{FA194603-4468-4DD8-BA9E-F4DC05AA1492}>, 地址: <fe80::4132:12:4897:b516%28>
    接口名: <{FA194603-4468-4DD8-BA9E-F4DC05AA1492}>, 地址: <192.168.192.1>
    接口名: <{4068A6F2-91F2-488C-8B89-7796E708D2F1}>, 地址: <fe80::843f:b418:1a60:4bc2%10>
    接口名: <{4068A6F2-91F2-488C-8B89-7796E708D2F1}>, 地址: <169.254.75.194>
    接口名: <{E1E314CB-8278-11EA-B32B-806E6F6E6963}>, 地址: <::1>
    接口名: <{E1E314CB-8278-11EA-B32B-806E6F6E6963}>, 地址: <127.0.0.1>
    接口名: <{B51F4294-253B-4774-83B5-30F997E6A596}>, 地址: <fe80::7842:fb73:2a1f:aeb8%24>
    接口名: <{B51F4294-253B-4774-83B5-30F997E6A596}>, 地址: <192.168.220.1>
    接口名: <{C52ECB1F-B415-4A45-B5FF-FACD70E0F629}>, 地址: <fe80::1cd:7a4f:1cb3:f9ef%25>
    接口名: <{C52ECB1F-B415-4A45-B5FF-FACD70E0F629}>, 地址: <192.168.0.101>
    接口名: <{B0BF9A64-3E48-49CD-8F2A-3BB5A3B39BC3}>, 地址: <fe80::cd14:2016:471d:bcb7%41>
    接口名: <{B0BF9A64-3E48-49CD-8F2A-3BB5A3B39BC3}>, 地址: <172.30.48.1>
    接口名: <{11F036CA-5152-42E4-A706-9C7A7DE01333}>, 地址: <fe80::dd88:a34:e39f:7428%90>
    接口名: <{11F036CA-5152-42E4-A706-9C7A7DE01333}>, 地址: <172.27.80.1>

基本信息的查看 - Linux (ubuntu)

常用命令行

新机可能需要的设置

开机优化

【博客园】Ubuntu20.04 TLS 开机卡在“A start job is running for wait for network to be Configured”解决open in new window

root账户
sudo passwd root # ubuntu默认没有root账户
给普通账户相应的权限

例如:

 chown -R linczero:linczero /home/linczero # 更改文件夹及其内容的所有权
 chmod -R u+rwx /path/to/folder # (可选) 或者给用户user1设置读写执行权限 (rwx)
静态路由的设置

https://blog.csdn.net/yilovexing/article/details/126424086

ssh的检查

(如果能ping同但ssh报错:ssh: connect to host 192.168.1.208 port 22: Connection refused)

telnet <ip-address> 22 # 如果您收到 "connection refused" 或 "connection timeout" 等错误消息,那么 SSH 服务可能未启用或防火墙阻止了连接。您还可以尝试运行以下命令:
ssh -v <ip-address> # 该命令将以详细模式运行 SSH 客户端,并显示客户端与服务器之间的通信。这将使您能够检查建立 SSH 连接期间是否发生任何错误。

systemctl status sshd # 本机上的检查

service ssh start # wsl开启ssh服务(我电脑的wsl每次重启都需要重新运行这个)

还有一种情况是使用root账户ssh时提示连接被拒绝

# 升级到root账户并打开配置文件:
sudo nano /etc/ssh/sshd_config

# 找到"PermitRootLogin prohibit-password"或"PermitRootLogin no" 这一行,将其改成 "PermitRootLogin yes"
# 保存并退出文件

# 重启SSH服务使其生效
service ssh restart
自动关机与自启

脚本

#!/bin/bash

# 设置关机时间,例如7:30pm
shutdown_time="19:30"

# 获取当前时间并转换为时间戳
current_time=$(date +%s)
shutdown_stamp=$(date -d "$shutdown_time" +%s)

# 计算关机时间与当前时间的时间差,并判断是否为负数
time_diff=$(( $shutdown_stamp - $current_time ))
if [ $time_diff -lt 0 ]; then
    echo "关机时间不能早于当前时间!"
    exit 1
fi

# 设置定时关机命令并显示信息
echo "将在 $shutdown_time 关机"
sudo shutdown -h $time_diff

启动。 将以上内容保存为一个名为auto_shutdown.sh的文件,并设置在下午7点自动执行该脚本。可以通过执行以下命令来实现:

sudo crontab -e

# 然后在文件末尾添加以下一行。这将每天的下午7点自动执行/path/to/auto_shutdown.sh脚本,并关机。
0 19 * * * /bin/bash /path/to/auto_shutdown.sh

自启。 最后,你需要将脚本加入到自启中。打开终端,执行以下命令以编辑/etc/rc.local文件:

sudo nano /etc/rc.local

# 在exit 0行之前添加以下命令:
/bin/bash /path/to/auto_shutdown.sh
容器环境
docker # 找不到就会提示你怎么安装了

可能还会安装一个portainer.io可视化管理docker的工具

查看 系统信息

基于ubuntu来写

lsb_release -a # 查看所有版本信息
cat /etc/issue # 查看linux发行版信息
cat /proc/version # 查看操作系统版本信息

uname -a # 查看内核版本
uname -rs # 查看内核版本 (更省略的命令)

查看 包管理器信息

apt-get upgrade # 如有问题看镜像 sudo nano /etc/apt/sources.list
apt-get update

查看 网络信息

lspci # 查看网卡的信息。如果显示未安装驱动,请安装对应的驱动
ifconfig # 查看网卡的状态。如果网卡被禁用,请使用命令「ifconfig [interface] up」启用网卡。
ip addr show # 或ip addr,查看网卡的IP地址。如果没有IP地址,请检查网络设置

#Linux 端口占用和杀进程
lsof -i:8090
kill -9 13420

route

# 查看路由
route -n
sudo route add -net 0.0.0.0 gw 192.168.209.1 netmask 0.0.0.0 dev enp1s0f1 # 手动增加路由(GW是上网口)

ifconfig

ifconfig # 查看网卡的状态。如果网卡被禁用,请使用命令「ifconfig [interface] up」启用网卡。

无法找到ifconfig的解决方法1:有可能需要加sudo,或者直接使用root账户操作

无法找到ifconfig的解决方法2:

# 安装
apt instanll net-tools

# 如果提示已经安装了net-tools包,却无法运行ifconfig,可能的原因是ifconfig命令没有在系统的PATH变量中。您可以按照下面的方法将其添加到PATH中:
# 临时,下次开机失效
export PATH=$PATH:/sbin:/usr/sbin

# 永久
nano ~/.bashrc
# 在文件末尾添加以下内容:
	export PATH=$PATH:/sbin:/usr/sbin
# 按Ctrl+X,然后按Y,再按Enter键保存并退出
source ~/.bashrc # 使更改生效

ethtool(亮灯)、arp

# 查看对应网口
ethtool -p eth0 30 # 让对应网口(eth0)亮灯30s,可能需要先安装:apt-get install ethtooli

# 查看设备之间的Mac地址映射
arp -n

lshw

如果 ifconfig 显示的口不全,用 lshw

ip link show # 这将显示系统上所有可用的网络接口,包括处于禁用状态的接口。

# 另一个方法是检查 lshw 命令的输出。如果您的系统中尚未安装它,请首先安装:
sudo apt-get install lshw    #对于基于Debian的系统,如:Ubuntu
sudo yum install lshw        #对于基于Red Hat的系统,如:CentOS
# 然后,可以运行以下命令来列出所有网络设备:
sudo lshw -class network

# 如果您发现了缺失的网络接口,可能需要启用或者重新启用它们。您可以通过以下命令激活网络接口(请使用您的具体接口名替换 <interface>):
sudo ifconfig <interface> up
# 或者,您也可以使用 ip 命令启用接口:
sudo ip link set <interface> up

# 如果你发现lshw显示出来的部分网口没有接口名(ifconfig能显示出来的接口名就有,不能的就没有)

防火墙

# 防火墙(系统可能用不同的防火墙)
sudo systemctl stop firewalld # 可能报错 bash: firewalld: command not found
sudo ufw disable # 也可能报错 bash: ufw: command not found
sudo iptables -L # 前两个都报错再看

iperf

apt install iperf3
# 服务端
iperf3 -s -B 192.168.208.199 -p 5201
# 客户端(选一)
iperf3 -c 192.168.208.199 -p 5201 --udp
iperf3 -c 192.168.208.199 -p 5201 --udp -l 100 -b 1000M
iperf3 -B 192.168.208.1 -c 192.168.208.199 -p 5201 --udp -l 100 -b 1000M

编辑网口配置文件

编辑网口配置文件1

# 安装ip命令
sudo apt-get update && sudo apt-get install -y iproute2
# 编辑网口配置文件
sudo nano /etc/network/interfaces 
# 参考配置
# eth0 configuration
auto eth0
allow-hotplug eth0
iface eth0 inet static
  address 192.168.1.100   # 将这里的 IP 地址更改为所需的 IP 地址
  netmask 255.255.255.0   # 修改子网掩码,如有必要
  gateway 192.168.1.1     # 修改这里的网关地址,如有必要
  dns-nameservers 8.8.8.8 # 将此设置为所需的 DNS 服务器地址
# 修改完成后可以重启服务
sudo systemctl restart networking

编辑网口配置文件2(ubuntu20.04但默认没有interfaces文件)

# 在 Ubuntu 20.04 中,默认情况下使用 Netplan 作为网络配置工具,而不是传统的 /etc/network/interfaces 文件。Netplan配置文件使用 YAML 文件格式,并存储在/etc/netplan/目录下。
# 要为 eth0 网口设置开机自启并分配默认 IP,遵循以下步骤:
# 找到已有的 Netplan 配置文件,进入 /etc/netplan/ 目录: 

cd /etc/netplan/

# 通常,您将看到一个以 .yaml 结尾的文件。例如,可以是 01-network-manager-all.yaml、50-cloud-init.yaml 或其它名字。每个系统可能都有一个不同的名字。
# 使用文本编辑器打开现有的配置文件。以下示例中,我们将使用 nano 编辑器: 

sudo nano 01-netcfg.yaml

# 注意:请确保使用您看到的 YAML 文件名替换 01-netcfg.yaml。
#     在此配置文件中,为 eth0 界面设置静态 IP。 
# 将以下示例添加并替换 addresses、gateway4 和 nameservers 的值,以匹配您的实际配置。确保缩进与现有的内容保持一致(2缩进不是4缩进,不然后面报错)

network:
  version: 2
  renderer: networkd
  ethernets:
    eth0:
      dhcp4: no
      addresses: [192.168.1.100/24]
      gateway4: 192.168.1.1
      nameservers:
        addresses: [8.8.8.8, 8.8.4.4]

# 保存更改并退出编辑器。按 Ctrl + X,然后按 Y,最后按 Enter 保存文件。
# 应用网络配置。运行以下命令,使 Netplan 应用修改后的配置: 
sudo netplan apply

# 这样,您的 Ubuntu 20.04 系统就设置了网口 eth0 开机自启并分配静态 IP。在计算机重启时,新的网络配置将保持有效。

编辑网口配置文件3(禁用netplan启用interfaces)

# 在 Ubuntu 20.04 下,虽然 /etc/network/interfaces 文件不再是首选的配置方式,但您仍然可以使用它来配置网络。要使用 interfaces 文件进行配置,请按照以下步骤操作:
# 首先,确保已经安装了 ifupdown。如果未安装,请使用以下命令安装: 
sudo apt-get update
sudo apt-get install ifupdown

# 创建 /etc/network/interfaces 文件(如果不存在)并用文本编辑器打开它: 
sudo touch /etc/network/interfaces
sudo nano /etc/network/interfaces
# 在文件中,添加以下内容来配置 ens33 接口。请根据实际情况更改 IP、子网掩码和网关地址: 
auto ens33
iface ens33 inet static
    address 192.168.208.202
    netmask 255.255.255.0
    gateway 192.168.208.1
# 保存文件并退出编辑器。按 Ctrl + X,然后按 Y,最后按 Enter。

# 由于您之前已经尝试使用 Netplan,我们需要禁用 Netplan。要禁用 Netplan,请重命名 /etc/netplan 目录: 
sudo mv /etc/netplan /etc/netplan.bak

# 现在重启网络服务以应用更改: 
sudo systemctl restart networking.service
# 重新启动计算机后,静态 IP 配置应该仍然保持不变。这种方法使用 /etc/network/interfaces 文件配置网络,而不是在 Ubuntu 20.04 中默认的 Netplan。

# 但好像不行……
# 可能报错:Failed to restart networking.service: Unit networking.service not found.
# 这个错误的原因可能是在您的系统上缺少相应的systemd服务。默认情况下,Ubuntu 18.04 及更高版本使用 netplan 进行网络管理,并且没有 networking.service 文件

ioctl

可以获取所有的信息,但是使用起来比较麻烦

#include <stdio.h>
#include <string.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <errno.h>

// 使用 ioctl 函数的版本,更详细
int unit_test_STNetDevice() {
    // 一个空socket,ioctl函数所需要的参数之一
    int fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (fd < 0) {
        perror("socket");
        close(fd);
        return -1;
    }

    // 核心,使用 ioctl 函数获取信息
    struct ifconf ifc;
    struct ifreq buf[16];
    ifc.ifc_len = sizeof(buf);
    ifc.ifc_buf = (caddr_t) buf;
    int iReturn = ioctl(fd, SIOCGIFCONF, (char *) &ifc);
    if (iReturn) {
        printf("错误 ioctl: %s [%s:%d]\n", strerror(errno), __FILE__, __LINE__);
        close(fd);
        return -1;
    }

    // 循环
    int interfaceNum = ifc.ifc_len / sizeof(struct ifreq);
    printf("接口数量: %d\n", interfaceNum);
    struct ifreq ifrcopy;
    char mac[16] = {0};
    char ip[32] = {0};
    char broadAddr[32] = {0};
    char subnetMask[32] = {0};
    while (interfaceNum-- > 0) {
        printf("    ——————————\n");
        printf("    设备名: %s\n", buf[interfaceNum].ifr_name);

        // 忽略未up或未运行的接口
        ifrcopy = buf[interfaceNum];
        if (ioctl(fd, SIOCGIFFLAGS, &ifrcopy)) {
            printf("    错误 ioctl: %s [%s:%d]\n", strerror(errno), __FILE__, __LINE__);
            close(fd);
            return -1;
        }

        // 获取接口的MAC地址
        if (!ioctl(fd, SIOCGIFHWADDR, (char *) (&buf[interfaceNum]))) {
            memset(mac, 0, sizeof(mac));
            snprintf(mac, sizeof(mac), "%02x%02x%02x%02x%02x%02x",
                     (unsigned char) buf[interfaceNum].ifr_hwaddr.sa_data[0],
                     (unsigned char) buf[interfaceNum].ifr_hwaddr.sa_data[1],
                     (unsigned char) buf[interfaceNum].ifr_hwaddr.sa_data[2],
                     (unsigned char) buf[interfaceNum].ifr_hwaddr.sa_data[3],
                     (unsigned char) buf[interfaceNum].ifr_hwaddr.sa_data[4],
                     (unsigned char) buf[interfaceNum].ifr_hwaddr.sa_data[5]);
            printf("    mac地址: %s\n", mac);
        } else {
            printf("    错误 ioctl: %s [%s:%d]\n", strerror(errno), __FILE__, __LINE__);
            close(fd);
            return -1;
        }

        // 获取该接口的IP地址
        if (!ioctl(fd, SIOCGIFADDR, (char *) &buf[interfaceNum])) {
            snprintf(ip, sizeof(ip), "%s",
                     (char *) inet_ntoa(((struct sockaddr_in *) &(buf[interfaceNum].ifr_addr))->sin_addr));
            printf("    设备ip: %s\n", ip);
        } else {
            printf("    错误 ioctl: %s [%s:%d]\n", strerror(errno), __FILE__, __LINE__);
            close(fd);
            return -1;
        }

        // 获取该接口的广义地址/广播地址
        if (!ioctl(fd, SIOCGIFBRDADDR, &buf[interfaceNum])) {
            snprintf(broadAddr, sizeof(broadAddr), "%s",
                     (char *) inet_ntoa(((struct sockaddr_in *) &(buf[interfaceNum].ifr_broadaddr))->sin_addr));
            printf("    广播地址: %s\n", broadAddr);
        } else {
            printf("    错误 ioctl: %s [%s:%d]\n", strerror(errno), __FILE__, __LINE__);
            close(fd);
            return -1;
        }

        // 获取接口的子网掩码
        if (!ioctl(fd, SIOCGIFNETMASK, &buf[interfaceNum])) {
            snprintf(subnetMask, sizeof(subnetMask), "%s",
                     (char *) inet_ntoa(((struct sockaddr_in *) &(buf[interfaceNum].ifr_netmask))->sin_addr));
            printf("    子网掩码: %s\n", subnetMask);
        } else {
            printf("    错误 ioctl: %s [%s:%d]\n", strerror(errno), __FILE__, __LINE__);
            close(fd);
            return -1;
        }
    }

    close(fd);
    return 0;
}

getifaddrs

方便与简洁(但无MAC地址)。值得一提的是,在MacOS或iOS系统上(如iPhone程序开发),上述iotcl函数没法获得mac地址跟子网掩码,这个使用,使用getifaddrs函数便更有优势了

#include <stdio.h>
#include <ifaddrs.h>
#include <arpa/inet.h>

int getSubnetMask()
{
    struct sockaddr_in *sin = NULL;
    struct ifaddrs *ifa = NULL, *ifList;

    if (getifaddrs(&ifList) < 0)
    {
        return -1;
    }

    for (ifa = ifList; ifa != NULL; ifa = ifa->ifa_next)
    {
        if(ifa->ifa_addr->sa_family == AF_INET)
        {
            //printf("n>>> interfaceName: %sn", ifa->ifa_name);
            //sin = (struct sockaddr_in *)ifa->ifa_addr;
            //printf(">>> ipAddress: %sn", inet_ntoa(sin->sin_addr));
            //sin = (struct sockaddr_in *)ifa->ifa_dstaddr;
            //printf(">>> broadcast: %sn", inet_ntoa(sin->sin_addr));
            //sin = (struct sockaddr_in *)ifa->ifa_netmask;
            //printf(">>> subnetMask: %sn", inet_ntoa(sin->sin_addr));
            
            printf("    接口名: <%s>\n", ifa->ifa_name);
            printf("    地址: <%s> <%sn>\n", host, inet_ntoa(((struct sockaddr_in *)ifa->ifa_addr)->sin_addr));
            printf("    广播: <%sn>\n", inet_ntoa(((struct sockaddr_in *)ifa->ifa_dstaddr)->sin_addr));
            printf("    子网掩码: <%sn>\n", inet_ntoa(((struct sockaddr_in *)ifa->ifa_netmask)->sin_addr));
            printf("    ——————————————————\n");
        }
    }

    freeifaddrs(ifList);

    return 0;
}

或更详细:

// 使用 getifaddrs 函数的版本,更简单,无mac地址
int unit_test_STNetDevice_getifaddrs() {
    // 获取所有的网卡设备和 IP 地址
    struct ifaddrs *ifaddr, *ifa;
    char host[NI_MAXHOST];

    if (getifaddrs(&ifaddr) == -1) {
        perror("getifaddrs");
        // exit(EXIT_FAILURE);
        return -1;
    }

    // 遍历网卡设备,并选择合适的网口
    printf("检查网卡设备:\n");
    int family, s;
    for (ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) {
        if (ifa->ifa_addr == nullptr) {
            continue;
        }
        family = ifa->ifa_addr->sa_family;
        if (family != AF_INET) { // || family == AF_INET6) { TODO 暂时过滤ipv6
            continue;
        }

        // 基本接口信息
        s = getnameinfo(ifa->ifa_addr, (family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6),
                        host, NI_MAXHOST, nullptr, 0, NI_NUMERICHOST);
        if (s != 0) {
            printf("    getnameinfo() 失败: %s\n", gai_strerror(s));
            // exit(EXIT_FAILURE);
            return -1;
        }

        printf("    接口名: <%s>\n", ifa->ifa_name);
        printf("    地址: <%s> <%s>\n", host, inet_ntoa(((struct sockaddr_in *) ifa->ifa_addr)->sin_addr));
        printf("    广播地址: <%s>\n", inet_ntoa(((struct sockaddr_in *) ifa->ifa_dstaddr)->sin_addr));
        printf("    子网掩码: <%s>\n", inet_ntoa(((struct sockaddr_in *) ifa->ifa_netmask)->sin_addr));
        printf("    ——————————————————\n");
    }
    freeifaddrs(ifaddr);

    // 在选择的网口上创建 socket
    int sockfd;
    struct sockaddr_in server_address;

    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) {
        perror("socket创建失败");
        exit(EXIT_FAILURE);
    }

    memset(&server_address, 0, sizeof(server_address));
    server_address.sin_family = AF_INET;
    server_address.sin_port = htons(8080);

    // 使用已选择的IP地址替换 "selected_ip_address"
    // const char* selected_ip_address = "127.0.0.1";
    // inet_pton(AF_INET, selected_ip_address, &(server_address.sin_addr));

    return 0;
}

参考输出

——————————————测试1开始——————————————
接口数量: 2
    ——————————
    设备名: eth0
    mac地址: 00155d51ba7d
    设备ip: 172.27.92.56
    广播地址: 172.27.95.255
    子网掩码: 255.255.240.0
    ——————————
    设备名: lo
    mac地址: 000000000000
    设备ip: 127.0.0.1
    广播地址: 0.0.0.0
    子网掩码: 255.0.0.0
——————————————测试2开始——————————————
检查网卡设备:
    接口名: <lo>
    地址: <127.0.0.1> <127.0.0.1>
    广播地址: <127.0.0.1>
    子网掩码: <255.0.0.0>
    ——————————————————
    接口名: <eth0>
    地址: <172.27.92.56> <172.27.92.56>
    广播地址: <172.27.95.255>
    子网掩码: <255.255.240.0>
    ——————————————————
——————————————测试正常结束——————————————

其他一些工作笔记

禁用本地回环

# 您可以通过设置网络配置和防火墙规则来实现这一目标。
# 首先,确保你的两个网口(假设为eth0和eth1)都已经正确配置并已连接到同一台交换机。为每个网口分配不同的 IP 地址。示例:

eth0: IP 地址为 192.168.1.10
eth1: IP 地址为 192.168.1.20

# 然后,确保这两个网络接口启用并且在同一个子网(例如 255.255.255.0)。
# 接下来,需要设置防火墙规则,确保数据流通过正确的网口。示例防火墙规则如下:
# 确保内核启用反向路由。这可防止数据包沿错误的网络接口进入或离开: 

echo 1 > /proc/sys/net/ipv4/conf/all/rp_filter
echo 1 > /proc/sys/net/ipv4/conf/eth0/rp_filter
echo 1 > /proc/sys/net/ipv4/conf/eth1/rp_filter

# 修改防火墙规则以便确保数据经过正确的接口。在这里,我们使用 iptables 修改: 

iptables -A OUTPUT -t mangle -p tcp -s 192.168.1.10 --sport 12345 -d 192.168.1.20 --dport 23456 -j MARK --set-mark 1
iptables -A OUTPUT -t mangle -p tcp -s 192.168.1.20 --sport 23456 -d 192.168.1.10 --dport 12345 -j MARK --set-mark 2
iptables -A PREROUTING -t mangle -p tcp -s 192.168.1.20 --sport 23456 -d 192.168.1.10 --dport 12345 -j MARK --set-mark 1
iptables -A PREROUTING -t mangle -p tcp -s 192.168.1.10 --sport 12345 -d 192.168.1.20 --dport 23456 -j MARK --set-mark 2

# 再使用 iproute2 工具设置与标记相关的路由规则:

ip rule add fwmark 1 table 1
ip rule add fwmark 2 table 2
ip route add default via 192.168.1.1 dev eth0 table 1
ip route add default via 192.168.1.1 dev eth1 table 2

# 如此,流量就会正确地在两个网络接口之间往返。
# 注意:确保您的操作系统中安装了 iptables 和 iproute2 并且将命令修改为符合您实际网络和端口设置。
# 在设置完成后,您可以在本地发送和接收数据,并通过交换机实现网口间的真实数据传输。