📄 00000015.htm
字号:
#include <sys/socket.h> /* struct msghdr */ <BR>#include <sys/uio.h> /* struct iovec */ <BR>#include <stddef.h> <BR>#include "ourhdr.h" <BR>static struct cmsghdr *cmptr = NULL; /* malloc'ed first time */ <BR>#define CONTROLLEN (sizeof(struct cmsghdr) + sizeof(int)) <BR> /* size of control buffer to send/recv one file descriptor */ <BR>/* Receive a file descriptor from another process (a server). <BR> * In addition, any data received from the server is passed <BR> * to (*userfunc)(STDERR_FILENO, buf, nbytes). We have a <BR> * 2-byte protocol for receiving the fd from send_fd(). */ <BR>int <BR>recv_fd(int servfd, ssize_t (*userfunc)(int, const void *, size_t)) <BR>{ <BR> int newfd, nread, status; <BR> char *ptr, buf[MAXLINE]; <BR> struct iovec iov[1]; <BR> struct msghdr msg; <BR> status = -1; <BR> for ( ; ; ) { <BR> iov[0].iov_base = buf; <BR> iov[0].iov_len = sizeof(buf); <BR> msg.msg_iov = iov; <BR> msg.msg_iovlen = 1; <BR> msg.msg_name = NULL; <BR> msg.msg_namelen = 0; <BR> if (cmptr == NULL && (cmptr = malloc(CONTROLLEN)) == NULL) <BR> return(-1); <BR> msg.msg_control = (caddr_t) cmptr; <BR> msg.msg_controllen = CONTROLLEN; <BR> if ( (nread = recvmsg(servfd, &msg, 0)) < 0) <BR> err_sys("recvmsg error"); <BR> else if (nread == 0) { <BR> err_ret("connection closed by server"); <BR> return(-1); <BR> } <BR> /* See if this is the final data with null & status. <BR> Null must be next to last byte of buffer, status <BR> byte is last byte. Zero status means there must <BR> be a file descriptor to receive. */ <BR> for (ptr = buf; ptr < &buf[nread]; ) { <BR> if (*ptr++ == 0) { <BR> if (ptr != &buf[nread-1]) <BR> err_dump("message format error"); <BR> status = *ptr & 255; <BR> if (status == 0) { <BR> if (msg.msg_controllen != CONTROLLEN) <BR> err_dump("status = 0 but no fd"); <BR> newfd = *(int *)CMSG_DATA(cmptr); /* new descriptor */ <BR> } else <BR> newfd = -status; <BR> nread -= 2; <BR> } <BR> } <BR> if (nread > 0) <BR> if ((*userfunc)(STDERR_FILENO, buf, nread) != nread) <BR> return(-1); <BR> if (status >= 0) /* final data has arrived */ <BR> return(newfd); /* descriptor, or -status */ <BR> } <BR>} <BR>程序15.10 4.3BSD之下的recv_fd函数 <BR>15.4 Open服务器,版本1 <BR> 使用文件描述符传送技术,现在我们开发一个open服务器:它是一个可执行程 <BR>序, <BR>由一个进程执行以打开一个或多个文件。该服务器不是将这种文件送回调用进程, <BR>而是送回一个打开文件描述符。这使该服务器对任何类型的文件(例如调制解调器 <BR>线,或一网络连接)而不单是普通文件都能起作用。这也意味着,用IPC交换最小 <BR>量的信息--从客户到服务器传送文件名和打开方式,而从服务器到客户返回描述符 <BR>。文件内容则不需用IPC传送。 <BR> 将服务器设计成一个单独的可执行程序有很多优点: <BR>1. 任一客户都易于和服务器联系,这类似于客户调用一库函数。我们不需要将一 <BR>特定服务编码在应用程序中,而是设计一种可供重用的设施。 <BR>2. 如若需要更改服务器,那么也只影响一道程序。相反,更新一库函数可能要更 <BR>改调用此库函数的所有程序(用连编程序重新连接)。共享库函数可以简化这种更 <BR>新。 <BR>3. 服务器可以是设置__用户__ID程序,于是使其具有客户没有的附加许可权。注 <BR>意,一个库函数(或共享库函数)不能提供这种能力。 <BR> 客户进程创建一流管道,然后调用fork和exec以调用服务器。客户经流管道发 <BR>送请求,服务器经管道回送响应。我们定义客户和服务器间的协议如下。 <BR>1. 客户经流管道向服务器发送下列形式的请求: <BR> open <pathname> <openmode>\o <BR><openmode>是open函数的第二个参数,以十进制表示。该请求字符串以null字节结 <BR>尾。 <BR>2. 服务器调用send_fd 或send_err回送一打开描述符或一条出错消息。这是一个 <BR>进程向其父进程发送一打开描述符的实例。在15.6节,我们将修改此实例,其中使 <BR>用了一个精灵服务器,它将一个描述符发送给完全无关的进程。 <BR> 程序15.11是头文件open.h,它包括标准系统头文件,并且定义了各个函数原 <BR>型。 <BR>#include <sys/types.h> <BR>#include <errno.h> <BR>。文件内容则不需用IPC传送。 <BR> 将服务器设计成一个单独的可执行程序有很多优点: <BR>1. 任一客户都易于和服务器联系,这类似于客户调用一库函数。我们不需要将一 <BR>特定服务编码在应用程序中,而是设计一种可供重用的设施。 <BR>2. 如若需要更改服务器,那么也只影响一道程序。相反,更新一库函数可能要更 <BR>改调用此库函数的所有程序(用连编程序重新连接)。共享库函数可以简化这种更 <BR>新。 <BR>3. 服务器可以是设置__用户__ID程序,于是使其具有客户没有的附加许可权。注 <BR>意,一个库函数(或共享库函数)不能提供这种能力。 <BR> 客户进程创建一流管道,然后调用fork和exec以调用服务器。客户经流管道发 <BR>送请求,服务器经管道回送响应。我们定义客户和服务器间的协议如下。 <BR>1. 客户经流管道向服务器发送下列形式的请求: <BR> open <pathname> <openmode>\o <BR><openmode>是open函数的第二个参数,以十进制表示。该请求字符串以null字节结 <BR>尾。 <BR>2. 服务器调用send_fd 或send_err回送一打开描述符或一条出错消息。这是一个 <BR>进程向其父进程发送一打开描述符的实例。在15.6节,我们将修改此实例,其中使 <BR>用了一个精灵服务器,它将一个描述符发送给完全无关的进程。 <BR> 程序15.11是头文件open.h,它包括标准系统头文件,并且定义了各个函数原 <BR>型。 <BR>#include <sys/types.h> <BR>#include <errno.h> <BR>#include "ourhdr.h" <BR>#define CL_OPEN "open" /* client's request for server */ <BR> /* our function prototypes */ <BR>int csopen(char *, int); <BR>程序15.11 open.h头文件 <BR>程序15.12是main函数,其中包含一个循环,它先从标准输入读一个路径名,然后 <BR>将该文件复制至标准输出。它调用函数csopen以与open 服务器联系,从其返回一 <BR>打开描述符。 <BR>#include "open.h" <BR>#include <fcntl.h> <BR>#define BUFFSIZE 8192 <BR>int <BR>main(int argc, char *argv[]) <BR>{ <BR> int n, fd; <BR> char buf[BUFFSIZE], line[MAXLINE]; <BR> /* read filename to cat from stdin */ <BR> while (fgets(line, MAXLINE, stdin) != NULL) { <BR> line[strlen(line) - 1] = 0; /* replace newline with null */ <BR> /* open the file */ <BR> if ( (fd = csopen(line, O_RDONLY)) < 0) <BR> continue; /* csopen() prints error from server */ <BR> /* and cat to stdout */ <BR> while ( (n = read(fd, buf, BUFFSIZE)) > 0) <BR> if (write(STDOUT_FILENO, buf, n) != n) <BR> err_sys("write error"); <BR> if (n < 0) <BR> err_sys("read error"); <BR> close(fd); <BR> } <BR> exit(0); <BR>} <BR>程序15.12 main 函数 <BR>程序15.13是函数csopen,它先创建一流管道,然后进行服务器的fork和exec操作 <BR>。 <BR>#include "open.h" <BR>#include <sys/uio.h> /* struct iovec */ <BR>/* Open the file by sending the "name" and "oflag" to the <BR> * connection server and reading a file descriptor back. */ <BR>int <BR>csopen(char *name, int oflag) <BR>{ <BR> pid_t pid; <BR> int len; <BR> char buf[10]; <BR> struct iovec iov[3]; <BR> static int fd[2] = { -1, -1 }; <BR> if (fd[0] < 0) { /* fork/exec our open server first time */ <BR> if (s_pipe(fd) < 0) <BR> err_sys("s_pipe error"); <BR> if ( (pid = fork()) < 0) <BR> err_sys("fork error"); <BR> else if (pid == 0) { /* child */ <BR>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -