在ioctl函数之前,对它的认识是停留在系统调用接口,并无实际更深入的了解和掌握,因为学习和使用,让我更加清楚了这个函数的“使命”。作为一个初学者,秉承谦虚好学的态度,希望多多指教,共同进步。废话不多说了。
使用:在网络编程方面,特别是网络服务器程序对iotcl函数的使用是很经常的,使用iotcl获取所在主机全部网络接口的信息,包括:接口地址,是否支持广播,是否支持多播等等。
原型:
#include <unistd.h>
int ioctl (int fd, int request,... /*void *arg*/);
返回:若成功则为0,若出错则为-1
参数:
第一个参数是int fd,使用是需传入打开的文件描述符,当然包含一般文件,设备文件,以及套接字文件。
第二个参数是int request,相关网络的请求参数,网络请求大体的分为6类:
1. 套接字操作
2. 文件操作
3. 接口操作
4. ARP高速缓存操作
5. 路由表操作
6. 流系统
网络相关的ioctl数据类型如下图所示:
第三个参数使用时传入的是一个指针,该指针的类型是依赖于第二个参数request的,犹如“种瓜得瓜”一般,在第二个参数中输入对用的套接字,文件,接口等数据类型,那当然你需要一个指向套接字,文件,接口等数据类型结构的存储指针。
实例:
罗列一些网络编程经常使用的头文件包含mynet.h
#include <netinet/in.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/file.h>
#include <sys/types.h>
#include <netinet/ip.h>
#include <arpa/ftp.h>
#include <arpa/inet.h>
#include <arpa/telnet.h>
#include <stdio.h>
#include <signal.h>
#include <string.h>
#include <net/if.h>
#include <stdlib.h>
#include <unistd.h>
#include <error.h>
#include <ifaddrs.h>
#include <netdb.h>
通过eth0获取本机的IPv4的地址;
#include "mynet.h"
int main(int argc, char* argv[]){
char *interface = "eth0";
struct ifreq ifr;
int skfd;
struct sockaddr_in *saddr;
char printaddr[50];
if ( (skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
perror("socket error");
return -1;
}
strncpy(ifr.ifr_name, interface, IFNAMSIZ);
if (ioctl(skfd, SIOCGIFADDR, &ifr) < 0) {
perror("net_get_ifaddr: ioctl SIOCGIFADDR");
close(skfd);
return -1;
}
close(skfd);
saddr = (struct sockaddr_in *) &ifr.ifr_addr;
inet_ntop(AF_INET, &saddr->sin_addr, printaddr, sizeof(printaddr));
printf("IPv4 address: %s\n", printaddr);
return 0;
}
通过eth0获取本机的IPv4的子网掩码;
#include "mynet.h"
int main(int argc, char* argv[]){
char *interface = "eth0";
struct ifreq ifr;
int skfd;
struct sockaddr_in *saddr;
char printaddr[50];
if ( (skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
perror("socket error");
return -1;
}
strncpy(ifr.ifr_name, interface, IFNAMSIZ);
if (ioctl(skfd, SIOCGIFNETMASK, &ifr) < 0) {
perror("net_get_ifaddr: ioctl SIOCGIFADDR");
close(skfd);
return -1;
}
close(skfd);
saddr = (struct sockaddr_in *) &ifr.ifr_addr;
inet_ntop(AF_INET, &saddr->sin_addr, printaddr, sizeof(printaddr));
printf("IPv4 netmask: %s\n", printaddr);
return 0;
}
通过eth0获取本机的IPv4的dns;
#include "mynet.h"
int main(int argc, char* argv[]){
FILE *fp;
int index = 0;
char buffer[256] = {0}, dnsname[80] = {0};
fp = fopen("/etc/resolv.conf", "rb");
char *printaddr;
if(!fp){
printf("IPv4 dns: %s\n", "0.0.0.0");
return 0;
}
while(fgets(buffer, sizeof(buffer), fp)){
if (sscanf(buffer, "nameserver %s\n", dnsname)){
printf("IPv4 dns: %s\n", dnsname);
}
}
return 0;
}
通过eth0获取本机的IPv6的地址;
include "mynet.h"
int main(int argc, char *argv[]){
struct ifaddrs *ifaddr, *ifa;
int family, s;
char host[NI_MAXHOST];
char* ifaname;
if (getifaddrs(&ifaddr) == -1){
perror("getifaddrs");
exit(EXIT_FAILURE);
}
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next){
if (ifa->ifa_addr == NULL)
continue;
family = ifa->ifa_addr->sa_family;
ifaname = ifa->ifa_name;
if (family == AF_INET6 && memcmp(ifaname, "eth0", 4) == 0 ) {
printf("%s ", ifa->ifa_name);
s = getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in6),
host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
if (s != 0){
printf("getnameinfo() failed: %s\n", gai_strerror(s));
exit(EXIT_FAILURE);
}
if (memcmp(host, "2001", 4) == 0){ //add "2001:f80...."
printf("\tIPv6 address: <%s>\n", host);
}else{
;
}
}else{
continue;
}
}
freeifaddrs(ifaddr);
exit(EXIT_SUCCESS);
}