📄 15.htm
字号:
<p>char *ptr, buf[MAXLINE]; </p>
<p>struct strbuf dat; </p>
<p>struct strrecvfd recvfd; </p>
<p>status = -1; </p>
<p>for ( ; ; ) { </p>
<p>dat.buf = buf; </p>
<p>dat.maxlen = MAXLINE; </p>
<p>flag = 0; </p>
<p>if (getmsg(servfd, NULL, &dat, &flag) < 0) </p>
<p>err_sys("getmsg error"); </p>
<p>nread = dat.len; </p>
<p>if (nread == 0) { </p>
<p>err_ret("connection closed by server"); </p>
<p>return(-1); </p>
<p>} </p>
<p>/* See if this is the final data with null & status. </p>
<p>Null must be next to last byte of buffer, status </p>
<p>byte is last byte. Zero status means there must </p>
<p>be a file descriptor to receive. */ </p>
<p>for (ptr = buf; ptr < &buf[nread]; ) { </p>
<p>if (*ptr++ == 0) { </p>
<p>if (ptr != &buf[nread-1]) </p>
<p>err_dump("message format error"); </p>
<p>status = *ptr & 255; </p>
<p>if (status == 0) { </p>
<p>if (ioctl(servfd, I_RECVFD, &recvfd) < 0) </p>
<p>return(-1); </p>
<p>newfd = recvfd.fd; /* new descriptor */ </p>
<p>} else </p>
<p>newfd = -status; </p>
<p>nread -= 2; </p>
<p>} </p>
<p>} </p>
<p>if (nread > 0) </p>
<p>if ((*userfunc)(STDERR_FILENO, buf, nread) != nread) </p>
<p>return(-1); </p>
<p>if (status >= 0) /* final data has arrived */ </p>
<p>return(newfd); /* descriptor, or -status */ </p>
<p>} </p>
<p>} </p>
<p>程序15.6 SVR4下的recv_fd函数 </p>
<p>15.3.2 4.3BSD </p>
<p>不幸,对于4.3BSD以及在其基础上构造的SunOS和Ultrix,以及从4.3BSD
</p>
<p>Reno开始的后续版本我们必须提供不同的实现。 </p>
<p>为了交换文件描述符,调用sendmsg(2)和recvmsg(2)函数。这两个函数的参数中都
</p>
<p>有一个指向msghdr的指针,该结构包含了所有关于要发送和接收消息的信息。该结
</p>
<p>构定义在〈sys/socket.h〉 头文件中,在BSD4.3之下,其样式是: </p>
<p>_______________________________________________________________________ </p>
<p>______ </p>
<p>strcut msghdr { </p>
<p>caddr_t msg_name; 可选的地址 </p>
<p>int msg_namelen; 地址长度 </p>
<p>struct iovec msg_iov; 散布/聚集数组 </p>
<p>int msg_iovlen; 在msg_iov数组中的元素数 </p>
<p>caddr_t msg_accrights; 存取权发送/接收到 </p>
<p>int msg-accrightslen; 存取权缓存的长度 </p>
<p>} </p>
<p>_______________________________________________________________________ </p>
<p>______ </p>
<p>头两个元素通常用于在网络连接上发送数据报文,在这里,目的地址可以由每个数
</p>
<p>据报文指定。下面两个元素使我们可以指定缓存的数组(散布读和聚集写),这如
</p>
<p>同我们对readv和writev函数(12.7节)的说明一样。最后两个元素处理存取权的
</p>
<p>传送和接收。当前唯一定义的存取权是文件描述符。存取权仅可跨越一个UNIX域套
</p>
<p>接口传送(亦即,在4.3BSD之下作为流管道我们所使用的)。为了发送或接收一文
</p>
<p>件描述符,将msg_accrights设置为指向该整型描述符,将msg_accrightslen设置
</p>
<p>为描述符的长度(亦即,整型的长度)。仅当此长度非0时,才传送或接收描述符
</p>
<p>。 </p>
<p>程序15.7是4.3BSD下的send_fd函数 </p>
<p>#include <sys/types.h> </p>
<p>#include <sys/socket.h> /* struct msghdr */ </p>
<p>#include <sys/uio.h> /* struct iovec */ </p>
<p>#include <errno.h> </p>
<p>#include <stddef.h> </p>
<p>#include "ourhdr.h" </p>
<p>/* Pass a file descriptor to another process. </p>
<p>* If fd<0, then -fd is sent back instead as the error status. */ </p>
<p>int </p>
<p>send_fd(int clifd, int fd) </p>
<p>{ </p>
<p>struct iovec iov[1]; </p>
<p>struct msghdr msg; </p>
<p>char buf[2]; /* send_fd()/recv_fd() 2-byte protocol */ </p>
<p>iov[0].iov_base = buf; </p>
<p>iov[0].iov_len = 2; </p>
<p>msg.msg_iov = iov; </p>
<p>msg.msg_iovlen = 1; </p>
<p>msg.msg_name = NULL; </p>
<p>msg.msg_namelen = 0; </p>
<p>if (fd < 0) { </p>
<p>msg.msg_accrights = NULL; </p>
<p>msg.msg_accrightslen = 0; </p>
<p>buf[1] = -fd; /* nonzero status means error */ </p>
<p>if (buf[1] == 0) </p>
<p>buf[1] = 1; /* -256, etc. would screw up protocol */ </p>
<p>} else { </p>
<p>msg.msg_accrights = (caddr_t) &fd; /* addr of descriptor */ </p>
<p>msg.msg_accrightslen = sizeof(int); /* pass 1 descriptor */ </p>
<p>buf[1] = 0; /* zero status means OK */ </p>
<p>} </p>
<p>buf[0] = 0; /* null byte flag to recv_fd() */ </p>
<p>if (sendmsg(clifd, &msg, 0) != 2) </p>
<p>return(-1); </p>
<p>return(0); </p>
<p>} </p>
<p>程序15.7 4.3BDS下的send_fd函数 </p>
<p>在sendnisg调用中,发送双字节协议数据(null和status字节)和描述符。
</p>
<p>为了接收一文件描述符,我们从流管道读,直至读到null字节,它位于最后的sta
</p>
<p>tus字节之前。在此null字节之前的是一条出错消息,它来自发送者。这示于程序
</p>
<p>15.8。 </p>
<p>#include <sys/types.h> </p>
<p>#include <sys/socket.h> /* struct msghdr */ </p>
<p>#include <sys/uio.h> /* struct iovec */ </p>
<p>#include <stddef.h> </p>
<p>#include "ourhdr.h" </p>
<p>/* Receive a file descriptor from another process (a server). </p>
<p>* In addition, any data received from the server is passed </p>
<p>* to (*userfunc)(STDERR_FILENO, buf, nbytes). We have a </p>
<p>* 2-byte protocol for receiving the fd from send_fd(). */ </p>
<p>int </p>
<p>recv_fd(int servfd, ssize_t (*userfunc)(int, const void *, size_t)) </p>
<p>{ </p>
<p>int newfd, nread, status; </p>
<p>char *ptr, buf[MAXLINE]; </p>
<p>struct iovec iov[1]; </p>
<p>struct msghdr msg; </p>
<p>status = -1; </p>
<p>for ( ; ; ) { </p>
<p>iov[0].iov_base = buf; </p>
<p>iov[0].iov_len = sizeof(buf); </p>
<p>msg.msg_iov = iov; </p>
<p>msg.msg_iovlen = 1; </p>
<p>msg.msg_name = NULL; </p>
<p>msg.msg_namelen = 0; </p>
<p>msg.msg_accrights = (caddr_t) &newfd;/* addr of descriptor */ </p>
<p>msg.msg_accrightslen = sizeof(int); /* receive 1 descriptor */ </p>
<p>if ( (nread = recvmsg(servfd, &msg, 0)) < 0) </p>
<p>err_sys("recvmsg error"); </p>
<p>else if (nread == 0) { </p>
<p>err_ret("connection closed by server"); </p>
<p>return(-1); </p>
<p>} </p>
<p>/* See if this is the final data with null & status. </p>
<p>Null must be next to last byte of buffer, status </p>
<p>byte is last byte. Zero status means there must </p>
<p>be a file descriptor to receive. */ </p>
<p>for (ptr = buf; ptr < &buf[nread]; ) { </p>
<p>if (*ptr++ == 0) { </p>
<p>if (ptr != &buf[nread-1]) </p>
<p>err_dump("message format error"); </p>
<p>status = *ptr & 255; </p>
<p>if (status == 0) { </p>
<p>if (msg.msg_accrightslen != sizeof(int)) </p>
<p>err_dump("status = 0 but no fd"); </p>
<p>/* newfd = the new descriptor */ </p>
<p>} else </p>
<p>newfd = -status; </p>
<p>nread -= 2; </p>
<p>} </p>
<p>} </p>
<p>if (nread > 0) </p>
<p>if ((*userfunc)(STDERR_FILENO, buf, nread) != nread) </p>
<p>return(-1); </p>
<p>if (status >= 0) /* final data has arrived */ </p>
<p>return(newfd); /* descriptor, or -status */ </p>
<p>} </p>
<p>} </p>
<p>程序15.8 4.3BSD下的recv_fd函数 </p>
<p>注意,该程序总是准备接收一描述符(在每次调用recvmsg之前,设置msg_accrig
</p>
<p>hts和msg_accrightslen ),但是仅当在返回时msg_accrightslen非0,我们才确实
</p>
<p>接收到一描述符。 </p>
<p>15.3.3 4.3+BSD </p>
<p>从4.3BSD Reno开始,更改了msghdr结构的定义。在以前版本中被称之为"存取权"
</p>
<p>的最后两个元素改称为"辅助数据"。另外,在该结构结束处增加了一个新成员msg
</p>
<p>_flags。 </p>
<p>strcut msghdr { </p>
<p>caddr_t msg_name; 可选的地址 </p>
<p>int msg_namelen; 地址长度 </p>
<p>struct iovec msg_iov; 散布/聚集数组 </p>
<p>int msg_iovlen; 在msg_iov数组中的元素数 </p>
<p>caddr_t msg_control; 辅助数据 </p>
<p>int msg-controllen; 辅助数据的长度 </p>
<p>int msg_flags; 接收到消息的标志 </p>
<p>} </p>
<p>现在,msg_control字段指向一个cmsghdr(控制消息头)结构。 </p>
<p>struct cmsghdr { </p>
<p>u_int cmsg_len; 数据的字节数,包括头 </p>
<p>int cmsg_level; 初始的协议 </p>
<p>int cmsg_type; 协议细节的类型 </p>
<p>下接真正的控制消息数据 </p>
<p>} </p>
<p>为了发送一文件描述符,将cmsg_len设置为cmsghdr结构长度加一个整型(描述符
</p>
<p> </p>
<p>)的长度。将cmsg_level设置为SOL_SOCKET,cmsg_type设置为SCM_RIGHTS,这表明
</p>
<p>正在传送的是存取权。("SCM"表示套接口级控制消息,"socket-level
control </p>
<p>message"。)实际描述符的存放位置紧随cmsy_type字段之后,使用CMSG_DATA宏以
</p>
<p>获得指向该整型数的指针。程序15.9示出了4.3BSD Reno之下的send_fd函数。
</p>
<p>#include <sys/types.h> </p>
<p>#include <sys/socket.h> /* struct msghdr */ </p>
<p>#include <sys/uio.h> /* struct iovec */ </p>
<p>#include <errno.h> </p>
<p>#include <stddef.h> </p>
<p>#include "ourhdr.h" </p>
<p>static struct cmsghdr *cmptr = NULL; /* buffer is malloc'ed first time </p>
<p>*/ </p>
<p>#define CONTROLLEN (sizeof(struct cmsghdr) + sizeof(int)) </p>
<p>/* size of control buffer to send/recv one file descriptor */ </p>
<p>/* Pass a file descriptor to another process. </p>
<p>* If fd<0, then -fd is sent back instead as the error status. */ </p>
<p>int </p>
<p>send_fd(int clifd, int fd) </p>
<p>{ </p>
<p>struct iovec iov[1]; </p>
<p>struct msghdr msg; </p>
<p>char buf[2]; /* send_fd()/recv_fd() 2-byte protocol */ </p>
<p>iov[0].iov_base = buf; </p>
<p>iov[0].iov_len = 2; </p>
<p>msg.msg_iov = iov; </p>
<p>msg.msg_iovlen = 1; </p>
<p>msg.msg_name = NULL; </p>
<p>msg.msg_namelen = 0; </p>
<p>if (fd < 0) { </p>
<p>msg.msg_control = NULL; </p>
<p>msg.msg_controllen = 0; </p>
<p>buf[1] = -fd; /* nonzero status means error */ </p>
<p>if (buf[1] == 0) </p>
<p>buf[1] = 1; /* -256, etc. would screw up protocol */ </p>
<p>} else { </p>
<p>if (cmptr == NULL && (cmptr = malloc(CONTROLLEN)) == NULL) </p>
<p>return(-1); </p>
<p>cmptr->cmsg_level = SOL_SOCKET; </p>
<p>cmptr->cmsg_type = SCM_RIGHTS; </p>
<p>cmptr->cmsg_len = CONTROLLEN; </p>
<p>msg.msg_control = (caddr_t) cmptr; </p>
<p>msg.msg_controllen = CONTROLLEN; </p>
<p>*(int *)CMSG_DATA(cmptr) = fd; /* the fd to pass */ </p>
<p>buf[1] = 0; /* zero status means OK */ </p>
<p>} </p>
<p>buf[0] = 0; /* null byte flag to recv_fd() */ </p>
<p>if (sendmsg(clifd, &msg, 0) != 2) </p>
<p>return(-1); </p>
<p>return(0); </p>
<p>} </p>
<p>程序15.9 4.3BSD之下的send_fd函数 </p>
<p>为了接收一描述符(程序15.10),我们为cmsghdr结构和一描述符分配足够的存储
</p>
<p>区,设置msg_control使其指向所分配到的存储区,然后调用recvmsg。 </p>
<p>#include <sys/types.h> </p>
<p>#include <sys/socket.h> /* struct msghdr */ </p>
<p>#include <sys/uio.h> /* struct iovec */ </p>
<p>#include <stddef.h> </p>
<p>#include "ourhdr.h" </p>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -