Linux中实现基于C代码的IP地址配置

    之前根据项目要求,需要通过web对linux终端配置IP地址,一种是通过修改脚本文件方式,另一种是通过编程方式。由于采用的嵌入式web服务器中需要实现C代码读取IP地址,所有采用第二中方式。参考了各大神的总结,现将我测试的代码作以记录。


#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <error.h>
#include <net/route.h>
#include <unistd.h>


#define MAX_INTERFACE   (16) 


/**
  * @brief  模仿ifconfig打印所有网卡信息.
  * @param  None.
  * @retval None.
  * @notes  None.
  */  
int GetIfAllAddr(void)
{
    int fd;
    struct ifreq  buf[MAX_INTERFACE];
    struct ifconf ifc;
    int ret = 0;
    int if_num = 0;
    
    fd = socket(AF_INET, SOCK_DGRAM, 0);
    if(fd < 0)
    {
        perror(" socket error");
        return fd;
    }

    ifc.ifc_len = sizeof(buf);
    ifc.ifc_buf = (caddr_t)buf;

    ret = ioctl(fd, SIOCGIFCONF, (char *)&ifc);
    if(ret < 0)
    {
        printf("get if config info failed");
        
        goto error_exit;
    }
    
    /* 网口总数 ifc.ifc_len 应该是一个输入参数 */
    if_num = ifc.ifc_len/sizeof(struct ifreq);
    printf("Interface num is %d\n", if_num);
    
    while(if_num--)
    {
        printf("【%s】: \n", buf[if_num].ifr_name);
        
        /* 获取第n个网卡信息 */
        ret = ioctl(fd, SIOCGIFFLAGS, (char *)&buf[if_num]);
        if(ret < 0)
        {
            continue;
        }
        
        /* 获取网口状态 */
        //get_net_status(buf[if_num].ifr_flags);
        
        /* 获取当前网卡的IP地址 */
        ret = ioctl(fd, SIOCGIFADDR, (char *)&buf[if_num]);
        if(ret < 0)
        {
            continue;
        }
        printf("  IP: %s\n", inet_ntoa(((struct sockaddr_in *)(&buf[if_num].ifr_addr))->sin_addr));
        
        /* 获取当前网卡的MAC */
        ret = ioctl(fd, SIOCGIFHWADDR, (char *)&buf[if_num]);
        if(ret < 0)
        {
            continue;
        }
        printf("  MAC: %02x:%02x:%02x:%02x:%02x:%02x\n\n",  
                (uint8_t)buf[if_num].ifr_hwaddr.sa_data[0],  
                (uint8_t)buf[if_num].ifr_hwaddr.sa_data[1],  
                (uint8_t)buf[if_num].ifr_hwaddr.sa_data[2],  
                (uint8_t)buf[if_num].ifr_hwaddr.sa_data[3],  
                (uint8_t)buf[if_num].ifr_hwaddr.sa_data[4],  
                (uint8_t)buf[if_num].ifr_hwaddr.sa_data[5]  
             );        
    }

error_exit:    
    close(fd);
    return ret;
}

/**
  * @brief  模仿ifconfig打印所有网卡信息.
  * @param  *ethName  网卡名字符
  * @retval None.
  * @notes  None.
  */  
