⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 15.htm

📁 UNIX环境下C编程的详细详细介绍
💻 HTM
📖 第 1 页 / 共 5 页
字号:

<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, &amp;dat, &amp;flag) &lt; 0) </p>

<p>err_sys(&quot;getmsg error&quot;); </p>

<p>nread = dat.len; </p>

<p>if (nread == 0) { </p>

<p>err_ret(&quot;connection closed by server&quot;); </p>

<p>return(-1); </p>

<p>} </p>

<p>/* See if this is the final data with null &amp; 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 &lt; &amp;buf[nread]; ) { </p>

<p>if (*ptr++ == 0) { </p>

<p>if (ptr != &amp;buf[nread-1]) </p>

<p>err_dump(&quot;message format error&quot;); </p>

<p>status = *ptr &amp; 255; </p>

<p>if (status == 0) { </p>

<p>if (ioctl(servfd, I_RECVFD, &amp;recvfd) &lt; 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 &gt; 0) </p>

<p>if ((*userfunc)(STDERR_FILENO, buf, nread) != nread) </p>

<p>return(-1); </p>

<p>if (status &gt;= 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 &lt;sys/types.h&gt; </p>

<p>#include &lt;sys/socket.h&gt; /* struct msghdr */ </p>

<p>#include &lt;sys/uio.h&gt; /* struct iovec */ </p>

<p>#include &lt;errno.h&gt; </p>

<p>#include &lt;stddef.h&gt; </p>

<p>#include &quot;ourhdr.h&quot; </p>

<p>/* Pass a file descriptor to another process. </p>

<p>* If fd&lt;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 &lt; 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) &amp;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, &amp;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 &lt;sys/types.h&gt; </p>

<p>#include &lt;sys/socket.h&gt; /* struct msghdr */ </p>

<p>#include &lt;sys/uio.h&gt; /* struct iovec */ </p>

<p>#include &lt;stddef.h&gt; </p>

<p>#include &quot;ourhdr.h&quot; </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) &amp;newfd;/* addr of descriptor */ </p>

<p>msg.msg_accrightslen = sizeof(int); /* receive 1 descriptor */ </p>

<p>if ( (nread = recvmsg(servfd, &amp;msg, 0)) &lt; 0) </p>

<p>err_sys(&quot;recvmsg error&quot;); </p>

<p>else if (nread == 0) { </p>

<p>err_ret(&quot;connection closed by server&quot;); </p>

<p>return(-1); </p>

<p>} </p>

<p>/* See if this is the final data with null &amp; 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 &lt; &amp;buf[nread]; ) { </p>

<p>if (*ptr++ == 0) { </p>

<p>if (ptr != &amp;buf[nread-1]) </p>

<p>err_dump(&quot;message format error&quot;); </p>

<p>status = *ptr &amp; 255; </p>

<p>if (status == 0) { </p>

<p>if (msg.msg_accrightslen != sizeof(int)) </p>

<p>err_dump(&quot;status = 0 but no fd&quot;); </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 &gt; 0) </p>

<p>if ((*userfunc)(STDERR_FILENO, buf, nread) != nread) </p>

<p>return(-1); </p>

<p>if (status &gt;= 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结构的定义。在以前版本中被称之为&quot;存取权&quot; 
</p>

<p>的最后两个元素改称为&quot;辅助数据&quot;。另外,在该结构结束处增加了一个新成员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>正在传送的是存取权。(&quot;SCM&quot;表示套接口级控制消息,&quot;socket-level 
control </p>

<p>message&quot;。)实际描述符的存放位置紧随cmsy_type字段之后,使用CMSG_DATA宏以 
</p>

<p>获得指向该整型数的指针。程序15.9示出了4.3BSD Reno之下的send_fd函数。 
</p>

<p>#include &lt;sys/types.h&gt; </p>

<p>#include &lt;sys/socket.h&gt; /* struct msghdr */ </p>

<p>#include &lt;sys/uio.h&gt; /* struct iovec */ </p>

<p>#include &lt;errno.h&gt; </p>

<p>#include &lt;stddef.h&gt; </p>

<p>#include &quot;ourhdr.h&quot; </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&lt;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 &lt; 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 &amp;&amp; (cmptr = malloc(CONTROLLEN)) == NULL) </p>

<p>return(-1); </p>

<p>cmptr-&gt;cmsg_level = SOL_SOCKET; </p>

<p>cmptr-&gt;cmsg_type = SCM_RIGHTS; </p>

<p>cmptr-&gt;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, &amp;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 &lt;sys/types.h&gt; </p>

<p>#include &lt;sys/socket.h&gt; /* struct msghdr */ </p>

<p>#include &lt;sys/uio.h&gt; /* struct iovec */ </p>

<p>#include &lt;stddef.h&gt; </p>

<p>#include &quot;ourhdr.h&quot; </p>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -