ioctl函数操作----FIOSETOWN和FIOGETOWN

来源:互联网 发布:淘宝聚划算怎么抢 编辑:程序博客网 时间:2024/05/21 06:35

  FIOSETOWN和FIOGETOWN用来设置文件描述符的进程ID或进程组ID,在《Unix网络编程》卷一中有下面的图

这个图是在第二版的16.3节,图中FIOSETOWN和FIOGETOWN操作时第三个参数所需要的类型均int类型,我感觉这个地方不太准确(个人理解,或者跟作者的想法不同,或者作者这个地方出现了遗漏)。因为FIOSETOWN和FIOGETOWN操作时,第三个参数的类型应该分别为const int * 和int *。这个地方还有一个地方,个人感觉不妥,FIOGETOWN和FIOSETOWN这两个归于“文件”操作之列,但是在调用ioctl并且指定FIOGETOWN或FIOSETOWN时,如果第一个参数是普通文件的描述符,接口会报ENOTTY错误。所以根据测试的结果FIOGETOWN、FIOSETOWN应该只能作用于套接字。另外一个依据是在FIOGETOWN、FIOSETOWN定义的头文件中的注释,其完整的头文件如下所示:

#ifndef __ASM_GENERIC_SOCKIOS_H#define __ASM_GENERIC_SOCKIOS_H/* Socket-level I/O control calls. */#define FIOSETOWN   0x8901#define SIOCSPGRP   0x8902#define FIOGETOWN   0x8903#define SIOCGPGRP   0x8904#define SIOCATMARK  0x8905#define SIOCGSTAMP  0x8906      /* Get stamp (timeval) */#define SIOCGSTAMPNS    0x8907      /* Get stamp (timespec) */#endif /* __ASM_GENERIC_SOCKIOS_H */

注释“/* Socket-level I/O control calls. */”的意思就是说这些操作是在套接字级别(直译,英文太烂),所以大胆认为书本中这个地方处理的不是很恰当。当然stevens大师的作品的经典毋庸置疑,我也是看他的书本入门的,这里只是把一些疑问和自己的想法跟大家分享一下,希望相互学习,共同进步。下面给出我的测试程序和输出结果。

一、 使用普通文件描述符

  测试程序如下:

#include <sys/ioctl.h>#include <errno.h>#include <string.h>#include <stdlib.h>#include <sys/types.h>#include <fcntl.h>#include <sys/stat.h>#include <stdio.h>#include <sys/socket.h>#include <unistd.h>#include <stdint.h>int main(void){    int     own = -1;    int     fd = -1;    pid_t   pid;    pid = getpid();    if ((fd = open("test_file", O_RDWR)) < 0) {        fprintf(stderr, "open: %s, errno = %d\n",                 strerror(errno), errno);        return -1;    }    if (ioctl(fd, FIOGETOWN, &own) < 0) {        fprintf(stderr, "ioctl get: %s, errno = %d\n",                 strerror(errno), errno);        return -1;    }    printf("pid = %d, own = %d\n", pid, own);    if (ioctl(fd, FIOSETOWN, &pid) < 0) {        fprintf(stderr, "ioctl set: %s, errno = %d\n",                 strerror(errno), errno);        return -1;    }    return 0;}

其中test_file是我建立的一个普通文件,从代码中可以看出这个fd是通过打开一个文件获取的,然后直接执行ioctl操作,其结果如下所示:

ioctl get: Inappropriate ioctl for device, errno = 25

错误码25就是错误ENOTTY,出现这个错误的原因是“The  specified  request  does  not apply to the kind of object that the descriptor d references”或者“d is not associated with a character special device”(d是第一个参数)。所以从这里可以看出,FIOSETOWN和FIOGETOWN不能作用于普通文件描述符,其余其他的文件类型管道、符号链接等读者可以自行测试,我也不知道可不可以。

二、使用套接字

测试程序如下:

#include <sys/ioctl.h>#include <errno.h>#include <string.h>#include <stdlib.h>#include <sys/types.h>#include <fcntl.h>#include <sys/stat.h>#include <stdio.h>#include <sys/socket.h>#include <unistd.h>#include <stdint.h>int main(void){    int     own = -1;    int     fd = -1;    pid_t   pid;    pid = getpid();    fd = socket(AF_INET, SOCK_STREAM, 0);    if (ioctl(fd, FIOGETOWN, &own) < 0) {        fprintf(stderr, "ioctl get: %s, errno = %d\n",                 strerror(errno), errno);        fprintf(stderr, "ioctl get: %s\n", strerror(ENOTTY));        return -1;    }    printf("pid = %d, own = %d\n", pid, own);    if (ioctl(fd, FIOSETOWN, &pid) < 0) {        fprintf(stderr, "ioctl set: %s, errno = %d\n",                 strerror(errno), errno);        return -1;    }    return 0;}


这个程序和上面唯一的不同就是文件描述符的获取,这个的文件描述符是套接字,其输出结构如下所示:

pid = 2194, own = 0


没有任何错误输出。这里还有一个细节需要注意,新创建的套接字其所有者是进程0,这个不知道是因为初始化的问题还是因为这个套接字是进程0创建的。这个问题,只有看内核源码才能解答了。