ioctl、fcntl、setsockopt 的区别

ioctl、fcntl、setsockopt 这三个系统函数都是用来设置文件描述符fd属性的,在Linux中,一切设备皆文件,这些文件范围广泛,有些属性是所有文件都具有的共性,而另外一些属性则是某个种类专有的特性。

Linux使用ioctl设置与IO设备高度相关的属性,使用fcntl设置文件描述符的属性,使用setsockopt设置网络套接字的属性,总体而言设备范围逐渐缩小,所设置的属性更具有网络编程针对性。

1. ioctl:

函数原型:

#include <sys/ioctl.h>
int ioctl(int fd, unsigned long request, ...);

ioctl用于硬件设备I/O通道控制,控制命令和参数都与设备高度相关,通常也与系统高度相关。

ioctl是底层的系统调用,所以跨平台性不好(可能某些平台的IO属性在其他平台上并不具有);而fcntl是封装好的函数,各个OS都是支持的。

在网络socket中,它们都可以用于设置socket描述字的某些属性,例如非阻塞:

fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL) | O_NONBLOCK));

ioctl(sockfd, FIONBIO, 1);		//1表示非阻塞,0表示阻塞

2. fcntl:

函数原型:

#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, ...);

fcntl的操作对象是文件描述符,用来控制文件描述符属性的通用方法(例如 读写属性、是否阻塞等),setsockopt是用来专门设置套接字描述符的属性,针对网络编程中常见的属性设置的需求。

只要是文件描述符,就可以使用fcntl;setsockopt偏向于设置IP、TCP协议对应的套接字属性。

fcntl可以设置的几个常见的类型:

O_APPEND / O_CREAT / O_RDONLY / O_WRONLY / O_RDWR / O_NONBLOCK

fcntl的典型应用:设置非阻塞IO:

int setnonblocking(int fd) {
          
   
	int old_option = fcntl(fd, F_GETFL);
	int new_option = old_option | O_NONBLOCK;
	fcntl(fd, F_SETFL, new_option); 
	return new_option;
}

//另一种简洁写法:
int setnonblocking(int fd) {
          
   
	int option = fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
	return option;
}

3. setsockopt:

函数原型:

#include <sys/types.h>
#include <sys/socket.h>
int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);

其中,level 指定要操作的协议层:

SOL_SOCKET		: 通用socket选项,与协议无关
IPPROTO_IP		: 设置IP层协议,IPv4
IPPROTO_IPV6	: IPv6
IPPROTO_TCP		: 设置TCP层选项

option_name 指定具体的选项,每个level下有各自的option,level 和 option_name 这两个参数联合唯一确定对sockfd的操作内容。

setsockopt的典型举例:设置套接字的超时时间:

int main_client() {
          
   
	int sockfd = socket():
	
	struct timeval timeout;
	timeout.tv_sec = 0;
	timeout.tv_usec = 0;	//设置超时时间

	setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));

	ret = connect(sockfd, &serveraddr, sizeof(servaddr));
	if(ret == -1) {
          
   
		if(errno == EINPROGRESS) {
          
   		//connect超时返回-1,并设置errno为EINPROGRESS
			printf("connect timeout
");
		}
		return -1;
	}
}

setsockopt可用的套接字选项汇总:


参考内容:

经验分享 程序员 微信小程序 职场和发展