实现简易Web服务器(c语言)

任务:

(1)实现服务器与客户端间的通信。

(2)可以实现HTTP请求中的GET方法。

(3)提供静态网页浏览功能,如可浏览:HTML页面,无格式文本,常见图像格式等。

(4)提供可以传递参数的动态网页浏览功能。

(5)可以检查一些明显错误报告给客户端,如:403无权访问,404找不到所请求的文件,501不支持相应方法等。

(6)在服务器端可输出HTTP响应的相关信息。

服务器端可配置参数,如:主目录,首页文件名,HTTP端口号等项。

套接字接口

套接字接口是一组函数,它们和Unix I/O函数结合起来,用以创建网络网络应用。

客户端和服务器使用socket函数来创建一个套接字描述符。

服务器端通过bind函数告诉内核将addr中的服务器套接字地址和套接字描述符sockfd联系起来;通过listen函数告诉内核,描述符是被服务器而不是客户端使用;通过accept函数来等待来自客户端的连接请求。

 

HTTP(超文本传输协议)被用在Web客户端和服务器之间的交互。当客户端需要服务时,它就向服务器发送一个HTTP请求说明需要的东西,服务器收到后解析,然后进行回应。本次实验,实现了应用最广泛的GET方法,并通过解析,判断是需要动态内容,还是静态内容,还是错误处理。

doit函数:处理一个HTTP事务。

首先读和解析请求行,获得方法,如果不是所支持的GET方法,就发送给它一个错误消息,并返回到主程序,主程序随后关闭连接并等待下一个连接请求。否则,读并且调用read_requesthdrs忽略报头中的其他信息。然后将URI解析为一个文件名和一个可能为空的CGI参数字符串,并且设置一个标志,表明请求的是静态内容还是动态内容。如果所需的文件不存在,就发送一个错误信息到客户端并返回。

parse_uri函数:解析URI并转为所需的文件名。

初始时设主目录为当前目录,可执行文件的目录为./cgi-bin。如果请求的是衣一个静态内容,就清楚CGI参数字符串,然后转为文件的路径名。如果请求的是动态内容,就提取出所有的CGI参数,然后转为文件的路径名。

serve_static函数:处理静态内容。

首先打开filename文件,用mmap函数将文件映射到一个虚拟内存空间,然后关闭这个文件,rio_writen函数复制到客户端已连接的描述符。这样前段就可以显示出所需的内容。

serve_dynamic函数:处理动态内容。

首先向客户端发送成功相应的内容,然后派生一个子进程,子进程用来自请求URI的CGI参数初始化QUERY_STRING环境变量,重定向标准输出到已连接文件描述符,然后执行CGI程序。

signal_r(SIGCHLD, sigchild_handler)函数:处理僵尸进程函数。

fork创建出很多进程,这些进程执行完以后就exit(0)然后发个信号通知主进程,exit函数退出后,进程的有关资源(打开的文件描述符,栈,寄存器,有关信息等)还没有释放掉,如果进程不被回收的话就会占用存储器资源这样的进程就称为僵尸进程。所以解决办法就是主进程使用一个信号处理函数,等待僵尸进程回收。

  1 /*
  2  * @filename:    webServer.c
  3  * @author:      Flyuz
  4  * @date:        2018年6月25日
  5  * @description: 主程序
  6  */
  7 
  8 #include "functionLib.h"
  9 
 10 void doit(int fd);
 11 void serve_static(int fd, char *filename, int filesize);
 12 int parse_uri(char *uri, char *filename, char *cgiargs);
 13 void read_requesthdrs(rio_t *rp);
 14 void clienterror(int fd, char *cause, char *errnum, char *shortmsg,
 15                  char *longmsg);
 16 void get_filetype(char *filename, char *filetype);
 17 void serve_dynamic(int fd, char *filename, char *cgiargs);
 18 
 19 
 20 int main(int argc, char **argv) {
 21   int listenfd, connfd;
 22   socklen_t clientlen;
 23 
 24   struct sockaddr_in clientaddr;
 25 
 26   if (argc != 2) {
 27     fprintf(stderr, "Usage: %s <port>\n", argv[0]);
 28     exit(1);
 29   }
 30 
 31   printf("The web server has been started.....\n");
 32 
 33   listenfd = Open_listenfd(argv[1]);
 34   /*
 35   信号处理函数
 36   用来处理僵尸进程
 37   */
 38   signal_r(SIGCHLD, sigchild_handler);
 39 
 40   while (1) {
 41     clientlen = sizeof(clientaddr);
 42     if((connfd = Accept(listenfd, (SA *)&clientaddr, &clientlen)) < 0)
 43     {
 44       if(errno == EINTR)
 45           continue;
 46       else
 47           printf("Accept error...");
 48     }
 49     pid_t pid = Fork();
 50     if(pid == 0)
 51     {
 52         doit(connfd);
 53         Close(connfd);
 54         exit(0);
 55     }
 56     else
 57     {
 58       Close(connfd);
 59     }
 60   }
 61 }
 62 
 63 void doit(int fd) {
 64   int is_static;
 65   struct stat sbuf;
 66   rio_t rio;
 67   char buf[MAXLINE], method[MAXLINE], uri[MAXLINE], version[MAXLINE];
 68   char filename[MAXLINE]; //设置根目录
 69   char cgiargs[MAXLINE];
 70 
 71   //初始化 rio 结构
 72   Rio_readinitb(&rio, fd);
 73   //读取http请求行
 74   Rio_readlineb(&rio, buf, MAXLINE);
 75   //格式化存入 把该行拆分
 76   sscanf(buf, "%s %s %s", method, uri, version);
 77 
 78   //只能处理GET请求,如果不是GET请求的话返回错误
 79   if (strcasecmp(method, "GET")) {
 80     clienterror(fd, method, "501", "Not Implemented",
 81                 "Flyuz does not implement thid method");
 82     return;
 83   }
 84 
 85   //读取并忽略请求报头
 86   read_requesthdrs(&rio);
 87 
 88   // memset(filename,0,sizeof(filename));
 89   //解析 URI
 90   is_static = parse_uri(uri, filename, cgiargs);
 91 
 92   //文件不存在
 93   if (stat(filename, &sbuf) < 0) {
 94     clienterror(fd, filename, "404", "Not found",
 95                 "Flyuz couldn't find this file");
 96     return;
 97   }
 98 
 99   if (is_static) { //服务静态内容
100     if (!(S_ISREG(sbuf.st_mode)) || !(S_IRUSR & sbuf.st_mode)) {
101       clienterror(fd, filename, "403", "Forbidden",
102                   "Flyuz couldn't read the file");
103       return;
104     }
105     serve_static(fd, filename, sbuf.st_size);
106   } else { //服务动态内容
107     if (!(S_ISREG(sbuf.st_mode)) || !(S_IXUSR & sbuf.st_mode)) {
108       clienterror(fd, filename, "403", "Forbidden",
109                   "Flyuz couldn't run the CGI program");
110       return;
111     }
112     serve_dynamic(fd, filename, cgiargs);
113   }
114 }
115 
116 /*
117  * 读取http 请求报头,无法使用请求报头的任何信息,读取之后忽略掉
118  */
119 void read_requesthdrs(rio_t *rp) {
120   char buf[MAXLINE];
121 
122   Rio_readlineb(rp, buf, MAXLINE);
123   printf("%s", buf);
124   //空文本行终止请求报头,碰到 空行 就结束 空行后面是内容实体
125   while (strcmp(buf, "\r\n")) {
126     Rio_readlineb(rp, buf, MAXLINE);
127     printf("%s", buf);
128   }
129   return;
130 }
131 
132 /*
133  * 解析URI 为 filename 和 CGI 参数
134  * 如果是动态内容返回0;静态内容返回 1
135  */
136 int parse_uri(char *uri, char *filename, char *cgiargs) {
137   if (!strstr(uri,
138               "cgi-bin")) { //默认可执行文件都放在cgi-bin下,这里表示没有找到
139     strcpy(cgiargs, "");
140     strcpy(filename, ".");
141     strcat(filename, uri);
142     /*
143     if(uri[strlen(uri)-1] == "/")  //设置默认文件
144         strcat(filename, "index.html");
145     */
146 
147     return 1; // static
148   } else {    //动态内容
149     char *ptr = strchr(uri, '?');
150     if (ptr) { //有参数
151       strcpy(cgiargs, ptr + 1);
152       *ptr = '\0';
153     } else { //无参数
154       strcpy(cgiargs, "");
155     }
156 
157     strcpy(filename, ".");
158     strcat(filename, uri);
159     return 0;
160   }
161 }
162 
163 /*
164  * 功能:发送一个HTTP响应,主体包含一个本地文件的内容
165  */
166 void serve_static(int fd, char *filename, int filesize) {
167   int srcfd;
168   char *srcp, body[MAXBUF], filetype[MAXLINE];
169 
170   /* 发送 响应行 和 响应报头 */
171   get_filetype(filename, filetype);
172 
173   sprintf(body, "HTTP/1.0 200 OK\r\n");
174   sprintf(body, "%sServer: Flyuz Web Server\r\n", body);
175   sprintf(body, "%sConnection:close\r\n", body);
176   sprintf(body, "%sContent-length: %d\r\n", body, filesize);
177   sprintf(body, "%sContent-type: %s\r\n\r\n", body, filetype);
178   Rio_writen(fd, body, strlen(body));
179   printf("Response headers: \n%s", body);
180 
181   /* 发送响应主体 即请求文件的内容 */
182   /* 只读方式发开filename文件,得到描述符*/
183   srcfd = Open(filename, O_RDONLY, 0);
184   /* 将srcfd 的前 filesize 个字节映射到一个从地址 srcp 开始的只读虚拟存储器区域
185    * 返回被映射区的指针 */
186   srcp = Mmap(0, filesize, PROT_READ, MAP_PRIVATE, srcfd, 0);
187   /* 此后通过指针 srcp 操作,不需要这个描述符,所以关掉 */
188   Close(srcfd);
189 
190   Rio_writen(fd, srcp, filesize);
191   /* 释放映射的虚拟存储器区域 */
192   Munmap(srcp, filesize);
193 }
194 
195 /*
196  * 功能:从文件名得出文件的类型
197  */
198 void get_filetype(char *filename, char *filetype) {
199   if (strstr(filename, ".html") || strstr(filename, ".php"))
200     strcpy(filetype, "text/html");
201   else if (strstr(filename, ".gif"))
202     strcpy(filetype, "image/gif");
203   else if (strstr(filename, ".png"))
204     strcpy(filetype, "image/png");
205   else if (strstr(filename, ".ipg"))
206     strcpy(filetype, "image/jpeg");
207   else
208     strcpy(filetype, "text/plain");
209 }
210 
211 /*
212  * 功能:运行客户端请求的CGI程序
213  */
214 void serve_dynamic(int fd, char *filename, char *cgiargs) {
215   char buf[MAXLINE];
216   char *emptylist[] = {NULL};
217 
218   /* 发送响应行 和 响应报头 */
219   sprintf(buf, "HTTP/1.0 200 OK\r\n");
220   Rio_writen(fd, buf, strlen(buf));
221   sprintf(buf, "Server Flyuz Web Server\r\n");
222   Rio_writen(fd, buf, strlen(buf));
223 
224   /* 剩下的内容由CGI程序负责发送 */
225   if (Fork() == 0) { //子进程
226     setenv("QUERY_STRING", cgiargs, 1);
227     Dup2(fd, STDOUT_FILENO);
228     Execve(filename, emptylist, __environ);
229   }
230   Wait(NULL);
231   /*
232   if(strstr(filename, ".php")) {
233             sprintf(response, "HTTP/1.1 200 OK\r\n");
234             sprintf(response, "%sServer: Pengge Web Server\r\n",response);
235             sprintf(response, "%sConnection: close\r\n",response);
236             sprintf(response, "%sContent-type: %s\r\n\r\n",response,filetype);
237             Write(connfd, response, strlen(response));
238             printf("Response headers:\n");
239             printf("%s\n",response);
240             php_cgi(filename, connfd,cgi_params);
241             Close(connfd);
242             exit(0);
243         //静态页面输出
244   }
245   */
246 }
247 
248 /*
249  * 检查一些明显的错误,报告给客户端
250  */
251 void clienterror(int fd, char *cause, char *errnum, char *shortmsg,
252                  char *longmsg) {
253   char buf[MAXLINE], body[MAXBUF];
254 
255   /* 构建HTTP response 响应主体 */
256   sprintf(body, "<html><title>Flyuz Error</title>");
257   sprintf(body,
258           "%s<body bgcolor="
259           "white"
260           ">\r\n",
261           body);
262   sprintf(body, "%s<center><h1>%s: %s</h1></center>", body, errnum, shortmsg);
263   sprintf(body, "%s<center><h3>%s: %s</h3></center>", body, longmsg, cause);
264   sprintf(body, "%s<hr><center>The Flyuzy Web server</center>\r\n", body);
265 
266   /* 打印HTTP响应报文 */
267   sprintf(buf, "HTTP/1.0 %s %s", errnum, shortmsg);
268   Rio_writen(fd, buf, strlen(buf));
269   sprintf(buf, "Content-type: text/html\r\n");
270   Rio_writen(fd, buf, strlen(buf));
271   sprintf(buf, "Content-length: %d\r\n\r\n", (int)strlen(body));
272   Rio_writen(fd, buf, strlen(buf));
273   Rio_writen(fd, body, strlen(body));
274 }
主程序
 1 /*
 2  * @filename:    functionLib.h
 3  * @author:      Flyuz
 4  * @date:        2018年6月25日
 5  * @description: 函数实现
 6  */
 7 
 8 #ifndef ALL_H
 9 #define ALL_H
10 
11 #include <stdio.h>
12 #include <string.h>
13 #include <stdlib.h>
14 #include <unistd.h>
15 #include <ctype.h>
16 #include <netinet/in.h>
17 #include <arpa/inet.h>
18 #include <sys/socket.h>
19 #include <sys/types.h>
20 #include <sys/wait.h>
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <signal.h>
24 #include <sys/stat.h>
25 #include <sys/mman.h>
26 
27 #define RIO_BUFSIZE 8192
28 #define    MAXLINE     8192  /* 一行最大长度 */
29 typedef struct {
30     int rio_fd;                 //内部读缓冲区描述符
31     int rio_cnt;                //内部缓冲区中未读字节数
32     char *rio_bufp;           //内部缓冲区中下一个未读的字节
33     char rio_buf[RIO_BUFSIZE];  //内部读缓冲区
34 }rio_t;                         //一个类型为rio_t的读缓冲区
35 
36 #define     MAXLINE     8192
37 #define     MAXBUF      8192
38 #define     LISTENQ     1024
39 
40 typedef struct sockaddr SA;
41 typedef void handler_t(int);
42 void unix_error(char *msg);
43 
44 /* Process control wrappers */
45 pid_t Fork();
46 void Execve(const char *filename, char *const argv[], char *const envp[]);
47 pid_t Wait(int *status);
48 
49 /* Unix I/O */
50 int Open(const char *pathname, int flags, mode_t mode);
51 void Close(int fd);
52 int Dup2(int oldfd, int newfd);
53 
54 
55 
56 void *Mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset);
57 void Munmap(void *start, size_t length);
58 
59 /* RIO package */
60 ssize_t rio_readn(int fd, void *usrbuf, size_t n);
61 ssize_t rio_writen(int fd, void *usrbuf, size_t n);
62 void rio_readinitb(rio_t *rp, int fd);
63 ssize_t rio_readlineb(rio_t *rp, void *usrbuf, size_t maxlen);
64 ssize_t rio_readnb(rio_t *rp, void *usrbuf, size_t n);
65 
66 
67 ssize_t Rio_readn(int fd, void *usrbuf, size_t n);
68 void Rio_writen(int fd, void *usrbuf, size_t n);
69 void Rio_readinitb(rio_t *rp, int fd);
70 ssize_t Rio_readlineb(rio_t *rp, void *usrbuf, size_t maxlen);
71 ssize_t Rio_readnb(rio_t *rp, void *usrbuf, size_t n);
72 
73 
74 int open_listenfd(char *port);
75 
76 int Open_listenfd(char *port);
77 
78 int Accept(int s, struct sockaddr *addr, socklen_t *addrlen);
79 
80 handler_t  *signal_r(int signum, handler_t *handler);
81 void sigchild_handler(int sig);
82 
83 #endif
头文件
  1 /*
  2  * @filename:    functionLib.c
  3  * @author:      Flyuz
  4  * @date:        2018年6月25日
  5  * @description: 辅助函数
  6  */
  7 
  8 #include "functionLib.h"
  9 
 10 void unix_error(char *msg)
 11 {
 12     fprintf(stderr, "%s: %s\n",msg, strerror(errno));
 13     exit(0);
 14 }
 15 
 16 pid_t Fork()
 17 {
 18     pid_t pid;
 19     pid = fork();
 20     if(pid < 0)
 21         unix_error("fork error");
 22     return pid;
 23 }
 24 
 25 void Execve(const char *filename, char *const argv[], char *const envp[])
 26 {
 27     if(execve(filename, argv,envp) < 0)
 28         unix_error("Execve error");
 29 }
 30 
 31 pid_t Wait(int *status)
 32 {
 33     pid_t pid;
 34 
 35     if((pid = wait(status)) < 0)
 36         unix_error("Wait error");
 37     return pid;
 38 }
 39 
 40 
 41 
 42 int Open(const char *pathname, int flags, mode_t mode)
 43 {
 44     int rc;
 45 
 46     if((rc = open(pathname, flags, mode)) < 0)
 47         unix_error("Open error");
 48     return rc;
 49 }
 50 
 51 int Accept(int s, struct sockaddr *addr, socklen_t *addrlen)
 52 {
 53     int rc;
 54 
 55     if((rc = accept(s, addr,addrlen)) < 0)
 56         unix_error("Accept error");
 57     return rc;
 58 }
 59 
 60 void Close(int fd)
 61 {
 62     int rc;
 63 
 64     if((rc = close(fd)) < 0)
 65         unix_error("Close error");
 66 }
 67 
 68 int Dup2(int oldfd, int newfd)
 69 {
 70     int rc;
 71 
 72     if((rc = dup2(oldfd, newfd)) < 0 )
 73         unix_error("Dup2 error");
 74     return rc;
 75 }
 76 
 77 
 78 void *Mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset)
 79 {
 80     void *ptr;
 81 
 82     if((ptr = mmap(addr, len, prot, flags, fd, offset)) == ((void *)-1))
 83         unix_error("Mmap error");
 84     return ptr;
 85 }
 86 
 87 void Munmap(void *start, size_t length)
 88 {
 89     if(munmap(start, length) < 0)
 90         unix_error("Munmap error");
 91 }
 92 /*
 93  * 无缓冲输入函数
 94  * 成功返回收入的字节数
 95  * 若EOF返回0 ,出错返回-1
 96  */
 97 ssize_t rio_readn(int fd, void *usrbuf, size_t n)
 98 {
 99     char *bufp = usrbuf;
100     size_t nleft = n;
101     ssize_t nread;
102     while(nleft > 0) {
103         if((nread = read(fd,bufp,nleft)) < 0) {
104             if(errno == EINTR)
105                 nread = 0;
106             else
107                 return -1;
108         } else if( nread == 0 )
109             break;
110         nleft -= nread;
111         bufp += nread;
112     }
113     return (n-nleft);
114 }
115 /*
116  * 无缓冲输出函数
117  * 成功返回输出的字节数,出错返回-1
118 */
119 ssize_t rio_writen(int fd, void *usrbuf, size_t n)
120 {
121     char *bufp = usrbuf;
122     size_t nleft = n;
123     ssize_t nwritten;
124     while(nleft > 0) {
125         if((nwritten = write(fd, bufp, nleft)) <= 0) {
126             if(errno == EINTR)
127                 nwritten = 0;
128             else
129                 return -1;
130         }
131         nleft -= nwritten;
132         bufp += nwritten;
133     }
134     return n;
135 }
136 
137 
138 static ssize_t rio_read(rio_t *rp, char *usrbuf, size_t n)
139 {
140     while(rp -> rio_cnt <= 0) {
141         rp -> rio_cnt = read(rp -> rio_fd, rp -> rio_buf,
142                 sizeof(rp -> rio_buf));
143         if(rp -> rio_cnt < 0) {
144             if(errno != EINTR)
145                 return -1;
146         } else if(rp -> rio_cnt == 0)
147             return 0;
148         else
149             rp -> rio_bufp = rp -> rio_buf;
150     }
151 
152     int cnt = rp -> rio_cnt < n ? rp -> rio_cnt : n;
153 
154     memcpy(usrbuf, rp -> rio_bufp, cnt);
155     rp -> rio_bufp += cnt;
156     rp -> rio_cnt -= cnt;
157     return cnt;
158 }
159 // 初始化rio_t结构,创建一个空的读缓冲区
160 // 将fd和地址rp处的这个读缓冲区联系起来
161 void rio_readinitb(rio_t *rp, int fd)
162 {
163     rp -> rio_fd = fd;
164     rp -> rio_cnt = 0;
165     rp -> rio_bufp = rp -> rio_buf;
166 }
167 
168 //带缓冲输入函数
169 ssize_t rio_readnb(rio_t *rp, void *usrbuf, size_t n)
170 {
171     size_t nleft = n;
172     ssize_t nread;
173     char *bufp = usrbuf;
174 
175     while(nleft > 0) {
176         if((nread = rio_read(rp, bufp, nleft)) < 0)
177             return -1;
178         else if (nread == 0)
179             break;
180 
181         nleft -= nread;
182         bufp += nread;
183     }
184     return (n-nleft);
185 }
186 /*
187 **带缓冲输入函数,每次输入一行
188 **从文件rp读出一个文本行(包括结尾的换行符),将它拷贝到usrbuf,并且用空字符来结束这个文本行
189 **最多读maxlen-1个字节,余下的一个留给结尾的空字符
190 **/
191 ssize_t rio_readlineb(rio_t *rp, void *usrbuf, size_t maxlen)
192 {
193     int n, rc;
194     char c, *bufp = usrbuf;
195     for(n = 1; n<maxlen; n++) {
196         if((rc = rio_read(rp, &c, 1)) == 1) {
197             *bufp++ = c;
198             if( c == '\n' ){
199                 n++;
200                 break;
201             }
202         } else if(rc == 0) {
203             if( n  == 1 )
204                 return 0;
205             else
206                 break;
207         } else
208             return -1;
209     }
210     *bufp = '\0';
211     return n-1;
212 }
213 
214 ssize_t Rio_readn(int fd, void *usrbuf, size_t n)
215 {
216     ssize_t nbytes;
217     if((nbytes = rio_readn(fd, usrbuf, n)) < 0)
218         unix_error("Rio_readn error");
219 
220     return nbytes;
221 }
222 
223 void Rio_writen(int fd, void *usrbuf, size_t n)
224 {
225     if(rio_writen(fd, usrbuf, n) != n)
226         unix_error("Rio_writen error");
227 }
228 
229 void Rio_readinitb(rio_t *rp, int fd)
230 {
231     rio_readinitb(rp, fd);
232 }
233 
234 ssize_t Rio_readlineb(rio_t *rp, void *usrbuf, size_t maxlen)
235 {
236     ssize_t nbytes;
237     if((nbytes = rio_readlineb(rp, usrbuf, maxlen)) < 0)
238         unix_error("Rio_readlineb error");
239     return nbytes;
240 }
241 
242 ssize_t Rio_readnb(rio_t *rp, void *usrbuf, size_t n)
243 {
244     ssize_t nbytes;
245     if((nbytes = rio_readnb(rp, usrbuf, n)) < 0)
246         unix_error("Rio_readnb error");
247     return nbytes;
248 }
249 
250 /*打开并返回监听描述符*/
251 int open_listenfd(char *port)
252 {
253     int listenfd, optval = 1;
254     struct sockaddr_in serveraddr;
255 
256     if((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
257         return -1;
258     }
259 
260     if(setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR,
261                 (const void *)&optval, sizeof(int)) < 0)
262         return -1;
263 
264     bzero((char *)&serveraddr, sizeof(serveraddr));
265 
266     serveraddr.sin_family = AF_INET;
267     serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
268     serveraddr.sin_port = htons((unsigned short)atoi(port));
269 
270     if(bind(listenfd, (SA *)&serveraddr, sizeof(serveraddr)) < 0)
271         return -1;
272 
273     if(listen(listenfd, LISTENQ) < 0)
274         return -1;
275 
276     return listenfd;
277 }
278 
279 int Open_listenfd(char *port)
280 {
281     int rc;
282     if((rc = open_listenfd(port)) < 0)
283         unix_error("open_listenfd error");
284     return rc;
285 }
286 //信号处理
287 handler_t  *signal_r(int signum, handler_t *handler)
288 {
289     struct sigaction action, old_action;
290 
291     action.sa_handler = handler;
292     sigemptyset(&action.sa_mask);
293     action.sa_flags = SA_RESTART;
294 
295     if (sigaction(signum, &action, &old_action) < 0)
296           perror("Signal error");
297     return (old_action.sa_handler);
298 }
299 //排队 防止阻塞
300 void sigchild_handler(int sig)
301 {
302     int stat;
303       while(waitpid(-1,&stat,WNOHANG)>0);
304       return;
305 }
辅助函数

猜你喜欢

转载自www.cnblogs.com/flyuz/p/9243789.html