网卡的信息储存在一个叫 ifreq 的结构体里面,获取本地IP实质上是从该结构体取想要的信息。该结构体如下:
#define IFHWADDRLEN 6
#define IFNAMSIZ IF_NAMESIZE
struct ifreq
{
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;
};
还会用到 ioctl 函数。ioctl是设备驱动程序中对设备的I/O通道进行管理的函数。所谓对I/O通道进行管理,就是对设备的一些特性进行控制,例如串口的传输波特率、马达的转速等等.。函数原型为:
#include<unistd.h>
int ioctl( int fd, int request, .../* void *arg */ );
返回0 :成功 -1 :出错
下表列出了网络相关ioctl 请求的request 参数以及arg 地址必须指向的数据类型:
类别 | Request | 说明 | 数据类型 |
套 接 口 | SIOCATMARK SIOCSPGRP SIOCGPGRP | 是否位于带外标记 设置套接口的进程ID 或进程组ID 获取套接口的进程ID 或进程组ID | int int int |
文
件
| FIONBIN FIOASYNC FIONREAD FIOSETOWN FIOGETOWN
| 设置/ 清除非阻塞I/O 标志 设置/ 清除信号驱动异步I/O 标志 获取接收缓存区中的字节数 设置文件的进程ID 或进程组ID 获取文件的进程ID 或进程组ID | int int int int int |
接 口
| SIOCGIFCONF SIOCSIFADDR SIOCGIFADDR SIOCSIFFLAGS SIOCGIFFLAGS SIOCSIFDSTADDR SIOCGIFDSTADDR SIOCGIFBRDADDR SIOCSIFBRDADDR SIOCGIFNETMASK SIOCSIFNETMASK SIOCGIFMETRIC SIOCSIFMETRIC SIOCGIFMTU SIOCxxx | 获取所有接口的清单 设置接口地址 获取接口地址 设置接口标志 获取接口标志 设置点到点地址 获取点到点地址 获取广播地址 设置广播地址 获取子网掩码 设置子网掩码 获取接口的测度 设置接口的测度 获取接口MTU (还有很多取决于系统的实现) | struct ifconf struct ifreq struct ifreq struct ifreq struct ifreq struct ifreq struct ifreq struct ifreq struct ifreq struct ifreq struct ifreq struct ifreq struct ifreq struct ifreq |
ARP | SIOCSARP SIOCGARP SIOCDARP | 创建/ 修改ARP 表项 获取ARP 表项 删除ARP 表项 | struct arpreq struct arpreq struct arpreq |
路 由 | SIOCADDRT SIOCDELRT | 增加路径 删除路径 | struct rtentry struct rtentry |
流 | I_xxx |
|
|
实现的代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
#include <unistd.h>
#include <net/if_arp.h>
#include <net/if.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
int get_ip()
{
int ret, skfd;
char *address;
struct ifreq ifr;
struct sockaddr_in *addr;
memset(&ifr, 0, sizeof(struct ifreq));
skfd = socket(AF_INET,SOCK_STREAM,0);
if(skfd < 0)
{
ret = -1;
exit(1);
}
strncpy(ifr.ifr_name, "eth0", IFNAMSIZ - 1);
ifr.ifr_addr.sa_family = AF_INET;
if (ioctl(skfd, SIOCGIFADDR, &ifr) == 0)
{
addr = (struct sockaddr_in *)&(ifr.ifr_addr);
address = inet_ntoa(addr->sin_addr);
printf("Ip = %s\n", address);
ret = 0;
}
else
{
ret = -1;
}
close(skfd);
return ret;
}
int main()
{
int re;
if(get_ip())
printf("get ip error !\n");
return 0;
}
以上的就是源码,本机IP在名叫“eth0”的网卡里面。
欢迎大家交流。