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

📄 15.htm

📁 UNIX环境下C编程的详细详细介绍
💻 HTM
📖 第 1 页 / 共 5 页
字号:
<p>static struct cmsghdr *cmptr = NULL; /* malloc'ed first time */ </p>

<p>#define CONTROLLEN (sizeof(struct cmsghdr) + sizeof(int)) </p>

<p>/* size of control buffer to send/recv one file descriptor */ </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>if (cmptr == NULL &amp;&amp; (cmptr = malloc(CONTROLLEN)) == NULL) </p>

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

<p>msg.msg_control = (caddr_t) cmptr; </p>

<p>msg.msg_controllen = CONTROLLEN; </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_controllen != CONTROLLEN) </p>

<p>err_dump(&quot;status = 0 but no fd&quot;); </p>

<p>newfd = *(int *)CMSG_DATA(cmptr); /* 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.10 4.3BSD之下的recv_fd函数 </p>

<p>15.4 Open服务器,版本1 </p>

<p>使用文件描述符传送技术,现在我们开发一个open服务器:它是一个可执行程 
</p>

<p>序, </p>

<p>由一个进程执行以打开一个或多个文件。该服务器不是将这种文件送回调用进程, 
</p>

<p>而是送回一个打开文件描述符。这使该服务器对任何类型的文件(例如调制解调器 
</p>

<p>线,或一网络连接)而不单是普通文件都能起作用。这也意味着,用IPC交换最小 
</p>

<p>量的信息--从客户到服务器传送文件名和打开方式,而从服务器到客户返回描述符 
</p>

<p>。文件内容则不需用IPC传送。 </p>

<p>将服务器设计成一个单独的可执行程序有很多优点: </p>

<p>1. 
任一客户都易于和服务器联系,这类似于客户调用一库函数。我们不需要将一 
</p>

<p>特定服务编码在应用程序中,而是设计一种可供重用的设施。 </p>

<p>2. 
如若需要更改服务器,那么也只影响一道程序。相反,更新一库函数可能要更 
</p>

<p>改调用此库函数的所有程序(用连编程序重新连接)。共享库函数可以简化这种更 
</p>

<p>新。 </p>

<p>3. 服务器可以是设置__用户__ID程序,于是使其具有客户没有的附加许可权。注 
</p>

<p>意,一个库函数(或共享库函数)不能提供这种能力。 </p>

<p>客户进程创建一流管道,然后调用fork和exec以调用服务器。客户经流管道发 
</p>

<p>送请求,服务器经管道回送响应。我们定义客户和服务器间的协议如下。 
</p>

<p>1. 客户经流管道向服务器发送下列形式的请求: </p>

<p>open &lt;pathname&gt; &lt;openmode&gt;\o </p>

<p>&lt;openmode&gt;是open函数的第二个参数,以十进制表示。该请求字符串以null字节结 
</p>

<p>尾。 </p>

<p>2. 服务器调用send_fd 或send_err回送一打开描述符或一条出错消息。这是一个 
</p>

<p>进程向其父进程发送一打开描述符的实例。在15.6节,我们将修改此实例,其中使 
</p>

<p>用了一个精灵服务器,它将一个描述符发送给完全无关的进程。 </p>

<p>程序15.11是头文件open.h,它包括标准系统头文件,并且定义了各个函数原 
</p>

<p>型。 </p>

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

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

<p>。文件内容则不需用IPC传送。 </p>

<p>将服务器设计成一个单独的可执行程序有很多优点: </p>

<p>1. 
任一客户都易于和服务器联系,这类似于客户调用一库函数。我们不需要将一 
</p>

<p>特定服务编码在应用程序中,而是设计一种可供重用的设施。 </p>

<p>2. 
如若需要更改服务器,那么也只影响一道程序。相反,更新一库函数可能要更 
</p>

<p>改调用此库函数的所有程序(用连编程序重新连接)。共享库函数可以简化这种更 
</p>

<p>新。 </p>

<p>3. 服务器可以是设置__用户__ID程序,于是使其具有客户没有的附加许可权。注 
</p>

<p>意,一个库函数(或共享库函数)不能提供这种能力。 </p>

<p>客户进程创建一流管道,然后调用fork和exec以调用服务器。客户经流管道发 
</p>

<p>送请求,服务器经管道回送响应。我们定义客户和服务器间的协议如下。 
</p>

<p>1. 客户经流管道向服务器发送下列形式的请求: </p>

<p>open &lt;pathname&gt; &lt;openmode&gt;\o </p>

<p>&lt;openmode&gt;是open函数的第二个参数,以十进制表示。该请求字符串以null字节结 
</p>

<p>尾。 </p>

<p>2. 服务器调用send_fd 或send_err回送一打开描述符或一条出错消息。这是一个 
</p>

<p>进程向其父进程发送一打开描述符的实例。在15.6节,我们将修改此实例,其中使 
</p>

<p>用了一个精灵服务器,它将一个描述符发送给完全无关的进程。 </p>

<p>程序15.11是头文件open.h,它包括标准系统头文件,并且定义了各个函数原 
</p>

<p>型。 </p>

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

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

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

<p>#define CL_OPEN &quot;open&quot; /* client's request for server */ </p>

<p>/* our function prototypes */ </p>

<p>int csopen(char *, int); </p>

<p>程序15.11 open.h头文件 </p>

<p>程序15.12是main函数,其中包含一个循环,它先从标准输入读一个路径名,然后 
</p>

<p>将该文件复制至标准输出。它调用函数csopen以与open 
服务器联系,从其返回一 </p>

<p>打开描述符。 </p>

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

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

<p>#define BUFFSIZE 8192 </p>

<p>int </p>

<p>main(int argc, char *argv[]) </p>

<p>{ </p>

<p>int n, fd; </p>

<p>char buf[BUFFSIZE], line[MAXLINE]; </p>

<p>/* read filename to cat from stdin */ </p>

<p>while (fgets(line, MAXLINE, stdin) != NULL) { </p>

<p>line[strlen(line) - 1] = 0; /* replace newline with null */ </p>

<p>/* open the file */ </p>

<p>if ( (fd = csopen(line, O_RDONLY)) &lt; 0) </p>

<p>continue; /* csopen() prints error from server */ </p>

<p>/* and cat to stdout */ </p>

<p>while ( (n = read(fd, buf, BUFFSIZE)) &gt; 0) </p>

<p>if (write(STDOUT_FILENO, buf, n) != n) </p>

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

<p>if (n &lt; 0) </p>

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

<p>close(fd); </p>

<p>} </p>

<p>exit(0); </p>

<p>} </p>

<p>程序15.12 main 函数 </p>

<p>程序15.13是函数csopen,它先创建一流管道,然后进行服务器的fork和exec操作 
</p>

<p>。 </p>

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

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

<p>/* Open the file by sending the &quot;name&quot; and &quot;oflag&quot; to the </p>

<p>* connection server and reading a file descriptor back. */ </p>

<p>int </p>

<p>csopen(char *name, int oflag) </p>

