LInux环境下以太网的查询修改等操作(C实现)

2024-01-18  本文已影响0人  狼少丷

一、每个方法的实现

0. 0 宏和一些声明
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <net/if.h>
#include <unistd.h>
#include <stdbool.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <netinet/ip.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <net/if_arp.h>
#include <linux/nl80211.h>
#include <linux/wireless.h>
#include <netinet/if_ether.h>
#include "HRDSP.h"

static struct ifreq ifr;
static int fd;
0.1 创建套接字Socket
/* 创建Socket */
static int if_socket()
{
    int sock = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock < 0)
    {
        perror("socket");
        return FALSE;
    }
    return sock;
}
1. 检测指定网络接口是否存在
bool_t netif_is_exist(const char *ifname)
{
    // 创建socket以进行ioctl调用
    fd = if_socket();

    strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1);
    ifr.ifr_name[IFNAMSIZ - 1] = '\0';

    if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0)
    {
        perror("ioctl");
        close(fd);
        return FALSE;
    }
    else
        return TRUE;
}
2. 检测指定网络接口链路是否连接
bool_t netif_is_link(const char *ifname)
{
    // 创建socket以进行ioctl调用
    fd = if_socket();

    // 清零ifr结构体并设置要检查的接口名称
    memset(&ifr, 0, sizeof(ifr));
    strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));

    // 调用ioctl获取网络接口标志
    if (ioctl(fd, SIOCGIFFLAGS, &ifr) == -1)
    {
        perror("ioctl");
        close(fd);
        exit(1);
    }

    // 检查IFF_RUNNING标志,确定链路状态
    if (ifr.ifr_flags & IFF_RUNNING)
    {
        return TRUE;
    }
    else
    {
        return FALSE;
    }

    // 关闭socket
    close(fd);
}
3. 检测指定网络接口是否开启
bool_t netif_is_up(const char *ifname)
{
    // 创建socket以进行ioctl调用
    fd = if_socket();

    strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1);

    if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0)
    {
        perror("ioctl");
        close(fd);
        return FALSE;
    }

    close(fd);
    if (ifr.ifr_flags & IFF_UP)
    {
        return TRUE;
    }
    else
    {
        return FALSE;
    }
}
4. 开启或关闭网络接口
bool_t netif_up(const char *ifname, bool_t up)
{
    // 创建socket以进行ioctl操作
    fd = if_socket();

    // 清零ifr结构体,并设置需要操作的网络接口名
    memset(&ifr, 0, sizeof(ifr));
    strncpy(ifr.ifr_name, ifname, IFNAMSIZ);

    // 获取当前网络接口的配置
    if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0)
    {
        perror("SIOCGIFFLAGS");
        close(fd);
        return FALSE;
    }

    if (netif_is_up(ifname) == up)
    {
        // 当前状态与需求状态一致
        return TRUE;
    }
    else
    {
        // 根据enable的值设置IFF_UP标志位来打开或关闭网络接口
        if (up == TRUE)
        {
            ifr.ifr_flags |= IFF_UP;
        }
        else
        {
            ifr.ifr_flags &= ~IFF_UP;
        }
        // 设置网络接口的状态
        if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0)
        {
            perror("SIOCSIFFLAGS");
            close(fd);
            return FALSE;
        }
    }

    close(fd);
    // 检查开启转态并返回
    return netif_is_up(ifname) == up;
}
5.获取指定网络接口MAC地址
bool_t netif_get_mac(const char *ifname, MacAddr_t mac)
{
    // 创建socket以进行ioctl调用
    fd = if_socket();

    ifr.ifr_addr.sa_family = AF_INET;
    strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1);

    if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0)
    {
        perror("ioctl");
        close(fd);
        return FALSE;
    }

    close(fd);
    memcpy(mac, ifr.ifr_hwaddr.sa_data, 6);

    return TRUE;
}

