實現簡易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 }
輔助函數

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM