在代码中获取linux下的IP地址

1:目的

由于linux下的IP是可以修改的,代码中使用IP时也要跟着修改,才能使用。所以在代码中先获取设备的IP地址,再进行网络联接,就可以避免这种事的发生。

2:结构体

2.1 struct sockaddr_in

包含协议,端口, IP地址

#include<netinet/in.h>或#include <arpa/inet.h>

struct sockaddr_in {
short int sin_family;              /* Address family */
unsigned short int sin_port;       /* Port number */
struct in_addr sin_addr;            /* Internet address */
unsigned char sin_zero[8];         /* Same size as struct sockaddr */
};

还有一个相似的结构体struct sockaddr,其中sa_data把目标地址和端口信息混在一起了

struct sockaddr {  
     sa_family_t sin_family;    //地址族
    char sa_data[14];          //14字节,包含套接字中的目标地址和端口信息               
   };

两个结构体长度一样,都是16个字节,即占用的内存大小是一致的,因此可以互相转化。二者是并列结构,指向sockaddr_in结构的指针也可以指向sockaddr

2.1 struct ifreq


struct ifreq
{
#define IFHWADDRLEN 6
 union
 {
  char ifrn_name[IFNAMSIZ];  
 } ifr_ifrn;
 
 union 
 {
  struct sockaddr ifru_addr;
  struct sockaddr ifru_dstaddr;
  struct sockaddr ifru_broadaddr;
  struct sockaddr ifru_netmask;
  struct  sockaddr ifru_hwaddr;
  short ifru_flags;
  int ifru_ivalue;
  int ifru_mtu;
  struct  ifmap ifru_map;
  char ifru_slave[IFNAMSIZ]; 
  char ifru_newname[IFNAMSIZ];
  void __user * ifru_data;
  struct if_settings ifru_settings;
 } ifr_ifru;

freq结构用来配置ip地址,激活接口,配置MTU。在Linux系统中获取IP地址通常都是通过ifconfig命令来实现的,然而ifconfig命令实际是通过ioctl接口与内核通信,ifconfig命令首先打开一个socket,然后调用ioctl将request传递到内核,从而获取request请求数据。处理网络接口的许多程序沿用的初始步骤之一就是从内核获取配置在系统中的所有接口。

3:函数

3.1 转换函数

htons()作用是将端口号由主机字节序转换为网络字节序的整数值。(host to net)

inet_addr()作用是将一个IP字符串转化为一个网络字节序的整数值,用于sockaddr_in.sin_addr.s_addr。

inet_ntoa()作用是将一个sin_addr结构体输出成IP字符串(network to ascii)

3.2 ioctl

#include <sys/ioctl.h> 
int ioctl(int fd, int cmd, ...) ;

ioctl 是设备驱动程序中设备控制接口函数,一个字符设备驱动通常会实现设备打开、关闭、读、写等功能,在一些需要细分的情境下,如果需要扩展新的功能,通常以增设 ioctl() 命令的方式实现。

4:示例:获取指定名称的IP地址

/*******************************************************************************
  * @file          main.c
  * @verison       v1.0.0
  * @copyright     COPYRIGHT &copy; 2020 CSG
  * @author        ShiYanKai
  * @date:         2021-09-15
  * @brief
  * @bug
  * - 2021-09-15  SYK Created
*******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <net/if.h>

#define ETH_NAME  "wlp3s0"
char ip[32];

//获得本机IP地址
char* GetLocalAddress(char *ip)
{
        int sock;
        struct sockaddr_in sin;
        struct ifreq ifr;

        sock = socket(AF_INET, SOCK_DGRAM, 0); 
        if (sock == -1) 
        {   
                perror("socket");
                return NULL;
        }   

        strncpy(ifr.ifr_name, ETH_NAME, IFNAMSIZ);
        ifr.ifr_name[IFNAMSIZ - 1] = 0;

        if (ioctl(sock, SIOCGIFADDR, &ifr) < 0)
        {   
                perror("ioctl");
                return NULL;
        }   

    memcpy(&sin, &ifr.ifr_addr, sizeof(sin));
    memcpy(ip, inet_ntoa(sin.sin_addr), 16);
//  printf("%s\n", inet_ntoa(sin.sin_addr));
    return inet_ntoa(sin.sin_addr);
}
yankaishi@zx-dev:~/test/get_id_addr$ ./a.out 
ip = 172.18.1.202

5:示例2-获取所有网卡的IP

/*******************************************************************************
  * @file          main-all.c
  * @verison       v1.0.0
  * @copyright     COPYRIGHT &copy; 2020 CSG
  * @author        ShiYanKai
  * @date:         2021-09-15
  * @brief
  * @bug
  * - 2021-09-15  SYK Created
*******************************************************************************/
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <stdio.h>
#include <stdlib.h>

int main(int argc,char* argv[])
{
    int sockfd;
    struct ifconf ifconf;
    struct ifreq *ifreq;
    char buf[512];//缓冲区
    //初始化ifconf
    ifconf.ifc_len =512;
    ifconf.ifc_buf = buf;
    if ((sockfd =socket(AF_INET,SOCK_DGRAM,0))<0)
    {   
        perror("socket" );
        exit(1);
    }   
    ioctl(sockfd, SIOCGIFCONF, &ifconf); //获取所有接口信息

    //接下来一个一个的获取IP地址
    ifreq = (struct ifreq*)ifconf.ifc_buf;
    printf("ifconf.ifc_len:%d\n",ifconf.ifc_len);
    printf("sizeof (struct ifreq):%d\n",sizeof (struct ifreq));

    for (int i=(ifconf.ifc_len/sizeof (struct ifreq)); i>0; i--)
    {   
        if(ifreq->ifr_flags == AF_INET){ //for ipv4
            printf("name =[%s]\n" , ifreq->ifr_name);
            printf("local addr = [%s]\n" ,inet_ntoa(((struct sockaddr_in*)&(ifreq->ifr_addr))->sin_addr));
            ifreq++;
        }   
    }   
    return 0;
}
yankaishi@zx-dev:~/test/get_id_addr$ ./a.out 
ifconf.ifc_len:80
sizeof (struct ifreq):40
name =[lo]
local addr = [127.0.0.1]
name =[wlp3s0]
local addr = [172.18.1.202]

6:获取IP地址后建立服务端

/*******************************************************************************
  * @file          server.c
  * @verison       v1.0.0
  * @copyright     COPYRIGHT &copy; 2020 CSG
  * @author        ShiYanKai
  * @date:         2021-09-16
  * @brief
  * @bug
  * - 2021-09-16  SYK Created
*******************************************************************************/

#include <stdio.h>

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

#define ETH_NAME  "wlp3s0"

int sockfd;
short PORT = 8000;
typedef struct sockaddr SA; 
char dir_name[20] = "files";
char rcvmsg[256] = {0};
char ip[32] = {0};

int GetLocalAddress(struct sockaddr_in *sin)
{
    int sock;
    //struct sockaddr_in sin;
    struct ifreq ifr;

    sock = socket(AF_INET, SOCK_DGRAM, 0); 
    if (sock == -1) 
    {   
            perror("socket");
            return -1; 
    }   

    strncpy(ifr.ifr_name, ETH_NAME, IFNAMSIZ);
    ifr.ifr_name[IFNAMSIZ - 1] = 0;

    if (ioctl(sock, SIOCGIFADDR, &ifr) < 0)
    {   
            perror("ioctl");
            return -1; 
    }   
    memcpy(sin, &ifr.ifr_addr, sizeof(struct sockaddr_in));
    memcpy(ip, inet_ntoa(sin->sin_addr), 16);
    printf("ip:%s\n", ip);

   // memcpy(ip, inet_ntoa(sin.sin_addr), 16);
    return 0;
}


void init()
{
        struct sockaddr_in addr;
        int reuseaddr = 1;

        printf("Server starting...\n");
        sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (sockfd == -1) {
                perror("socket");
                exit(-1);
        }
        GetLocalAddress(&addr);
        addr.sin_family = AF_INET;
        addr.sin_port = htons(PORT);
       // addr.sin_addr.s_addr = inet_addr(IP);
        setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(reuseaddr));
        if(bind(sockfd, (SA *)&addr, sizeof(addr)) == -1) {
                perror("bind");
                exit(-1);
        }
        if(listen(sockfd, 100) == -1) {
                perror("listen");
                exit(-1);
        }
        printf("Server init OK\n");
}

