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

📄 18.htm

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

<p>daemon_init(); </p>

<p>loop(); /* never returns */ </p>

<p>} </p>

<p>_______________________________________________________________________</p>

<p>_______ </p>

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

<p>当使用了 -d 选项后,所有对log_XXX函数的调用(见附录B)都送到标准错</p>

<p>误。 </p>

<p>否则它们就会被syslog记录下来。 </p>

<p>函数loop是服务器程序的主循环(程序18.3)。它使用了select 
函数来复</p>

<p>用 </p>

<p>不同的描述符。 </p>

<p>_______________________________________________________________________</p>

<p>_______ </p>

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

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

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

<p>static void cli_done(int); </p>

<p>static void child_done(int); </p>

<p>static fd_set allset; /* one bit per client conn, plus one</p>

<p>for listenfd </p>

<p>*/ </p>

<p>/* modified by loop() and cli_do </p>

<p>e() */ </p>

<p>void </p>

<p>loop(void) </p>

<p>{ </p>

<p>int i, n, maxfd, maxi, listenfd, nread; </p>

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

<p>Client *cliptr; </p>

<p>uid_t uid; </p>

<p>fd_set rset; </p>

<p>if (signal_intr(SIGCHLD, sig_chld) == SIG_ERR) </p>

<p>log_sys(&quot;signal error&quot;); </p>

<p>/* obtain descriptor to listen for client reques </p>

<p>s on */ </p>

<p>if ( (listenfd = serv_listen(CS_CALL)) &lt; 0) </p>

<p>log_sys(&quot;serv_listen error&quot;); </p>

<p>FD_ZERO(&amp;allset); </p>

<p>FD_SET(listenfd, &amp;allset); </p>

<p>maxfd = listenfd; </p>

<p>maxi = -1; </p>

<p>for ( ; ; ) { </p>

<p>if (chld_flag) </p>

<p>child_done(maxi); </p>

<p>rset = allset; /* rset gets modified each time around * </p>

<p>if ( (n = select(maxfd + 1, &amp;rset, NULL, NULL, NULL)) &lt; 0) </p>

<p> </p>

<p>if (errno == EINTR) { </p>

<p>/* caught SIGCHLD, find entry with child </p>

<p>one set */ </p>

<p>child_done(maxi); </p>

<p>continue; /* issue the select agai </p>

<p>*/ </p>

<p>} else </p>

<p>log_sys(&quot;select error&quot;); </p>

<p>} </p>

<p>if (FD_ISSET(listenfd, &amp;rset)) { </p>

<p>/* accept new client request */ </p>

<p>if ( (clifd = serv_accept(listenfd, &amp;uid)) &lt; 0) </p>

<p>log_sys(&quot;serv_accept error: %d&quot;, clifd); </p>

<p>i = client_add(clifd, uid); </p>

<p>FD_SET(clifd, &amp;allset); </p>

<p>if (clifd &gt; maxfd) </p>

<p>maxfd = clifd; /* max fd for select() */ </p>

<p>if (i &gt; maxi) </p>

<p>maxi = i; /* max index in client[] </p>

<p>array */ </p>

<p>log_msg(&quot;new connection: uid %d, fd %d&quot;, uid, clifd); </p>

<p>continue; </p>

<p>} </p>

<p>/* Go through client[] array. </p>

<p>Read any client data that has arrived. */ </p>

<p>for (cliptr = &amp;client[0]; cliptr &lt;= &amp;client[maxi]; cliptr++)</p>

<p>{ </p>

<p>if ( (clifd = cliptr-&gt;fd) &lt; 0) </p>

<p>continue; </p>

<p>if (FD_ISSET(clifd, &amp;rset)) { </p>

<p>/* read argument buffer from cli </p>

<p>nt */ </p>

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

<p>log_sys(&quot;read error on fd %d&quot;, clifd); </p>

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

<p>/* The client has terminated or closed t </p>

<p>e stream </p>

<p>pipe. Now we can release its device </p>

<p>ock. */ </p>

<p>log_msg(&quot;closed: uid %d, fd %d&quot;, </p>

<p>liptr-&gt;uid, clifd); </p>

<p>lock_rel(cliptr-&gt;pid); </p>

<p>cli_done(clifd); </p>

<p>continue; </p>

<p>} </p>

<p>/* Data has arrived from the client. Process th </p>

<p>client's request. */ </p>

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

<p>log_quit(&quot;request from uid %d not null t </p>

<p>rminated:&quot; </p>

<p>&quot; %*.*s&quot;, uid, nread, n </p>

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

<p>cli_done(clifd); </p>

<p>continue; </p>

<p>} </p>

<p>log_msg(&quot;starting: %s, from uid %d&quot;, buf, uid); </p>

<p>/* Parse the arguments, set opti </p>

<p>ns. Since </p>

<p>we may need to try calling ag </p>

<p>in for this </p>

<p>client, save options in clien </p>

<p>[] array. */ </p>

<p>if (buf_args(buf, cli_args) &lt; 0) </p>

<p>log_quit(&quot;command line error: %s&quot;, buf); </p>

<p>cliptr-&gt;Debug = Debug; </p>

<p>cliptr-&gt;parity = parity; </p>

<p>strcpy(cliptr-&gt;sysname, sysname); </p>

<p>strcpy(cliptr-&gt;speed, (speed == NULL) ? &quot;&quot; : spe </p>

<p>d); </p>

<p>cliptr-&gt;childdone = 0; </p>

<p>cliptr-&gt;sysftell = 0; </p>

<p>cliptr-&gt;foundone = 0; </p>

<p>if (request(cliptr) &lt; 0) { </p>

<p>/* system not found, or unable t </p>

<p>connect */ </p>

<p>if (send_err(cliptr-&gt;fd, -1, errmsg) &lt; 0 </p>

<p>log_sys(&quot;send_err error&quot;); </p>

<p>cli_done(clifd); </p>

<p>continue; </p>

<p>} </p>

<p>/* At this point request() has forked a child th </p>

<p>t is </p>

<p>trying to dial the remote system. We'll find </p>

<p>out the child's status when it terminates. */ </p>

<p>} </p>

<p>} </p>

<p>} </p>

<p>} </p>

<p>/* Go through the client[] array looking for clients whose</p>

<p>dialing </p>

<p>children have terminated. This function is called by loop()</p>

<p>when </p>

<p>chld_flag (the flag set by the SIGCHLD handler) is nonzero.</p>

<p>*/ </p>

<p>static void </p>

<p>child_done(int maxi) </p>

<p>{ </p>

<p>Client *cliptr; </p>

<p>again: </p>

<p>chld_flag = 0; /* to check when done with loop for more</p>

<p>SIGCHLDs */ </p>

<p>for (cliptr = &amp;client[0]; cliptr &lt;= &amp;client[maxi]; cliptr++)</p>

<p>{ </p>

<p>if ( (clifd = cliptr-&gt;fd) &lt; 0) </p>

<p>continue; </p>

<p>if (cliptr-&gt;childdone) { </p>

<p>log_msg(&quot;child done: pid %d, status %d&quot;, </p>

<p>cliptr-&gt;pid, cliptr-&gt;chi </p>

<p>ddone-1); </p>

<p>/* If the child was successful (exit(0)), just clear </p>

<p>the flag. When the client terminates, we'll read </p>

<p>the EOF on the stream pipe above and release </p>

<p>the device lock. */ </p>

<p>if (cliptr-&gt;childdone == 1) { /* child did exit(0) */ </p>

<p>cliptr-&gt;childdone = 0; </p>

<p>continue; </p>

<p>} </p>

<p>/* Unsuccessful: child did exit(1). Release the device </p>

<p>lock and try again from where we left off. */ </p>

<p>cliptr-&gt;childdone = 0; </p>

<p>lock_rel(cliptr-&gt;pid); /* unlock the device entry */ </p>

<p>if (request(cliptr) &lt; 0) { </p>

<p>/* still unable, time to give up </p>

<p>*/ </p>

<p>if (send_err(cliptr-&gt;fd, -1, errmsg) &lt; 0) </p>

<p>log_sys(&quot;send_err error&quot;); </p>

<p>cli_done(clifd); </p>

<p>continue; </p>

<p>} </p>

<p>/* request() has forked another child for this client */ </p>

<p>} </p>

<p>} </p>

<p>if (chld_flag) /* additional SIGCHLDs have been caught */ </p>

<p>goto again; /* need to check all childdone flags again */ </p>

<p>} </p>

<p>/* Clean up when we're done with a client. */ </p>

<p>static void </p>

<p>cli_done(int clifd) </p>

<p>{ </p>

<p>client_del(clifd); /* delete entry in client[] array */ </p>

<p>FD_CLR(clifd, &amp;allset); /* turn off bit in select() set */ </p>

<p>close(clifd); /* close our end of stream pipe */ </p>

<p>} </p>

<p>_______________________________________________________________________</p>

<p>_______ </p>

<p>程序18.3 loop.c文件 </p>

<p>loop函数初始化了client数组,建立了一个对SIGCHLD信号的处理器。我们</p>

<p>不 </p>

<p>调用signal,而调用了signal_intr ,这样当有信号返回时,每一个慢速</p>

<p>的系统调 </p>

<p>用都可以被中断。loop函数然后调用serv_listen(程序15.19和程序</p>

<p>15.22)。lo </p>

<p>op函数的其他部分是一个基于select函数的无限循环,它检查两种情况: 
</p>

<p>1. 如果传来一个新的客户端连接请求,我们调用serv_accept(程序15.20</p>

<p>和15.2 </p>

<p>4)。函数client_add为这个新的客户端在client数组中增加一项。 </p>

<p>2. 浏览整个client数组,看是否有客户端终止或者新的客户端请求到达。 
</p>

<p>当一个客户终止拨号时(不管是否自愿),它的客户端指定的通向服务器端的</p>

<p>流管道被 
关闭,我们从管道上得到一个文件终止符。这时,我们就可以释放</p>

<p>这 </p>

<p>个客户端所拥有的全部加锁,并删除client数组中的项。 </p>

<p>当从客户端收到请求时,我们就调用request函数(函数buf_args见程序</p>

<p>15.17 </p>

<p>)。如果客户端调用的远程系统的名字有效,而且找到相对应的Devices项,</p>

<p>requ </p>

<p>est函数就会创建一个子进程,然后返回。 </p>

<p>在loop函数运行中,子进程终止这一外部事件随时都可能发生。如果在</p>

<p>selec </p>

<p>t函数中阻塞,则select函数就返回一个EINTR错误。因为在loop函数的其他</p>

<p>地方也 </p>

<p>可能出现子进程终止信号,所以在这个循环中每次调用select之前都检测标</p>

<p>志chl </p>

<p>d_flag,如果有,我们就调用child_done来处理子进程终止。 </p>

<p>loop函数浏览整个client数组,检查每一项的childdone标志。如果子进程</p>

<p>成 </p>

<p>功,就不需要做其他事情。但如果子进程以状态1终止时(exit(1)),我们</p>

<p>就调用 </p>

<p>request函数来尝试使用Systems文件中的下一项。 </p>

<p>程序18.4 是cli_args,这个函数在客户端请求到达时被loop函数中的</p>

<p>buf_ar </p>

<p>gs所调用。它处理客户端送来的命令行参数。注意这个函数根据命令行参数</p>

<p>设置全 </p>

<p>局变量,然后loop函数将这些全局变量复制到client数组的相应的项中,这</p>

<p>些选项 </p>

<p>只影响一个客户端请求。 </p>

<p>程序18.5是client.c,它定义了处理client数组的函数组。程序18.5和程</p>

<p>序15.27 </p>

<p>的区别在于在这里我们一定要根据进程的ID(见函数client_sigchld)来查</p>

<p>询所需 </p>

<p>要的项。 </p>

<p>程序18.6是文件lock.c。其中的函数管理父进程中的lock数组。同上面的</p>

<p>cli </p>

<p>ent数组一样,我们调用realloc来给lock数组动态分配空间,以避免编译时</p>

<p>的限制 </p>

<p>。 </p>

<p>_______________________________________________________________________</p>

<p>_______ </p>

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

<p>/* This function is called by buf_args(), which is called by</p>

<p>loop(). </p>

<p>* buf_args() has broken up the client's buffer into an</p>

<p>argv[] style </p>

<p>* array, which is now processed. */ </p>

<p>int </p>

<p>cli_args(int argc, char **argv) </p>

<p>{ </p>

<p>int c; </p>

<p>if (argc &lt; 2 || strcmp(argv[0], CL_CALL) != 0) { </p>

<p>strcpy(errmsg, &quot;usage: call &lt;sysname&gt; &lt;options&gt;&quot;); </p>

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

<p>} </p>

<p>Debug = 0; /* option defaults */ </p>

<p>parity = NONE; </p>

<p>speed = NULL; </p>

<p>opterr = 0; /* don't want getopt() writing to stderr */ </p>

<p>optind = 1; /* since we call getopt() multiple times */ </p>

<p>while ( (c = getopt(argc, argv, &quot;des:o&quot;)) != EOF) { </p>

<p>switch (c) { </p>

<p>case 'd': </p>

<p>Debug = 1; /* client wants DEBUG() output */ </p>

<p>break; </p>

<p>case 'e': /* even parity */ </p>

<p>parity = EVEN; </p>

<p>break; </p>

<p>case 'o': /* odd parity */ </p>

<p>parity = ODD; </p>

<p>break; </p>

<p>case 's': /* speed */ </p>

<p>speed = optarg; </p>

<p>break; </p>

<p>case '?': </p>

<p>sprintf(errmsg, &quot;unrecognized option: -%c\n&quot;, optopt); </p>

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

<p>} </p>

<p>} </p>

<p>if (optind &lt; argc) </p>

<p>sysname = argv[optind]; /* name of host to call */ </p>

<p>else { </p>

<p>sprintf(errmsg, &quot;missing &lt;hostname&gt; to call\n&quot;); </p>

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

⌨️ 快捷键说明

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