在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);
}