6. 设置指定网络接口MAC地址
bool_t netif_set_mac(const char *ifname, MacAddr_t mac)
{
    // 创建socket以进行ioctl调用
    fd = if_socket();

    // 指定要修改的网络接口
    strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1);

    // 准备好新的MAC地址
    ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
    memcpy(ifr.ifr_hwaddr.sa_data, mac, ETH_ALEN);

    // 调用ioctl设置MAC地址
    if (ioctl(fd, SIOCSIFHWADDR, &ifr) < 0)
    {
        perror("ioctl");
        close(fd);
        return FALSE;
    }

    close(fd);
    return TRUE;
}
7. 获取指定网络接口IP地址
bool_t netif_get_ip(const char *ifname, in_addr_t *ip)
{
    // 创建socket以进行ioctl调用
    fd = if_socket();

    ifr.ifr_addr.sa_family = AF_INET;
    strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1);

    if (ioctl(fd, SIOCGIFADDR, &ifr) < 0)
    {
        perror("ioctl");
        close(fd);
        return FALSE;
    }
    close(fd);

    struct sockaddr_in *addr = (struct sockaddr_in *)&ifr.ifr_addr;
    *ip = addr->sin_addr.s_addr;

    return TRUE;
}
8. 设置指定网络接口IP地址
bool_t netif_set_ip(const char *ifname, const char *in_addr_tip)
{
    // 构建设置IP地址的命令字符串
    char command[100];
    snprintf(command, sizeof(command), "ifconfig %s %s", ifname, in_addr_tip);

    // 执行命令,设置IP地址
    int ret = system(command);

    if (ret == -1)
    {
        printf("Failed to set IP address.\n");
        return FALSE;
    }
    else
    {
        printf("IP address set successfully.\n");
        return TRUE;
    }
}
9.获取指定网络接口子网掩码
bool_t netif_get_mask(const char *ifname, in_addr_t *ip)
{
    // 创建socket以进行ioctl调用
    fd = if_socket();

    strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
    if (ioctl(fd, SIOCGIFNETMASK, &ifr) < 0)
    {
        perror("ioctl");
        close(fd);
        return FALSE;
    }

    close(fd);

    struct sockaddr_in *addr = (struct sockaddr_in *)&ifr.ifr_netmask;
    *ip = addr->sin_addr.s_addr;

    return TRUE;
}
10. 设置指定网络接口子网掩码
bool_t netif_set_mask(const char *ifname, in_addr_t mask)
{
    struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr;
    struct sockaddr_in *addr;

    // 创建socket以进行ioctl调用
    fd = if_socket();

    // 清空ifr结构体并设置网络接口名称,例如 "eth0"
    memset(&ifr, 0, sizeof(ifr));
    strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name) - 1);

    // 获取当前的子网掩码
    if (ioctl(fd, SIOCGIFNETMASK, &ifr) == -1)
    {
        perror("ioctl");
        close(fd);
        exit(EXIT_FAILURE);
    }
    // 准备好 sockaddr_in 结构体设置子网掩码
    addr = (struct sockaddr_in *)&ifr.ifr_addr;
    addr->sin_family = AF_INET;
    addr->sin_addr.s_addr = mask;

    // 使用SIOCSIFNETMASK ioctl命令设置子网掩码
    if (ioctl(fd, SIOCSIFNETMASK, &ifr) == -1)
    {
        perror("ioctl SIOCSIFNETMASK failed");
        close(fd);
        return FALSE;
    }

    // 操作成功
    close(fd);
    return TRUE;
}
11.设置指定网络接口发送队列长度
bool_t netif_set_txqueue(const char *ifname, uint32_t len)
{

    // 构建设置IP地址的命令字符串
    char command[100];
    snprintf(command, sizeof(command), "ifconfig %s txqueuelen %d", ifname, len);

    // 执行命令,设置IP地址
    int ret = system(command);

    if (ret == -1)
    {
        printf("Failed to set txqueuelen.\n");
        return FALSE;
    }
    else
    {
        printf("TxqueueLen set successfully.\n");
        return TRUE;
    }
}
12. 设置指定网络接口最大包负载MTU
bool_t netif_set_mtu(const char *ifname, uint32_t mtu)
{

    // 为了设置MTU先关不端口
    if (netif_up(ifname, 0) != TRUE)
    {
        return FALSE;
    }

    // 创建socket以进行ioctl调用
    fd = if_socket();

    // 清零结构体
    memset(&ifr, 0, sizeof(ifr));
    // 指定网络接口名称
    strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1);

    // 获取当前接口参数
    if (ioctl(fd, SIOCGIFMTU, &ifr) < 0)
    {
        perror("0 ioctl SIOCGIFMTU");
        close(fd);
        return FALSE;
    }

    printf("Current MTU of %s is %d chenge %d\n", ifname, ifr.ifr_mtu, mtu);

    if (ifr.ifr_mtu == mtu)
    {
        printf("Current MTU of %s is %d == %d\n", ifname, ifr.ifr_mtu, mtu);

        return TRUE;
    }

    // 设置新的MTU
    ifr.ifr_mtu = mtu;
    if (ioctl(fd, SIOCSIFMTU, &ifr) != 0)
    {
        perror("ioctl");

        return FALSE;
    }

    // 再次获取新设置的MTU
    if (ioctl(fd, SIOCGIFMTU, &ifr) < 0)
    {
        perror("ioctl");
        close(fd);
        return FALSE;
    }

    printf("New MTU of %s is %d\n", ifname, ifr.ifr_mtu);

    // 关闭socket
    close(fd);
    // 设置MTU后再重启端口
    netif_up(ifname, 1);
    return TRUE;
}
13.获取收发包的数量
bool_t netif_get_bytes(char *ifname, unsigned long long *tx_bytes, unsigned long long *rx_bytes)
{
    FILE *fp;
    char buffer[1024];
    char *line;

    // 打开/proc/net/dev文件
    fp = fopen("/proc/net/dev", "r");
    if (fp == NULL)
    {
        perror("Error opening file");
        return FALSE;
    }

    // 读取文件,直到找到相应的网络接口
    while (fgets(buffer, sizeof(buffer), fp))
    {
        if (strstr(buffer, ifname))
        {
            // 这里假设行的格式是以下这种类型的:
            // eth0: 123455  162100    ...(其他统计数据)
            // 您可能需要根据实际情况调整 sscanf 的格式字符串来适配

            // 解析接收和发送的数据包数量
            line = strstr(buffer, ifname);
            sscanf(line, "%*s %lu %*d %*d %*d %*d %*d %*d %*d %lu", rx_bytes, tx_bytes);
            printf("Interface: %s\n", ifname);

            break;
        }
    }

    // 关闭文件
    fclose(fp);
    return TRUE;
}

14.获取无线是否连接(连接个数)
int wlan_get_count(const char *ifname)
{
    char cmd[256];
    FILE *fp;
    int count = 0;
    char buffer[256];

    // 创建获取无线设备列表的命令字符串
    snprintf(cmd, sizeof(cmd), "iw dev %s station dump | grep Station | wc -l", ifname);

    // 打开命令用于读取
    if ((fp = popen(cmd, "r")) == NULL)
    {

        printf("Error opening pipe!\n");
        return -1;
    }

    // 从管道中读取输出
    if (fgets(buffer, sizeof(buffer), fp) != NULL)
    {
        // 将输出字符串转换为整数
        count = atoi(buffer);
    }

    // 关闭管道
    if (pclose(fp))
    {
        printf("Command not found or exited with error status\n");
        return -1;
    }

    return count;
}
15.重新配置生效无线网络参数,当修改完无线网络参数后,可以调用此函数重启端口
int wlan_restart(void)
{
    // system("iwconfig wlan0 key s:your_key");
    // system("iwconfig wlan0 essid your_essid");
    // wlan0 ifname 根据自己的端口来替换
    if (netif_is_up("wlan0") == TRUE)
    {
        // 如果开启就关闭无线接口
        int result_down = system("ifconfig wlan0 down");
        if (result_down == -1)
        {
            perror("system");
            return FALSE;
        }
    }
    // 重新启动无线接口
    int result_up = system("ifconfig wlan0 up");
    if (result_up == -1)
    {
        perror("system");
        return FALSE;
    }
    return TRUE;
}
16.重新配置网络参数,包括Ethernet、WiFi、Bluetooth、LTE等 当修改完网络参数后,可以调用此函数重启此服务
int net_restart(void)
{
    int result = system("systemctl restart NetworkManager");
    if (result == -1)
    {
        perror("system");
        return FALSE;
    }
    return TRUE;
}
17.获取无线连接信号强度(dBm)
int wlan_get_signal(const char *ifname)
{
    char cmd[1024];
    FILE *fp;
    char line[256];
    int signal_strength = 0;

    // 构建iwconfig命令,替换你的无线接口名(比如wlan0)
    snprintf(cmd, sizeof(cmd), "iwconfig %s", ifname);

    // 执行命令
    fp = popen(cmd, "r");
    if (fp == NULL)
    {
        perror("popen");
        return EXIT_FAILURE;
    }

    // 读取命令返回的内容
    while (fgets(line, sizeof(line), fp) != NULL)
    {
        char *ptr;
        // 在返回的内容中查找"Signal level"字段
        if ((ptr = strstr(line, "Signal level")) != NULL)
        {
            // 解析信号强度
            sscanf(ptr, "Signal level=%d dBm", &signal_strength);
            break;
        }
    }

    // 关闭fp指针
    pclose(fp);
    return signal_strength;
}

二、整体实现代码

2.1 宏定义 HRDSP.h文件
#ifndef HRDSP_H
#define HRDSP_H

#ifdef __cplusplus
extern "C"
{
#endif

#include <stdint.h>
#include <netinet/in.h>

    typedef unsigned char MacAddr_t[6]; // MacAddr_t[ETH_ALEN]
    typedef enum
    {
        FALSE,
        TRUE
    } bool_t;

    // 1. 检测指定网络接口是否存在 -----------------------------------
    bool_t netif_is_exist(const char *ifname);
    // 2. 检测指定网络接口链路是否连接 -----------------------------------
    bool_t netif_is_link(const char *ifname);
    // 3. 检测指定网络接口是否开启 -----------------------------------
    bool_t netif_is_up(const char *ifname);
    // 4. 开启或关闭网络接口 0:关闭 、1:开启 -----------------------------------
    bool_t netif_up(const char *ifname, bool_t up);
    // 5.获取指定网络接口MAC地址 -----------------------------------
    bool_t netif_get_mac(const char *ifname, MacAddr_t mac);
    // 6. 设置指定网络接口MAC地址 -----------------------------------
    bool_t netif_set_mac(const char *ifname, MacAddr_t mac);
    // 7. 获取指定网络接口IP地址 -----------------------------------
    bool_t netif_get_ip(const char *ifname, in_addr_t *ip);
    // 8. 设置指定网络接口IP地址 -----------------------------------
    bool_t netif_set_ip(const char *ifname, const char *in_addr_tip);
    // 9.获取指定网络接口子网掩码 ---------------------------------
    bool_t netif_get_mask(const char *ifname, in_addr_t *ip);
    // 10. 设置指定网络接口子网掩码 -----------------------------------
    bool_t netif_set_mask(const char *ifname, in_addr_t mask);
    // 11.设置指定网络接口发送队列长度 ----------------------------
    bool_t netif_set_txqueue(const char *ifname, uint32_t len);
    //  12. 设置指定网络接口最大包负载MTU -----------------------------------
    bool_t netif_set_mtu(const char *ifname, uint32_t mtu);
    // 13.获取收发包的数量 -----------------------------------
    bool_t netif_get_bytes(char *ifname, unsigned long long *tx_bytes, unsigned long long *rx_bytes);
    // 14.获取无线是否连接(连接个数) -----------------------------------
   int wlan_get_count(const char *ifname);
    // 15.重新配置生效无线网络参数,当修改完无线网络参数后,可以调用此函数 ---------------
    int wlan_restart(void);
    // 16.重新配置网络参数,包括Ethernet、WiFi、Bluetooth、LTE等 当修改完网络参数后,可以调用此函数 -----------------------------------
    int net_restart(void);
    // 17.获取无线连接信号强度(dBm) -----------------------------------
    int wlan_get_signal(const char *ifname);
#ifdef __cplusplus
} // extern "C"
#endif

#endif
2.2 核心实现代码 (部分犯法需要sudo甚至是root权限,我用的板卡是有sudo权限的)
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <net/if.h>
#include <unistd.h>
#include <stdbool.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <netinet/ip.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <net/if_arp.h>
#include <linux/nl80211.h>
#include <linux/wireless.h>
#include <netinet/if_ether.h>
#include "HRDSP.h"

static struct ifreq ifr;
static int fd;

/* 创建Socket */
static int if_socket()
{
    int sock = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock < 0)
    {
        perror("socket");
        return FALSE;
    }
    return sock;
}

/*1. 检测指定网络接口是否存在 J*/
bool_t netif_is_exist(const char *ifname)
{
    // 创建socket以进行ioctl调用
    fd = if_socket();

    strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1);
    ifr.ifr_name[IFNAMSIZ - 1] = '\0';

    if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0)
    {
        perror("ioctl");
        close(fd);
        return FALSE;
    }
    else
        return TRUE;
}

/*2. 检测指定网络接口链路是否连接 X*/
bool_t netif_is_link(const char *ifname)
{

    // 创建socket以进行ioctl调用
    fd = if_socket();

    // 清零ifr结构体并设置要检查的接口名称
    memset(&ifr, 0, sizeof(ifr));
    strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));

    // 调用ioctl获取网络接口标志
    if (ioctl(fd, SIOCGIFFLAGS, &ifr) == -1)
    {
        perror("ioctl");
        close(fd);
        exit(1);
    }

    // 检查IFF_RUNNING标志,确定链路状态
    if (ifr.ifr_flags & IFF_RUNNING)
    {
        return TRUE;
    }
    else
    {
        return FALSE;
    }

    // 关闭socket
    close(fd);
}

/*3. 检测指定网络接口是否开启 J*/
bool_t netif_is_up(const char *ifname)
{
    // 创建socket以进行ioctl调用
    fd = if_socket();

    strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1);

    if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0)
    {
        perror("ioctl");
        close(fd);
        return FALSE;
    }

    close(fd);
    if (ifr.ifr_flags & IFF_UP)
    {
        return TRUE;
    }
    else
    {
        return FALSE;
    }
}

/*4. 开启或关闭网络接口 0:关闭 、1:开启 X*/
bool_t netif_up(const char *ifname, bool_t up)
{
    // 创建socket以进行ioctl操作
    fd = if_socket();

    // 清零ifr结构体,并设置需要操作的网络接口名
    memset(&ifr, 0, sizeof(ifr));
    strncpy(ifr.ifr_name, ifname, IFNAMSIZ);

    // 获取当前网络接口的配置
    if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0)
    {
        perror("SIOCGIFFLAGS");
        close(fd);
        return FALSE;
    }

    if (netif_is_up(ifname) == up)
    {
        // 当前状态与需求状态一致
        return TRUE;
    }
    else
    {
        // 根据enable的值设置IFF_UP标志位来打开或关闭网络接口
        if (up == TRUE)
        {
            ifr.ifr_flags |= IFF_UP;
        }
        else
        {
            ifr.ifr_flags &= ~IFF_UP;
        }
        // 设置网络接口的状态
        if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0)
        {
            perror("SIOCSIFFLAGS");
            close(fd);
            return FALSE;
        }
    }

    close(fd);
    // 检查开启转态并返回
    return netif_is_up(ifname) == up;
}

// 5.获取指定网络接口MAC地址-----------------------------------
bool_t netif_get_mac(const char *ifname, MacAddr_t mac)
{
    // 创建socket以进行ioctl调用
    fd = if_socket();

    ifr.ifr_addr.sa_family = AF_INET;
    strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1);

    if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0)
    {
        perror("ioctl");
        close(fd);
        return FALSE;
    }

    close(fd);
    memcpy(mac, ifr.ifr_hwaddr.sa_data, 6);

    return TRUE;
}

/*6. 设置指定网络接口MAC地址 X*/
bool_t netif_set_mac(const char *ifname, MacAddr_t mac)
{
    // 创建socket以进行ioctl调用
    fd = if_socket();

    // 指定要修改的网络接口
    strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1);

    // 准备好新的MAC地址
    ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
    memcpy(ifr.ifr_hwaddr.sa_data, mac, ETH_ALEN);

    // 调用ioctl设置MAC地址
    if (ioctl(fd, SIOCSIFHWADDR, &ifr) < 0)
    {
        perror("ioctl");
        close(fd);
        return FALSE;
    }

    close(fd);
    return TRUE;
}

/*7. 获取指定网络接口IP地址 J*/
bool_t netif_get_ip(const char *ifname, in_addr_t *ip)
{
    // 创建socket以进行ioctl调用
    fd = if_socket();

    ifr.ifr_addr.sa_family = AF_INET;
    strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1);

    if (ioctl(fd, SIOCGIFADDR, &ifr) < 0)
    {
        perror("ioctl");
        close(fd);
        return FALSE;
    }
    close(fd);

    struct sockaddr_in *addr = (struct sockaddr_in *)&ifr.ifr_addr;
    *ip = addr->sin_addr.s_addr;

    return TRUE;
}

/* 8. 设置指定网络接口IP地址 */
bool_t netif_set_ip(const char *ifname, const char *in_addr_tip)
{

    // 构建设置IP地址的命令字符串
    char command[100];
    snprintf(command, sizeof(command), "ifconfig %s %s", ifname, in_addr_tip);

    // 执行命令,设置IP地址
    int ret = system(command);

    if (ret == -1)
    {
        printf("Failed to set IP address.\n");
        return FALSE;
    }
    else
    {
        printf("IP address set successfully.\n");
        return TRUE;
    }
}

// 9.获取指定网络接口子网掩码 ---------------------------------
bool_t netif_get_mask(const char *ifname, in_addr_t *ip)
{
    // 创建socket以进行ioctl调用
    fd = if_socket();

    strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
    if (ioctl(fd, SIOCGIFNETMASK, &ifr) < 0)
    {
        perror("ioctl");
        close(fd);
        return FALSE;
    }

    close(fd);

    struct sockaddr_in *addr = (struct sockaddr_in *)&ifr.ifr_netmask;
    *ip = addr->sin_addr.s_addr;

    return TRUE;
}

/* 10. 设置指定网络接口子网掩码 */
bool_t netif_set_mask(const char *ifname, in_addr_t mask)
{
    struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr;
    struct sockaddr_in *addr;

    // 创建socket以进行ioctl调用
    fd = if_socket();

    // 清空ifr结构体并设置网络接口名称,例如 "eth0"
    memset(&ifr, 0, sizeof(ifr));
    strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name) - 1);

    // 获取当前的子网掩码
    if (ioctl(fd, SIOCGIFNETMASK, &ifr) == -1)
    {
        perror("ioctl");
        close(fd);
        exit(EXIT_FAILURE);
    }
    // 准备好 sockaddr_in 结构体设置子网掩码
    addr = (struct sockaddr_in *)&ifr.ifr_addr;
    addr->sin_family = AF_INET;
    addr->sin_addr.s_addr = mask;

    // 使用SIOCSIFNETMASK ioctl命令设置子网掩码
    if (ioctl(fd, SIOCSIFNETMASK, &ifr) == -1)
    {
        perror("ioctl SIOCSIFNETMASK failed");
        close(fd);
        return FALSE;
    }

    // 操作成功
    close(fd);
    return TRUE;
}

// 11.设置指定网络接口发送队列长度 ---------------------X-------
bool_t netif_set_txqueue(const char *ifname, uint32_t len)
{

    // 构建设置IP地址的命令字符串
    char command[100];
    snprintf(command, sizeof(command), "ifconfig %s txqueuelen %d", ifname, len);

    // 执行命令,设置IP地址
    int ret = system(command);

    if (ret == -1)
    {
        printf("Failed to set txqueuelen.\n");
        return FALSE;
    }
    else
    {
        printf("TxqueueLen set successfully.\n");
        return TRUE;
    }
}

/* 12. 设置指定网络接口最大包负载MTU X */
bool_t netif_set_mtu(const char *ifname, uint32_t mtu)
{

    // 为了设置MTU先关不端口
    if (netif_up(ifname, 0) != TRUE)
    {
        return FALSE;
    }

    // 创建socket以进行ioctl调用
    fd = if_socket();

    // 清零结构体
    memset(&ifr, 0, sizeof(ifr));
    // 指定网络接口名称
    strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1);

    // 获取当前接口参数
    if (ioctl(fd, SIOCGIFMTU, &ifr) < 0)
    {
        perror("0 ioctl SIOCGIFMTU");
        close(fd);
        return FALSE;
    }

    printf("Current MTU of %s is %d chenge %d\n", ifname, ifr.ifr_mtu, mtu);

    if (ifr.ifr_mtu == mtu)
    {
        printf("Current MTU of %s is %d == %d\n", ifname, ifr.ifr_mtu, mtu);

        return TRUE;
    }

    // 设置新的MTU
    ifr.ifr_mtu = mtu;
    if (ioctl(fd, SIOCSIFMTU, &ifr) != 0)
    {
        perror("ioctl");

        return FALSE;
    }

    // 再次获取新设置的MTU
    if (ioctl(fd, SIOCGIFMTU, &ifr) < 0)
    {
        perror("ioctl");
        close(fd);
        return FALSE;
    }

    printf("New MTU of %s is %d\n", ifname, ifr.ifr_mtu);

    // 关闭socket
    close(fd);
    // 设置MTU后再重启端口
    netif_up(ifname, 1);
    return TRUE;
}

// 13.获取收发包的数量 ------------------------------X-----
bool_t netif_get_bytes(char *ifname, unsigned long long *tx_bytes, unsigned long long *rx_bytes)
{
    FILE *fp;
    char buffer[1024];
    char *line;

    // 打开/proc/net/dev文件
    fp = fopen("/proc/net/dev", "r");
    if (fp == NULL)
    {
        perror("Error opening file");
        return FALSE;
    }

    // 读取文件,直到找到相应的网络接口
    while (fgets(buffer, sizeof(buffer), fp))
    {
        if (strstr(buffer, ifname))
        {
            // 这里假设行的格式是以下这种类型的:
            // eth0: 123455  162100    ...(其他统计数据)
            // 您可能需要根据实际情况调整 sscanf 的格式字符串来适配

            // 解析接收和发送的数据包数量
            line = strstr(buffer, ifname);
            sscanf(line, "%*s %lu %*d %*d %*d %*d %*d %*d %*d %lu", rx_bytes, tx_bytes);
            printf("Interface: %s\n", ifname);

            break;
        }
    }

    // 关闭文件
    fclose(fp);
    return TRUE;
}

// 14.获取无线是否连接(连接个数) -----------------------------------
int wlan_get_count(const char *ifname)
{
    char cmd[256];
    FILE *fp;
    int count = 0;
    char buffer[256];

    // 创建获取无线设备列表的命令字符串
    snprintf(cmd, sizeof(cmd), "iw dev %s station dump | grep Station | wc -l", ifname);

    // 打开命令用于读取
    if ((fp = popen(cmd, "r")) == NULL)
    {

        printf("Error opening pipe!\n");
        return -1;
    }

    // 从管道中读取输出
    if (fgets(buffer, sizeof(buffer), fp) != NULL)
    {
        // 将输出字符串转换为整数
        count = atoi(buffer);
    }

    // 关闭管道
    if (pclose(fp))
    {
        printf("Command not found or exited with error status\n");
        return -1;
    }

    return count;
}

// 15.重新配置生效无线网络参数,当修改完无线网络参数后,可以调用此函数 ---------------
int wlan_restart(void)
{
    // system("iwconfig wlan0 key s:your_key");
    // system("iwconfig wlan0 essid your_essid");
    if (netif_is_up("wlan0") == TRUE)
    {
        // 如果开启就关闭无线接口
        int result_down = system("ifconfig wlan0 down");
        if (result_down == -1)
        {
            perror("system");
            return FALSE;
        }
    }
    // 重新启动无线接口
    int result_up = system("ifconfig wlan0 up");
    if (result_up == -1)
    {
        perror("system");
        return FALSE;
    }
    return TRUE;
}

// 16.重新配置网络参数,包括Ethernet、WiFi、Bluetooth、LTE等 当修改完网络参数后,可以调用此函数 -----------------------------------
int net_restart(void)
{
    int result = system("systemctl restart NetworkManager");
    if (result == -1)
    {
        perror("system");
        return FALSE;
    }
    return TRUE;
}

// 17.获取无线连接信号强度(dBm) -----------------------------------
int wlan_get_signal(const char *ifname)
{
    char cmd[1024];
    FILE *fp;
    char line[256];
    int signal_strength = 0;

    // 构建iwconfig命令,替换你的无线接口名(比如wlan0)
    snprintf(cmd, sizeof(cmd), "iwconfig %s", ifname);

    // 执行命令
    fp = popen(cmd, "r");
    if (fp == NULL)
    {
        perror("popen");
        return EXIT_FAILURE;
    }

    // 读取命令返回的内容
    while (fgets(line, sizeof(line), fp) != NULL)
    {
        char *ptr;
        // 在返回的内容中查找"Signal level"字段
        if ((ptr = strstr(line, "Signal level")) != NULL)
        {
            // 解析信号强度
            sscanf(ptr, "Signal level=%d dBm", &signal_strength);
            break;
        }
    }

    // 关闭fp指针
    pclose(fp);
    return signal_strength;
}

2.3 测试代码 (简答写了一个将就着用吧>-<)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <net/if.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <linux/wireless.h>
#include "HRDSP.h"

typedef unsigned char MacAddr_t[6];
#define MAX_IP_LEN 15

int main(int argc, char *argv[])
{

    typedef enum
    {
        FALSE,
        TRUE
    } bool_t;

    char *ifname; // ens33  eth0   lo
    printf("请设置要测试的端口(注:每次启动仅设置一次):\n");
    char port_name[50];
    scanf("%s", &port_name);
    ifname = port_name;
    printf("port_name=%s\n", ifname);
    printf("进入测试\n");

    MacAddr_t mac;
    in_addr_t ip, mask;
    unsigned long long tx_bytes, rx_bytes;

    int is_break = 0;
    int nunmber;
    char command[256];
    int isup;
    char ipAddress[MAX_IP_LEN + 1]; // 最大IP地址长度为15,例如 255.255.255.255

    unsigned char macAddr[6];
    char mac_str[18];
    struct ifreq ifr;
    int s;

    char subnet_mask[16], in_mtu[255]; // 用于存储用户输入的子网掩码字符串

    // 无线循环
    while (is_break == 0)
    {
        printf("请输入要测试的指令编号:\n");
        scanf("%d", &nunmber);

        switch (nunmber)
        {
        case 1:
            //-------------------1. 检测指定网络接口是否存在--------------------------------------
            printf("netif_is_exist Interface: %s\n", netif_is_exist(ifname) ? "exists" : "does not exist");
            break;
        case 2:
            //-------------------2. 检测指定网络接口链路是否连接--------------------------------------
            printf("Link status: %s\n", netif_is_link(ifname) ? "Connected" : "Disconnected");
            break;
        case 3:
            //------------------3. 检测指定网络接口是否开启---------------------------------------
            printf("netif_is_up Interface: %s\n", netif_is_up(ifname) ? "is up" : "is not up");
            break;
        case 4:
            //--------------------4. 开启或关闭网络接口 0:关闭 、1:开启------------------os 需要判断关闭返回值-------------------
            printf("开启或关闭网络接口 0:关闭-1:开启:\n");
            scanf("%d", &isup);
            printf("Interface up_dow: %s\n", netif_up(ifname, isup) ? "Success" : "Failed");
            break;
        case 5:
            //-----------------------5.获取指定网络接口MAC地址----------------------------------
            if (netif_get_mac(ifname, mac))
            {
                printf("5.netif_get_mac MAC address of %s: %02X:%02X:%02X:%02X:%02X:%02X\n",
                       ifname, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
            }
            else
            {
                printf("Failed to get MAC address of %s\n", ifname);
            }
            break;
        case 6:
            //--------------------6. 设置指定网络接口MAC地址-------------------------------------
            // Set MAC address
            // 获取用户输入的MAC地址
            printf("输入设置指定网络接口MAC地址 (e.g. 01:23:45:67:89:ab):\n");
            scanf("%17s", &mac_str);
            printf("输入mac_str: %s\n", mac_str);
            if (sscanf(mac_str, "%hhX:%hhX:%hhX:%hhX:%hhX:%hhX", &macAddr[0],
                       &macAddr[1], &macAddr[2], &macAddr[3], &macAddr[4], &macAddr[5]) != 6)
            {
                fprintf(stderr, "Invalid MAC address format\n");
                return FALSE;
            }

            // MacAddr_t mac = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55};
            printf("Set MAC address: %s\n", netif_set_mac(ifname, macAddr) ? "Success" : "Failed");
            break;
        case 7:
            //---------------------------7. 获取指定网络接口IP地址------------------------------
            if (netif_get_ip(ifname, &ip))
            {
                struct in_addr addr;
                addr.s_addr = ip;
                printf("IP address of %s: %s\n", ifname, inet_ntoa(addr));
            }
            else
            {
                printf("Failed to get IP address of %s\n", ifname);
            }
            break;
        case 8:
            //----------------8. 设置指定网络接口IP地址-----------------------------------------
            // Set IP address
            printf("输入设置指定网络接口IP地址-169.254.127.228-:\n");
            scanf("%15s", &ipAddress);
            printf("Set IP address: %s\n", netif_set_ip(ifname, ipAddress) ? "Success" : "Failed");
            break;
        case 9:
            //----------------9.获取指定网络接口子网掩码-----------------------------------------
            if (netif_get_mask(ifname, &mask))
            {
                struct in_addr addr;
                addr.s_addr = mask;
                printf("Subnet mask of %s: %s\n", ifname, inet_ntoa(addr));
            }
            else
            {
                printf("Failed to get subnet mask of %s\n", ifname);
            }
            break;
        case 10:
            //-----------------10. 设置指定网络接口子网掩码----------------------------------------
            // Set subnet mask
            printf("输入设置指定网络接口子网掩码-255.255.0.0-:\n");
            scanf("%15s", &subnet_mask);
            in_addr_t subnetMask = inet_addr(subnet_mask);
            printf("Set subnet mask: %s\n", netif_set_mask(ifname, subnetMask) ? "Success" : "Failed");
            break;
        case 11:
            //------------------11.设置指定网络接口发送队列长度---------------------------------------
            printf("输入设置指定网络接口发送队列长度100:\n");
            uint32_t *len;
            scanf("%d", &len);
            if (netif_set_txqueue(ifname, len))
            {
                printf("Successfully set tx queue length\n");
            }
            else
            {
                printf("Failed to set tx queue length\n");
            }
            break;
        case 12:
            //-----------------12. 设置指定网络接口最大包负载MTU----------------------------------------
            // Set MTU
            printf("输入设置指定网络接口最大包负载MTU=1500:\n");
            scanf("%9s", &in_mtu);
            uint32_t mtu = atoi(in_mtu);
            printf("Set MTU: %s\n", netif_set_mtu(ifname, mtu) ? "Success" : "Failed");
            break;
        case 13:
            //------------------------13.获取收发包的数量---------------------------------
            if (netif_get_bytes(ifname, &tx_bytes, &rx_bytes))
            {
                printf("TX bytes of %s: %llu\n", ifname, tx_bytes);
                printf("RX bytes of %s: %llu\n", ifname, rx_bytes);
            }
            else
            {
                printf("Failed to get TX/RX bytes of %s\n", ifname);
            }
            break;
        case 14:
            //------------------------14.获取无线是否连接(连接个数)---------------------------------
            {
                int count = wlan_get_count(ifname);
                if (count >= 0)
                {
                    printf("Number of wireless connections on %s: %d\n", ifname, count);
                }
                else
                {
                    printf("Could not get the wireless connection count.\n");
                }
            }
            break;
        case 15:
            //------------------------15.重新配置生效无线网络参数,当修改完无线网络参数后,可以调用此函数---------------------------------
            printf(wlan_restart() == 1 ? "Wireless network restarted successfully.\n" : "Failed to restart wireless network.\n");
            break;
        case 16:
            //------------------------16.重新配置网络参数,包括Ethernet、WiFi、Bluetooth、LTE等 当修改完网络参数后,可以调用此函数---------------------------------
            printf(net_restart() == 1 ? "Wireless network restarted successfully.\n" : "Failed to restart wireless network.\n");
            break;
        case 17:
            //------------------------17.获取无线连接信号强度(dBm)---------------------------------
            {
                int signal = wlan_get_signal(ifname);
                if (signal != 0)
                {
                    printf("Current signal strength of interface '%s': %d dBm\n", ifname, signal);
                }
                else
                {
                    printf("Could not get signal strength for the interface '%s'\n", ifname);
                }
            }
            break;
        default:
            // 结束循环
            goto end_of_while;
            break;
        }
    }

end_of_while:
    printf("结束测试:\n");

    return 0;
}
上一篇 下一篇

猜你喜欢

热点阅读