描述符传递探讨

927阅读 0评论2007-11-06 yunyuaner
分类:LINUX

套接口api定义了如下两个高级I/O函数:
 

ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
ssize_t sendmsg(int sockfd, struct msghdr *msg, int flags);

 
使用这两个函数可以在进程之间传递描述符。用户空间看到的描述符,是一个整型变量,它实际上是内核中相应结构的一个标号而已,这点比较类似于windows下的handle。例如,内核为进程所打开的文件创建文件描述符file结构,该结构除包含访问权限,文件偏移等与进程相关的属性外,还包括一个指向inode结构的指针,后者才是存放在磁盘文件的真正写照。进程维护一个file结构组成双向链表,标识当前所有打开的文件。同时,所有的file结构又组成一个hash table,用户态程序开发者可以通过file的编号作为键值,在hash table中找到其对应的file结构。

回到我讨论的话题中来,为什么需要传递描述符呢?这个要从进程的创建说起。linux内核中,用task_struct结构描述进程,这个结构大概占1k左右的空间,一般的,它与内核栈相邻,二者共用两个内存页。这样做的好处是,可以通过sp寄存器的指针快速的计算出task_struct结构的位置。当我们使用fork函数创建一个进程时(这里姑且不谈轻量级进程),它会拷贝父进程task_struct结构中的大部分内容到子进程的task_struct中,如页表,信号量,信号处理函数等等。tast_struct中维护一个file结构链表,它是该进程打开的文件列表,该列表会被复制到子进程的地址空间。由于采用了copy on write技术,此刻子进程和父进程共享file链表。

而当子进程打开新的文件时,它创建新的file结构,而该file结构属于子进程地址空间,对父进程透明。所以即使子进程通过IPC机制,把该描述符的标号传给父进程,父进程仍无法访问它,因为这个编号不是结构本身,它仅仅是hash table中的一个键值。

而通过上面两个套接口api传递描述符的机理就是通过unix域协议,拷贝传递进程的file结构到被传递进程,当然,这两个file结构的编号可能是不同的。

上一篇:小谈一下Bootloader的原理与实现
下一篇:Linux下Rtl8139too网卡设备驱动程序关键函数剖析