void rcv_proc(int sfd)
{
        int size = 0;
        char buf[512] = {0};
        while(size = read(sfd, buf, sizeof(buf)))
        {
                printf("Client %d say>: %s \n", sfd, buf);
                if(!write(sfd, buf, strlen(buf) + 1))
                {
                        perror("write");
                }
                memset(buf, 0, sizeof(buf));
        }
        printf("%d, has disconnect\n", sfd);
}

void service()
{
        printf("Server has started!\n");
        int fd;
        for(;;)
        {
                struct sockaddr_in fromaddr;
                socklen_t len = sizeof(fromaddr);
                printf("\nWaiting for clients to connect...\n");
                fd = accept(sockfd, (SA *)&fromaddr, &len);//accept是接收要连接client的IP和端口,所以这里要新建个
struct sockaddr_in用来接收
                if (-1 == fd)
                {
                        printf("Client connect failed\n");
                        continue;
                }
                else
                {
                        printf("Has connect to client: %d\n", fd);
                }
                rcv_proc(fd);
        }
}
void sig_close()
{
        close(sockfd);
        printf("Server is going down ...\n");
        exit(0);
}

int main()
{
        signal(SIGINT, sig_close);
        printf("press <Ctrl+c> to stop server\n");
        init();
        service();
        return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值