int GetIfAddr(const char *ethName)
{
    int fd;
    int ret = 0;
    struct ifreq ifr;
    
    fd = socket(AF_INET, SOCK_DGRAM, 0);
    if(fd < 0)
    {
        perror(" socket error");
        return fd;
    }

    memset(&ifr, 0, sizeof(ifr));
    strcpy(ifr.ifr_name, ethName);
    
    /* 获取第n个网卡信息 */
    ret = ioctl(fd, SIOCGIFFLAGS, (char *)&ifr);
    if(ret < 0)
    {
        perror("ioctl_SIOCGIFFLAGS error");
    }

    printf("%s", ifr.ifr_name);
    
    /* 获取当前网卡的MAC */
    ret = ioctl(fd, SIOCGIFHWADDR, (char *)&ifr);
    if(ret < 0)
    {
        perror("ioctl_SIOCGIFHWADDR error");
    }
    printf("      HWaddr: %02x:%02x:%02x:%02x:%02x:%02x\n",  
             (uint8_t)ifr.ifr_hwaddr.sa_data[0],  
             (uint8_t)ifr.ifr_hwaddr.sa_data[1],  
             (uint8_t)ifr.ifr_hwaddr.sa_data[2],  
             (uint8_t)ifr.ifr_hwaddr.sa_data[3],  
             (uint8_t)ifr.ifr_hwaddr.sa_data[4],  
             (uint8_t)ifr.ifr_hwaddr.sa_data[5]  
           );    

    /* 获取当前网卡的IP地址 */
    ret = ioctl(fd, SIOCGIFADDR, (char *)&ifr);
    if(ret < 0)
    {
        perror("ioctl_SIOCGIFADDR error");
    }
    printf("          inet addr:%s    ", inet_ntoa(((struct sockaddr_in *)(&ifr.ifr_addr))->sin_addr));
    
    /* 获取当前网卡的广播地址 */
    ret = ioctl(fd, SIOCGIFBRDADDR, (char *)&ifr);
    if(ret < 0)
    {
        perror("ioctl_SIOCGIFBRDADDR error");
    }
    printf("Bcast:%s    ", inet_ntoa(((struct sockaddr_in *)(&ifr.ifr_addr))->sin_addr));
    
    /* 获取当前网卡的子网掩码 */
    ret = ioctl(fd, SIOCGIFNETMASK, (char *)&ifr);
    if(ret < 0)
    {
        perror("ioctl_SIOCGIFNETMASK error");
    }
    printf("Mask:%s\n", inet_ntoa(((struct sockaddr_in *)(&ifr.ifr_addr))->sin_addr));    
    
    ret = ifr.ifr_flags;
    close(fd);
    return ret;           
}
  
/**
  * @brief  根据网口名称设置IP地址.
  * @param  *ethName  网卡名字符
  * @retval None.
  * @notes  None.
  */  
int SetIfAddr(const char *ethName, char *ipAddr, char *mask, char *gateway)
{
    int fd;
    int ret = 0;
    struct ifreq ifr;
    struct sockaddr_in *sin;
    struct rtentry rt;
    
    fd = socket(AF_INET, SOCK_DGRAM, 0);
    if(fd < 0)
    {
        perror(" socket error");
        return fd;
    }
    
    memset(&ifr, 0, sizeof(ifr));
    strcpy(ifr.ifr_name, ethName);
    sin = (struct sockaddr_in *)&ifr.ifr_addr;
    sin->sin_family = AF_INET;
    
    /* IP地址设置 */
    ret = inet_aton(ipAddr, &(sin->sin_addr));
    if(ret < 0)
    {
        perror("inet_aton  error");
        goto error_exit;
    }
    
    ret = ioctl(fd, SIOCSIFADDR, &ifr);
    if(ret < 0)
    {
        perror("ioctl SIOCSIFADDR error");
        goto error_exit;
    }
    
    /* 子网掩码设置 */
    ret = inet_aton(mask, &(sin->sin_addr));
    if(ret < 0)
    {
        perror("inet_aton  error");
        goto error_exit;        
    }
    
    ret = ioctl(fd, SIOCSIFNETMASK, &ifr);
    if(ret < 0)
    {
        perror("ioctl SIOCSIFNETMASK error");
        goto error_exit;        
    }
    
    /* 网关 */
    memset(&rt, 0, sizeof(struct rtentry));
    memset(sin, 0, sizeof(struct sockaddr_in));
    sin->sin_family = AF_INET;
    sin->sin_port = 0;
    ret = inet_aton(gateway, &(sin->sin_addr));
    if(ret < 0)
    {
        perror("inet_aton gateway error");        
    }
    memcpy(&rt.rt_gateway, sin, sizeof(struct sockaddr_in));
    ((struct sockaddr_in *)&rt.rt_dst)->sin_family = AF_INET;
    ((struct sockaddr_in *)&rt.rt_genmask)->sin_family = AF_INET;
    rt.rt_flags = RTF_GATEWAY;
    
    /* 设置网关,如果所设置的网关与现有网关一样,会报File exists */
    ret = ioctl(fd, SIOCADDRT, &rt);
    if(ret < 0)
    {
        perror("ioctl(SIOCADDRT) error in set_default_route\n");
        goto error_exit;        
    }

error_exit:
    close(fd);
    return ret;
}  
  
  
int main(int argc, char *argv[])
{
    char *ip = "192.168.10.56";
    char *mask = "255.255.255.0";
    char *gateway = "192.168.10.1";
    
    if(SetIfAddr("eth0", ip, mask, gateway) < 0)
    {
        printf("SetIfAddr fail !\n");
    }
    
    GetIfAddr("eth0");
    
    //GetIfAllAddr();
    
    return 0;

 

/* 
 ************************************************************************************
 * use methord:
 *   Interface request structure used for socket ioctl's. All interface ioctl's must        
 *   have parameter definitions which begin with ifr_name.          
 *   The remainder may be interface specific.
 *               
 *   struct ifreq           
 *   {
 *   # define IFHWADDRLEN 6           
 *   # define IFNAMSIZ IF_NAMESIZE
 *       union          
 *       {
 *          char ifrn_name[IFNAMSIZ]; //Interface name, e.g. "en0".    
 *       } ifr_ifrn;
 *
 *       union       
 *       {
 *           struct sockaddr ifru_addr;      
 *           struct sockaddr ifru_dstaddr; 
 *           struct sockaddr ifru_broadaddr;
 *           struct sockaddr ifru_netmask;     
 *           struct sockaddr ifru_hwaddr;
 *           short int ifru_flags;    
 *           int ifru_ivalue;
 *           int ifru_mtu;
 *           struct ifmap ifru_map;    
 *           char ifru_slave[IFNAMSIZ]; //Just fits the size
 *           char ifru_newname[IFNAMSIZ];   
 *           __caddr_t ifru_data;
 *       } ifr_ifru;
 *    };              
 *    # define ifr_name ifr_ifrn.ifrn_name           // interface name
 *    # define ifr_hwaddr ifr_ifru.ifru_hwaddr       // MAC address          
 *    # define ifr_addr ifr_ifru.ifru_addr           // address
 *    # define ifr_dstaddr ifr_ifru.ifru_dstaddr     // other end of p-p lnk
 *    # define ifr_broadaddr ifr_ifru.ifru_broadaddr // broadcast address          
 *    # define ifr_netmask ifr_ifru.ifru_netmask     // interface net mask
 *    # define ifr_flags ifr_ifru.ifru_flags         // flags          
 *    # define ifr_metric ifr_ifru.ifru_ivalue       // metric
 *    # define ifr_mtu ifr_ifru.ifru_mtu             // mtu
 *    # define ifr_map ifr_ifru.ifru_map             // device map          
 *    # define ifr_slave ifr_ifru.ifru_slave         // slave device
 *    # define ifr_data ifr_ifru.ifru_data           // for use by interface          
 *    # define ifr_ifindex ifr_ifru.ifru_ivalue      // interface index
 *    # define ifr_bandwidth ifr_ifru.ifru_ivalue    // link bandwidth
 *    # define ifr_qlen ifr_ifru.ifru_ivalue         // queue length          
 *    # define ifr_newname ifr_ifru.ifru_newname     // New name
 *    # define _IOT_ifreq _IOT(_IOTS(char),IFNAMSIZ,_IOTS(char),16,0,0)          
 *    # define _IOT_ifreq_short _IOT(_IOTS(char),IFNAMSIZ,_IOTS(short),1,0,0)
 *    # define _IOT_ifreq_int _IOT(_IOTS(char),IFNAMSIZ,_IOTS(int),1,0,0)
 *   
 *
 *   通过ioctl()函数调用请求参数表: 
 *  ---------------------------------------------------------------------------------------------------------
 *  |  类别  |   Request                |     说明                                              |   数据类型    |        
 *  ---------------------------------------------------------------------------------------------------------
 *  |   套    | SIOCATMARK        | 是否位于带外标记                             |     int       |
 *  |   接    | SIOCSPGRP          | 设置套接口的进程ID或进程组ID        |     int       |
 *  |   口    | SIOCGPGRP          | 获取套接口的进程ID或进程组ID        |     int       |
 *  ---------------------------------------------------------------------------------------------------------            
 *  |           | FIONBIN                 | 设置/清除非阻塞I/O标志                   |     int       |
 *  |   文    | FIOASYNC              | 设置/清除信号驱动异步I/O标志        |     int       |
 *  |           | FIONREAD             | 获取接收缓存区的字节数                  |     int       |           
 *  |   件    | FIOSETOWN           | 设置文件的进程ID或进程组ID          |     int       |
 *  |           | FIOGETOWN          | 获取文件的进程ID或进程组ID          |     int       |           
 *  ---------------------------------------------------------------------------------------------------------
 *  |           | SIOCGIFCONF         | 获取所有接口的清单                      | struct ifconf |
 *  |           | SIOCSIFADDR         | 设置接口地址                                 | struct ifreq  |             
 *  |           | SIOCGIFADDR         | 获取接口地址                                 | struct ifreq  |
 *  |           | SIOCSIFFLAGS        | 设置接口标志                                 | struct ifreq  |           
 *  |           | SIOCGIFFLAGS       | 获取接口标志                                 | struct ifreq  |
 *  |   接    | SIOCSIFDSTADDR   | 设置点到点地址                             | struct ifreq  |            
 *  |           | SIOCGIFDSTADDR  | 获取点到点地址                             | struct ifreq  |
 *  |   口    | SIOCGIFBRDADDR  | 获取广播地址                                | struct ifreq  |            
 *  |           | SIOCSIFBRDADDR  | 设置广播地址                                | struct ifreq  |
 *  |           | SIOCGIFNETMASK  | 获取子网掩码                                | struct ifreq  |
 *  |           | SIOCSIFNETMASK  | 设置子网掩码                                | struct ifreq  |
 *  |           | SIOCGIFMETRIC     | 获取接口的测度                             | struct ifreq  |
 *  |           | SIOCSIFMETRIC      | 设置接口的测度                             | struct ifreq  |
 *  |           | SIOCGIFMTU           | 获取接口的MTU                             | struct ifreq  |
 *  |           | SIOCxxx                   | (还有很多取决于系统实现)            | struct ifreq  |
 *  -----------------------------------------------------------------------------------------------------------
 *  |           | SIOCSARP              | 创建/修改ARP表项                        | struct arpreq |
 *  |  ARP  | SIOCGARP             | 获取ARP表项                                 | struct arpreq |
 *  |           | SIOCDARP             | 删除ARP表项                                 | struct arpreq |
 *  ----------------------------------------------------------------------------------------------------------
 *  |   路    | SIOCADDRT           | 增加路径                                          | struct rtentry|
 *  |   由    | SIOCDELRT           | 删除路径                                          | struct rtentry|
 *  ----------------------------------------------------------------------------------------------------------
 *  |   流    | I_xxx                       |
 *  --------------------------------------
 *              
 *
 ************************************************************************************
 */

  • 3
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 在 C 实现基于 Linux 的 socket 服务端需要用到以下函数: 1. `socket()`:创建套接字。 2. `bind()`:绑定套接字到一个地址和端口。 3. `listen()`:监听套接字。 4. `accept()`:接受连接请求。 5. `send()` 和 `recv()`:发送和接收数据。 这里是一个简单的服务端程序的示例,它创建了一个 TCP socket,并在端口 8080 上监听: ``` #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> int main() { int sockfd; struct sockaddr_in serv_addr; // 创建套接字 sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { perror("socket() failed"); exit(1); } // 填充服务器地址结构 memset(&serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); serv_addr.sin_port = htons(8080); // 绑定套接字到地址和端口 if (bind(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) { perror("bind() failed"); exit(1); } // 监听套接字 if (listen(sockfd, 5) < 0) { perror("listen() failed"); exit(1); } while (1) { int cli_sockfd; struct sockaddr_in cli_addr; socklen_t cli_addr_len; // 接受连接请求 cli_sockfd = accept(sockfd, (struct sockaddr*)&cli_addr, &cli_addr_len); if (cli_sockfd < 0) ### 回答2: 要实现一个基于Linux的Socket服务端,可以使用C语言进行编程。下面是一个简单的示例代码: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <netinet/in.h> #include <sys/socket.h> #define PORT 8888 #define BUFFER_SIZE 1024 int main() { int server_fd, client_fd; struct sockaddr_in server_address, client_address; socklen_t client_address_size = sizeof(client_address); char buffer[BUFFER_SIZE] = {0}; // 创建Socket if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) { perror("Socket创建失败"); exit(EXIT_FAILURE); } // 设置服务器地址 server_address.sin_family = AF_INET; server_address.sin_addr.s_addr = INADDR_ANY; server_address.sin_port = htons(PORT); // 将地址和Socket绑定 if (bind(server_fd, (struct sockaddr *)&server_address, sizeof(server_address)) < 0) { perror("绑定失败"); exit(EXIT_FAILURE); } // 监听连接 if (listen(server_fd, 5) < 0) { perror("监听失败"); exit(EXIT_FAILURE); } printf("等待客户端连接...\n"); // 接受客户端连接 if ((client_fd = accept(server_fd, (struct sockaddr *)&client_address, &client_address_size)) < 0) { perror("接受连接失败"); exit(EXIT_FAILURE); } printf("客户端已连接\n"); // 接收客户端发送的数据 int valread = read(client_fd, buffer, BUFFER_SIZE); printf("接收到的消息:%s\n", buffer); // 回复客户端 char *message = "收到消息!"; send(client_fd, message, strlen(message), 0); printf("回复消息:%s\n", message); // 关闭连接 close(client_fd); close(server_fd); return 0; } ``` 这段代码会创建一个使用TCP协议的Socket服务器,并监听8888端口。当客户端连接成功后,会接收客户端发送的消息,并回复一条消息。完成后会关闭连接。注意需要在命令行编译和运行该程序,可以使用以下命令进行编译: ``` gcc server.c -o server ``` 然后运行: ``` ./server ``` 这样就可以启动这个Socket服务器了。 ### 回答3: 要使用C语言实现一个基于Linux的socket服务端,首先需要引入相关头文件,如<sys/socket.h>和<netinet/in.h>。接着在主函数创建一个套接字,并配置服务端的IP地址和端口号。然后,绑定套接字到这个地址,并设置监听模式。 以下是一个简单的例子来实现上述功能: ```c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <sys/socket.h> #include <netinet/in.h> #define PORT 8080 #define BUFFER_SIZE 1024 int main() { int server_fd, new_socket, valread; struct sockaddr_in address; int opt = 1; int address_length = sizeof(address); char buffer[BUFFER_SIZE] = {0}; char *response = "Hello from server"; // 创建套接字 if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) { perror("socket failed"); exit(EXIT_FAILURE); } // 配置服务端地址和端口 address.sin_family = AF_INET; address.sin_addr.s_addr = INADDR_ANY; address.sin_port = htons(PORT); // 将套接字绑定到地址 if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) { perror("bind failed"); exit(EXIT_FAILURE); } // 设置监听模式 if (listen(server_fd, 3) < 0) { perror("listen failed"); exit(EXIT_FAILURE); } // 接受并处理客户端连接 if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t *)&address_length)) < 0) { perror("accept failed"); exit(EXIT_FAILURE); } // 读取客户端数据 valread = read(new_socket, buffer, BUFFER_SIZE); printf("Client: %s\n", buffer); // 发送响应给客户端 write(new_socket, response, strlen(response)); printf("Response sent\n"); return 0; } ``` 在这个例子,我们首先创建了一个套接字(server_fd),然后设置了服务端的IP地址和端口号。接下来,我们将套接字绑定到这个地址,并设置监听模式,允许最多3个客户端连接。最后,通过接受客户端连接,读取客户端发送的数据,并向客户端发送响应。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值