<p>{ </p>

<p>pid_t pid; </p>

<p>int len; </p>

<p>char buf[10]; </p>

<p>struct iovec iov[3]; </p>

<p>static int fd[2] = { -1, -1 }; </p>

<p>if (fd[0] &lt; 0) { /* fork/exec our open server first time */ </p>

<p>if (s_pipe(fd) &lt; 0) </p>

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

<p>if ( (pid = fork()) &lt; 0) </p>

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

<p>else if (pid == 0) { /* child */ </p>

<p>close(fd[0]); </p>

<p>if (fd[1] != STDIN_FILENO) { </p>

<p>if (dup2(fd[1], STDIN_FILENO) != STDIN_FILENO) </p>

<p>err_sys(&quot;dup2 error to stdin&quot;); </p>

<p>} </p>

<p>if (fd[1] != STDOUT_FILENO) { </p>

<p>if (dup2(fd[1], STDOUT_FILENO) != STDOUT_FILENO) </p>

<p>err_sys(&quot;dup2 error to stdout&quot;); </p>

<p>} </p>

<p>if (execl(&quot;./opend&quot;, &quot;opend&quot;, NULL) &lt; 0) </p>

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

<p>} </p>

<p>close(fd[1]); /* parent */ </p>

<p>} </p>

<p>sprintf(buf, &quot; %d&quot;, oflag); /* oflag to ascii */ </p>

<p>iov[0].iov_base = CL_OPEN &quot; &quot;; </p>

<p>iov[0].iov_len = strlen(CL_OPEN) + 1; </p>

<p>iov[1].iov_base = name; </p>

<p>iov[1].iov_len = strlen(name); </p>

<p>iov[2].iov_base = buf; </p>

<p>iov[2].iov_len = strlen(buf) + 1; /* +1 for null at end of buf */ </p>

<p>len = iov[0].iov_len + iov[1].iov_len + iov[2].iov_len; </p>

<p>if (writev(fd[0], &amp;iov[0], 3) != len) </p>

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

<p>/* read descriptor, returned errors handled by write() */ </p>

<p>return( recv_fd(fd[0], write) ); </p>

<p>} </p>

<p>程序15.13 csopen函数 </p>

<p>子进程关闭管道的一端,父进程关闭另一端。子进程也为它所执行的服务器将管道 
</p>

<p>它使用的一端复制到其标准输入和标准输出0(另一种可选择的方案是将描述符fd 
</p>

<p>[1]的ASCII 表示形式作为一个参数传送给服务器。) </p>

<p>父进程将请求发送给服务器,请求中包含路径名和打开方式。最后,父进程调用r 
</p>

<p>ecv-fd以返回描述符或错误消息。如若服务器返回一错误消息则调用write,向标 
</p>

<p>准出错输出该消息。 </p>

<p>现在,观察open服务器。其程序是opend,它由子进程执行(见程序15.13)。先观 
</p>

<p>察opend.h头文件(程序15.14),它包括了系统头文件,并且说明了全局变量和函 
</p>

<p>数原型。 </p>

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

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

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

<p>#define CL_OPEN &quot;open&quot; /* client's request for server */ </p>

<p>/* declare global variables */ </p>

<p>extern char errmsg[]; /* error message string to return to client */ </p>

<p>extern int oflag; /* open() flag: O_xxx ... */ </p>

<p>extern char *pathname; /* of file to open() for client */ </p>

<p>/* function prototypes */ </p>

<p>int cli_args(int, char **); </p>

<p>void request(char *, int, int); </p>

<p>程序.15.14 opend.h头文件 </p>

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

<p>/* define global variables */ </p>

<p>char errmsg[MAXLINE]; </p>

<p>int oflag; </p>

<p>char *pathname; </p>

<p>int </p>

<p>main(void) </p>

<p>{ </p>

<p>int nread; </p>

<p>char buf[MAXLINE]; </p>

<p>for ( ; ; ) { /* read arg buffer from client, process request */ </p>

<p>if ( (nread = read(STDIN_FILENO, buf, MAXLINE)) &lt; 0) </p>

<p>err_sys(&quot;read error on stream pipe&quot;); </p>

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

<p>break; /* client has closed the stream pipe */ </p>

<p>request(buf, nread, STDIN_FILENO); </p>

<p>} </p>

<p>exit(0); </p>

<p>} </p>

<p>程序15.15 main函数 </p>

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

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

<p>void </p>

<p>request(char *buf, int nread, int fd) </p>

<p>{ </p>

<p>int newfd; </p>

<p>if (buf[nread-1] != 0) { </p>

<p>sprintf(errmsg, &quot;request not null terminated: %*.*s\n&quot;, </p>

<p>nread, nread, buf); </p>

<p>send_err(STDOUT_FILENO, -1, errmsg); </p>

<p>return; </p>

<p>} </p>

⌨️ 快捷键说明

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