[作业向]tinyhttp web服务器设计及完整代码

  最近看了《HTTP权威指南》和《UNP》有了写一个简单的web服务器的想法,正好这个学期没有什么课,所以就花了一个星期这样写了一个出来,鉴于本人水平有限,如果有什么设计或代码错误的,希望各位指出哈。

tinyhttp web服务器的架构为epoll + 多线程 + sendfile,  本来想用线程池代替的因为每来一个连接就new一个线程这样对于OS来说负担太大,并且线程一旦过多线程切换就会花费很大代价造成性能瓶颈,但是我打算之后单独写一个线程池代码示例的说,所以这个版本就使用多线程来代替线程池了。

tinyhttp暂时只支持GET和HEAD方法,支持的首部不多大概七八个吧,支持伪长连接(我觉得是伪的哈哈)。

话不多说,先上几张效果图吧:

这张是测试http请求和响应包的

[作业向]tinyhttp web服务器设计及完整代码_第1张图片 

这张是自己构造了一个包来收发的

[作业向]tinyhttp web服务器设计及完整代码_第2张图片

这张是我把google首页的源代码拿来测试的

[作业向]tinyhttp web服务器设计及完整代码_第3张图片

这张是我自己写了一个html代码使用火狐浏览器来与的我tinyhttp web服务其通信的测试

[作业向]tinyhttp web服务器设计及完整代码_第4张图片

我的tinyhttp是可配置的,现阶段只支持domain和docroot配置项,domain就是你部署的网站域名,docroot想必学过网页的都知道是什么意思吧~

 

好了,现在就把完整的源代码给出,总共有1500+行:

  1 /*
  2 *Author        Zou Xiao hang
  3 *Email        [email protected]
  4 *File Name    tinyhttp.h
  5 *Date         2013/10/05
  6 */
  7 #ifndef _TINY_HTTP_H_
  8 #define    _TINY_HTTP_H_
  9 
 10 #include <sys/socket.h>
 11 #include <sys/types.h>
 12 #include <stdlib.h>
 13 #include <stdio.h>
 14 #include <netdb.h>
 15 #include <sys/epoll.h>
 16 #include <strings.h>
 17 #include <string>
 18 #include <errno.h>
 19 #include <unistd.h>
 20 #include <fcntl.h>
 21 #include <utility>
 22 #include <fstream>
 23 #include <sstream>
 24 #include <map>
 25 #include <iostream>
 26 #include <string.h>
 27 #include <pthread.h>
 28 #include <netinet/tcp.h>
 29 #include <time.h>
 30 #include <sys/stat.h>
 31 #include <sys/sendfile.h>
 32 
 33 #include "utility.h"
 34 #include "parse.h"
 35 
 36 using namespace std;
 37 
 38 typedef struct _epollfd_connfd
 39 {
 40     int epollfd;
 41     int connfd;
 42 }_epollfd_connfd;
 43 
 44 /***********************************  常数定义  
 45 *******************************************/
 46 #define MAX_EVENTS    1024    //epoll最大监听事件数
 47 #define MAX_BACKLOG    100        //监听队列最大数
 48 /******************************************************************************
 49 ***********/
 50 
 51 /***********************************  保存配置文件相关值  
 52 *********************************/
 53 string tyhp_domain("");
 54 string tyhp_docroot(""); 
 55 /******************************************************************************
 56 ***********/
 57 
 58 /***********************************  MIME定义  
 59 *******************************************/
 60 typedef struct mime_node
 61 {
 62     const char *type;
 63     const char *value;
 64 }mime_node;
 65 
 66 mime_node tyhp_mime[] = 
 67 {
 68     {".html", "text/html"},
 69     {".xml", "text/xml"},
 70     {".xhtml", "application/xhtml+xml"},
 71     {".txt", "text/plain"},
 72     {".rtf", "application/rtf"},
 73     {".pdf", "application/pdf"},
 74     {".word", "application/msword"},
 75     {".png", "image/png"},
 76     {".gif", "image/gif"},
 77     {".jpg", "image/jpeg"},
 78     {".jpeg", "image/jpeg"},
 79     {".au", "audio/basic"},
 80     {".mpeg", "video/mpeg"},
 81     {".mpg", "video/mpeg"},
 82     {".avi", "video/x-msvideo"},
 83     {".gz", "application/x-gzip"},
 84     {".tar", "application/x-tar"},
 85     {NULL ,NULL}
 86 };
 87 /*
 88  *函数作用:将MIME的type转换为相应的value
 89  *函数参数:type
 90  *函数返回值: NULL表示type在MIME中不存在,否则返回相应value的指针
 91  */
 92 inline const char* tyhp_mime_type2value(const char *type)
 93 {
 94     for(int i = 0; tyhp_mime[i].type != NULL; ++i)
 95     {
 96         if(strcmp(type, tyhp_mime[i].type) == 0)
 97             return tyhp_mime[i].value;
 98     }
 99     return NULL;
100 }
101 /******************************************************************************
102 ***********/
103 
104 /***********************************  HTTP状态码  
105 *******************************************/
106 #define TYHP_CONTINUE         100    //收到了请求的起始部分,客户端应该继续请求
107 
108 #define TYHP_OK                200    //服务器已经成功处理请求
109 #define TYHP_ACCEPTED        202    //请求已接受,服务器尚未处理
110 
111 #define TYHP_MOVED            301    //请求的URL已移走,响应应该包含Location URL
112 #define    TYHP_FOUND            302    //请求的URL临时移走,响应应该包含Location URL
113 #define TYHP_SEEOTHER        303    //告诉客户端应该用另一个URL获取资源,响应应该包含
114 Location URL
115 #define TYHP_NOTMODIFIED    304    //资源未发生变化
116 
117 #define TYHP_BADREQUEST        400    //客户端发送了一条异常请求
118 #define TYHP_FORBIDDEN        403    //服务器拒绝请求
119 #define TYHP_NOTFOUND        404    //URL未找到
120 
121 
122 #define TYHP_ERROR            500    //服务器出错
123 #define TYHP_NOIMPLEMENTED    501 //服务器不支持当前请求所需要的某个功能
124 #define TYHP_BADGATEWAY        502    
125 //作为代理或网关使用的服务器遇到了来自响应链中上游的无效响应
126 #define TYHP_SRVUNAVAILABLE    503 
127 //服务器目前无法提供请求服务,过一段时间后可以恢复
128 
129 char tyhp_ok[] =             "OK";
130 char tyhp_badrequest[] =     "Bad Request";
131 char tyhp_forbidden[] =        "Forbidden";
132 char tyhp_notfound[] =         "Not Found";
133 char tyhp_noimplemented[] =     "No Implemented";
134 
135 /*
136  *函数作用:通过HTTP状态码返回友好语句
137  *函数参数:HTTP状态码
138  *函数返回值: 相应的语句
139  */
140 char *tyhp_get_state_by_codes(int http_codes);
141 /******************************************************************************
142 ************/
143 
144 /***********************************  HTTP响应首部  
145 *******************************************/
146 #define TYHP_ACCEPTRANGE_HEAD            "Accpet-Range"
147 #define    TYHP_AGE_HEAD                     "Age"
148 #define    TYHP_ALLOW_HEAD                    "Allow"
149 #define    TYHP_CONTENTBASE_HEAD            "Content-Base"
150 #define    TYHP_CONTENTLENGTH_HEAD            "Content-Length"
151 #define    TYHP_CONTENTLOCATION_HEAD        "Content-Location"
152 #define    TYHP_CONTENTRANGE_HEAD            "Content-Range"
153 #define    TYHP_CONTENTTYPE_HEAD            "Content-Type"
154 #define    TYHP_DATE_HEAD                    "Date"
155 #define    TYHP_EXPIRES_HEAD                "Expires"
156 #define    TYHP_LAST_MODIFIED_HEAD            "Last-Modified"
157 #define    TYHP_LOCATION_HEAD                 "Location"
158 #define    TYHP_PUBLIC_HEAD                "Public"
159 #define TYHP_RANGE_HEAD                 "Range"
160 #define    TYHP_SERVER_HEAD                "Server"
161 /******************************************************************************
162 ************/
163 /***********************************  HTTP请求首部  
164 *******************************************/
165 //#define TYHP
166 /******************************************************************************
167 ************/
168 
169 #endif
  1 /*
  2 *Author        Zou Xiao hang
  3 *Email        [email protected]
  4 *File Name    tinyhttp.cpp
  5 *Date         2013/10/05
  6 */
  7 #include "tinyhttp.h"    
  8 
  9 #define ONEKILO        1024
 10 #define ONEMEGA        1024*ONEKILO
 11 #define ONEGIGA        1024*ONEMEGA
 12 
 13 /***********************************  线程相关  *******************************************/
 14 /*
 15  *函数作用:处理客户端链接的线程例程
 16  *函数参数:param为客户conn_sock
 17  *函数返回值: 无
 18  */
 19 void* tyhp_thread_func(void *param);
 20 
 21 
 22 //记录当前处理线程的数量
 23 int32_t tyhp_thread_num = 0;
 24 pthread_mutex_t tyhp_thread_num_mutex = PTHREAD_MUTEX_INITIALIZER;
 25 /*
 26  *函数作用:tyhp_thread_num原子加1
 27  *函数参数:无
 28  *函数返回值: 无
 29  */
 30 void tyhp_thread_num_add1();
 31 /*
 32  *函数作用:tyhp_thread_num原子减1
 33  *函数参数:无
 34  *函数返回值: 无
 35  */
 36 void tyhp_thread_num_minus1();
 37 /*
 38  *函数作用:tyhp_thread_num原子读
 39  *函数参数:无
 40  *函数返回值: tyhp_thread_num当前值
 41  */
 42  int32_t tyhp_thread_num_read();
 43 /*****************************************************************************************/
 44 
 45 /********************************  tyhp_http_header_t处理函数  *********************************/
 46  /*
 47  *函数作用:根据解析下来的tyhp_http_header_t来处理客户的请求
 48  *函数参数:  phttphdr指向要处理的tyhp_http_header_t
 49              out保存了处理的结果,即http响应包
 50  *函数返回值: HTTP状态码
 51  */
 52 int tyhp_do_http_header(tyhp_http_header_t *phttphdr, string& out);
 53 /*
 54  *函数作用:通过HTTP状态码返回友好语句
 55  *函数参数:HTTP状态码
 56  *函数返回值: 相应的语句
 57  */
 58 char *tyhp_get_state_by_codes(int http_codes);
 59 /*****************************************************************************************/
 60 
 61 /***********************************  web服务器程序入口函数  ***************************************/
 62 int main(int argc, char const *argv[])
 63 {
 64     int                 listen_fd;
 65     int                 conn_sock; 
 66     int                 nfds;
 67     int                 epollfd;
 68     uint16_t             listen_port;
 69     struct servent         *pservent;
 70     struct epoll_event     ev;
 71     struct epoll_event    events[MAX_EVENTS];
 72     struct sockaddr_in     server_addr;
 73     struct sockaddr_in    client_addr;
 74     socklen_t             addrlen;
 75     pthread_attr_t        pthread_attr_detach;
 76     _epollfd_connfd     epollfd_connfd;
 77     pthread_t             tid;
 78 
 79     if(argc != 2)
 80     {
 81         printf("Usage: %s <config_path>\n", argv[0]);
 82         exit(-1);
 83     }
 84     //判断配置文件是否存在
 85     if(-1 == tyhp_is_file_existed(argv[1]))
 86     {
 87         perror("tyhp_is_file_existed");
 88         exit(-1);
 89     }
 90     //调用tyhp_parse_config解析配置文件
 91     if(-1 == tyhp_parse_config(argv[1]))
 92     {
 93         printf("tyhp_parse_config error\n");
 94         exit(-1);
 95     }
 96 
 97     //创建监听套接字
 98     listen_fd = tyhp_socket(AF_INET, SOCK_STREAM, 0);
 99     //设置监听套接字为非阻塞模式
100     tyhp_set_nonblocking(listen_fd);
101     //对监听套接字设置SO_REUSEADDR选项
102     tyhp_set_reuse_addr(listen_fd);
103     //通过服务名和协议名获得相应的知名端口,其实可以直接设置端口为80,我们这样做是为了可扩展性
104     pservent = tyhp_getservbyname("http", "tcp");
105     //pservent->s_port已经是网络字节序了
106     listen_port = pservent->s_port;
107     
108     bzero(&server_addr, sizeof(server_addr));
109     server_addr.sin_family = AF_INET;
110     server_addr.sin_port = (listen_port);
111     server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
112 
113     //将服务器sockaddr_in与监听套接字绑定
114     tyhp_bind(listen_fd, (struct sockaddr*)&server_addr, sizeof(server_addr));
115     //开始监听
116     tyhp_listen(listen_fd, MAX_BACKLOG);
117     
118     //创建epoll文件描述符
119     epollfd = tyhp_epoll_create(MAX_EVENTS);
120     
121     ev.events = EPOLLIN;//可读事件
122     ev.data.fd = listen_fd;
123     //将监听事件加入epoll中
124     tyhp_epoll_ctl(epollfd, EPOLL_CTL_ADD, listen_fd, &ev);
125 
126     //设置线程属性为detach
127     pthread_attr_init(&pthread_attr_detach);
128     pthread_attr_setdetachstate(&pthread_attr_detach, PTHREAD_CREATE_DETACHED);
129         
130     for(;;)
131     {
132         //无限等待直到有描述符就绪
133         nfds = tyhp_epoll_wait(epollfd, events, MAX_EVENTS, -1);
134         //若tyhp_epoll_wait被中断则重新调用该函数
135         if(nfds == -1 && errno == EINTR)
136             continue;
137             
138         for(int n = 0; n != nfds; ++n)
139         {
140             //处理监听套接字触发的事件
141             if(events[n].data.fd == listen_fd)
142             {
143                 conn_sock = tyhp_accept(listen_fd, (struct sockaddr*)&client_addr, &addrlen);
144                 //设置新链接上的套接字为非阻塞模式
145                 tyhp_set_nonblocking(conn_sock);
146                 //设置读事件和ET模式
147                 ev.events = EPOLLIN | EPOLLET;
148                 ev.data.fd = conn_sock;
149                 //将监听事件加入epoll中
150                 tyhp_epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock, &ev);
151             }
152             else
153             {
154                 epollfd_connfd.epollfd = epollfd;
155                 epollfd_connfd.connfd = events[n].data.fd;
156                 ev.data.fd = conn_sock;
157                 //epoll不再监听这个客户端套接字
158                 tyhp_epoll_ctl(epollfd, EPOLL_CTL_DEL, conn_sock, &ev);
159                 //处理链接
160                 pthread_create(&tid, &pthread_attr_detach, &tyhp_thread_func, (void*)&epollfd_connfd);
161                 //tyhp_thread_func((void*)&epollfd_connfd);
162                 //close(conn_sock);
163             }
164         }
165     }
166     //清理工作
167     pthread_attr_destroy(&pthread_attr_detach);
168 
169     //关闭监听套接字
170     close(listen_fd);
171     return 0;
172 }
173 /*****************************************************************************************/
174 
175 /***********************************  线程相关  *******************************************/
176 /*
177  *函数作用:处理客户端链接的线程例程
178  *函数参数:
179  *函数返回值: NULL
180  */
181  #define TIMEOUT    1000*60*4 //设置超时 milliseconds
182 void* tyhp_thread_func(void *param)
183 {
184     tyhp_thread_num_add1();
185 
186     tyhp_http_header_t *phttphdr = tyhp_alloc_http_header();
187 
188     _epollfd_connfd *ptr_epollfd_connfd = (_epollfd_connfd*)param;
189     //int epollfd = ptr_epollfd_connfd->epollfd;
190     //获取客户连接socket
191     int conn_sock = ptr_epollfd_connfd->connfd;
192 
193     struct epoll_event ev, events[2];
194     ev.events = EPOLLIN | EPOLLET;
195     ev.data.fd = conn_sock;
196     //针对客户链接的新epollfd
197     int epollfd = tyhp_epoll_create(2);
198     tyhp_epoll_ctl(epollfd, EPOLL_CTL_ADD, ev.data.fd, &ev);
199     int nfds = 0;
200 
201     pthread_t tid = pthread_self();
202     printf("NO.%u thread runs now !!!\n", (unsigned int)tid);
203     
204     //Nginx默认http请求包大小为1M,所以我也分配1M缓存来存http请求包
205     char *buff = (char*)tyhp_malloc(ONEMEGA);
206     bzero(buff, ONEMEGA);
207 
208     //关闭connfd的Nagle算法
209     tyhp_set_off_tcp_nagle(conn_sock);
210     //设置接收超时时间为60秒
211     tyhp_set_recv_timeo(conn_sock, 60, 0);
212     //设置发送超时时间为120秒
213     //tyhp_set_snd_timeo(connfd, 120, 0);
214 begin:
215     int32_t nread = 0, n = 0;
216     for(;;)
217     {    
218         if((n = read(conn_sock, buff+nread, ONEMEGA-1)) > 0)
219             nread += n;
220         else if(0 == n)
221             break;
222         else if(-1 == n && errno == EINTR)
223             continue;
224         else if(-1 == n && errno == EAGAIN)
225             break;
226         else if(-1 == n && errno == EWOULDBLOCK)
227         {
228             perror("socket read timeout");
229             goto out;
230         }
231         else
232         {
233             perror("read http request error");
234             tyhp_free(buff);
235             break;
236         }
237         
238     }
239 
240     if(0 != nread)
241     {
242         string str_http_request(buff, buff + nread);
243 
244         //do_something(str_http_request);
245         if(!tyhp_parse_http_request(str_http_request, phttphdr))
246         {
247             perror("tyhp_parse_http_request: parse str_http_request failed");
248             goto out;
249         }
250         cout<<"解析出来的http请求包:"<<endl;
251         tyhp_print_http_header(phttphdr);
252 
253         string out;
254         int http_codes = tyhp_do_http_header(phttphdr, out);
255 
256         /****** debug *****/
257         cout<<"http响应包:"<<endl<<out<<endl;
258 
259         char *out_buf = (char *)tyhp_malloc(out.size());
260         if(out_buf == NULL)
261             goto out;
262         int i;
263         for(i = 0; i != out.size(); ++i)
264             out_buf[i] = out[i];
265         out_buf[i] = '\0';
266         int nwrite = 0; n = 0;
267         if( http_codes == TYHP_BADREQUEST         || 
268             http_codes == TYHP_NOIMPLEMENTED     ||
269             http_codes == TYHP_NOTFOUND         ||
270             (http_codes == TYHP_OK && phttphdr->method == "HEAD"))
271         {
272             while((n = write(conn_sock, out_buf + nwrite, i)) != 0)
273             {
274                 if(n == -1 && errno == EINTR)
275                     continue;
276                 else
277                     goto out;
278                 nwrite += n;
279             }
280         }
281         if(http_codes == TYHP_OK)
282         {
283             if(phttphdr->method == "GET")
284             {
285                 while((n = write(conn_sock, out_buf + nwrite, i)) != 0)
286                 {
287                     cout<<n<<endl;
288                     if(n == -1 && errno == EINTR)
289                         continue;
290                     else
291                         break;
292                     nwrite += n;
293                 }
294                 string real_url = tyhp_make_real_url(phttphdr->url);
295                 int fd = open(real_url.c_str(), O_RDONLY);
296                 int file_size = tyhp_get_file_length(real_url.c_str());
297                 cout<<"file size "<<file_size<<endl;
298                 int nwrite = 0;
299                 cout<<"sendfile : "<<real_url.c_str()<<endl;
300             again:
301                 if((sendfile(conn_sock, fd, (off_t*)&nwrite, file_size)) < 0)
302                     perror("sendfile");
303                 if(nwrite < file_size)
304                     goto again;
305                 cout<<"sendfile ok:"<<nwrite<<endl;
306             }
307         }
308         free(out_buf);
309         //超时4分钟
310         nfds = tyhp_epoll_wait(epollfd, events, 2, TIMEOUT);
311         if(0 == nfds)//timeout
312             goto out;
313         for(int i = 0; i < nfds; ++i)
314         {
315             if(events[i].data.fd == conn_sock)
316                 goto begin;
317             else
318                 goto out;
319         }
320     }
321 
322 out:
323     tyhp_free_http_header(phttphdr);
324     close(conn_sock);
325     tyhp_thread_num_minus1();
326     printf("NO.%u thread ends now ~~~\n", (unsigned int)tid);
327 }
328 
329 /*
330  *函数作用:tyhp_thread_num原子加1
331  *函数参数:无
332  *函数返回值: 无
333  */
334 void tyhp_thread_num_add1()
335 {
336     pthread_mutex_lock(&tyhp_thread_num_mutex);
337     ++tyhp_thread_num;
338     pthread_mutex_unlock(&tyhp_thread_num_mutex);
339 }
340 /*
341  *函数作用:tyhp_thread_num原子减1
342  *函数参数:无
343  *函数返回值: 无
344  */
345 void tyhp_thread_num_minus1()
346 {
347     pthread_mutex_lock(&tyhp_thread_num_mutex);
348     --tyhp_thread_num;
349     pthread_mutex_unlock(&tyhp_thread_num_mutex);
350 }
351 /*
352  *函数作用:tyhp_thread_num原子读
353  *函数参数:无
354  *函数返回值: tyhp_thread_num当前值
355  */
356  int32_t tyhp_thread_num_read();
357  /*****************************************************************************************/
358 
359  /********************************  tyhp_http_header_t处理函数  *********************************/
360  /*
361  *函数作用:根据解析下来的tyhp_http_header_t来处理客户的请求
362  *函数参数:  phttphdr指向要处理的tyhp_http_header_t
363              out保存了处理的结果,即http响应包
364  *函数返回值: HTTP状态码
365 
366  *目前支持的请求首部:
367  *目前支持的响应首部:Date,Content-Base,Content-Length,Content-Location
368                          Last-Modified,Public,Server
369  */
370 int tyhp_do_http_header(tyhp_http_header_t *phttphdr, string& out)
371 {
372     char status_line[256] = {0};
373     string crlf("\r\n");
374     string server("Server: tinyhttp\r\n");
375     string Public("Public: GET, HEAD\r\n");
376     string content_base = "Content-Base: " + tyhp_domain + crlf;
377     string date = "Date:" + tyhp_time_gmt() + crlf;
378 
379     string content_length("Content-Length: ");
380     string content_location("Content-Location: ");
381     string last_modified("Last-Modified: ");
382     //string body("");
383 
384     if(phttphdr == NULL)
385     {
386         snprintf(status_line, sizeof(status_line), "HTTP/1.1 %d %s\r\n", 
387             TYHP_BADREQUEST, tyhp_get_state_by_codes(TYHP_BADREQUEST));
388         out = status_line + crlf;
389         return TYHP_BADREQUEST;
390     }
391 
392     string method = phttphdr->method;
393     string real_url = tyhp_make_real_url(phttphdr->url);
394     string version = phttphdr->version;
395     if(method == "GET" || method == "HEAD")
396     {
397         if(tyhp_is_file_existed(real_url.c_str()) == -1)
398         {
399             snprintf(status_line, sizeof(status_line), "HTTP/1.1 %d %s\r\n", 
400                 TYHP_NOTFOUND, tyhp_get_state_by_codes(TYHP_NOTFOUND));
401             out += (status_line + server + date + crlf); 
402             return TYHP_NOTFOUND;
403         }
404         else
405         {
406             int len = tyhp_get_file_length(real_url.c_str());
407             snprintf(status_line, sizeof(status_line), "HTTP/1.1 %d %s\r\n", 
408                 TYHP_OK, tyhp_get_state_by_codes(TYHP_OK));
409             out += status_line;
410             snprintf(status_line, sizeof(status_line), "%d\r\n", len);
411             out += content_length + status_line;
412             out += server + content_base + date;
413             out += last_modified + tyhp_get_file_modified_time(real_url.c_str()) + crlf + crlf;
414         }
415     }
416     else if(method == "PUT")
417     {
418         snprintf(status_line, sizeof(status_line), "HTTP/1.1 %d %s\r\n", 
419                 TYHP_NOIMPLEMENTED, tyhp_get_state_by_codes(TYHP_NOIMPLEMENTED));
420         out += status_line + server + Public + date + crlf;
421         return TYHP_NOIMPLEMENTED;
422     }
423     else if(method == "DELETE")
424     {
425         snprintf(status_line, sizeof(status_line), "HTTP/1.1 %d %s\r\n", 
426                 TYHP_NOIMPLEMENTED, tyhp_get_state_by_codes(TYHP_NOIMPLEMENTED));
427         out += status_line + server + Public + date + crlf;
428         return TYHP_NOIMPLEMENTED;
429     }
430     else if(method == "POST")
431     {
432         snprintf(status_line, sizeof(status_line), "HTTP/1.1 %d %s\r\n", 
433                 TYHP_NOIMPLEMENTED, tyhp_get_state_by_codes(TYHP_NOIMPLEMENTED));
434         out += status_line + server + Public + date + crlf;
435         return TYHP_NOIMPLEMENTED;
436     }
437     else
438     {
439         snprintf(status_line, sizeof(status_line), "HTTP/1.1 %d %s\r\n", 
440             TYHP_BADREQUEST, tyhp_get_state_by_codes(TYHP_BADREQUEST));
441         out = status_line + crlf;
442         return TYHP_BADREQUEST;
443     }
444 
445     return TYHP_OK;
446 }
447 /*
448 #define TYHP_CONTINUE         100    //收到了请求的起始部分,客户端应该继续请求
449 
450 #define TYHP_OK                200    //服务器已经成功处理请求
451 #define TYHP_ACCEPTED        202    //请求已接受,服务器尚未处理
452 
453 #define TYHP_MOVED            301    //请求的URL已移走,响应应该包含Location URL
454 #define    TYHP_FOUND            302    //请求的URL临时移走,响应应该包含Location URL
455 #define TYHP_SEEOTHER        303    //告诉客户端应该用另一个URL获取资源,响应应该包含Location URL
456 #define TYHP_NOTMODIFIED    304    //资源未发生变化
457 
458 #define TYHP_BADREQUEST        400    //客户端发送了一条异常请求
459 #define TYHP_FORBIDDEN        403    //服务器拒绝请求
460 #define TYHP_NOTFOUND        404    //URL未找到
461 
462 #define TYHP_ERROR            500    //服务器出错
463 #define TYHP_NOIMPLEMENTED    501 //服务器不支持当前请求所需要的某个功能
464 #define TYHP_BADGATEWAY        502    //作为代理或网关使用的服务器遇到了来自响应链中上游的无效响应
465 #define TYHP_SRVUNAVAILABLE    503 //服务器目前无法提供请求服务,过一段时间后可以恢复
466 
467 /*
468  *函数作用:通过HTTP状态码返回友好语句
469  *函数参数:HTTP状态码
470  *函数返回值: 相应的语句
471  */
472 char *tyhp_get_state_by_codes(int http_codes)
473 {
474     switch (http_codes)
475     {
476         case TYHP_OK:
477             return tyhp_ok;
478         case TYHP_BADREQUEST:
479             return tyhp_badrequest;
480         case TYHP_FORBIDDEN:
481             return tyhp_forbidden;
482         case TYHP_NOTFOUND:
483             return tyhp_notfound;
484         case TYHP_NOIMPLEMENTED:
485             return tyhp_noimplemented;
486         default:
487             break;
488     }
489 
490     return NULL;
491 }
492 /*****************************************************************************************/
 1 /*
 2 *Author        Zou Xiao hang
 3 *Email        [email protected]
 4 *File Name    parse.cpp
 5 *Date         2013/10/05
 6 */
 7 #include <stdlib.h>
 8 #include <stdio.h>
 9 #include <string>
10 #include <map>
11 #include <utility>
12 #include <sstream>
13 #include <ctype.h>
14 #include <iostream>
15 
16 using namespace std;
17 
18 typedef map<string, string>     tyhp_header;
19 
20 //#define string::npos            REQUEST_END
21 #define make_tyhp_header(key, value)    \
22             make_pair((key), (value))    
23 
24 //保存从http request解析下来的值
25 typedef struct _tyhp_http_header_t
26 {
27     string         method;
28     string         url;
29     string        version;
30 
31     tyhp_header header;
32 
33     string     body;
34 }tyhp_http_header_t;
35 
36 /*
37  *函数作用:打印tyhp_http_header_t里的header
38  *函数参数:tyhp_header 的const 引用
39  *函数返回值: 无
40  */
41  void tyhp_print_http_header_header(const tyhp_header& head);
42 /*
43  *函数作用:打印tyhp_http_header_t
44  *函数参数:tyhp_http_header_t指针
45  *函数返回值: 无
46  */
47  void tyhp_print_http_header(tyhp_http_header_t *phttphdr);
48 
49 /*
50  *函数作用:分配内存给tyhp_http_header_t
51  *函数参数:无
52  *函数返回值: NULL表示分配失败,其他值表示成功
53  */
54 tyhp_http_header_t *tyhp_alloc_http_header();
55 /*
56  *函数作用:回收分配给tyhp_http_header_t的内存
57  *函数参数:tyhp_http_header_t指针
58  *函数返回值: 无
59  */
60 void tyhp_free_http_header(tyhp_http_header_t *phttphdr);
61 /*
62  *函数作用:解析http_request
63  *函数参数:http_request为待解析的值,phttphdr保存了解析下来的值
64  *函数返回值: true表示解析成功,false表示解析失败
65  */
66 bool tyhp_parse_http_request(const string& http_request, tyhp_http_header_t *phttphdr);
67 /*
68  *函数作用:根据key的值在phttphdr所指向的tyhp_http_header_t中查找相对应的值
69  *函数参数:key为关键字,header
70  *函数返回值: -返回空值表示查找失败,否则返回相应的值
71  */
72 string tyhp_get_value_from_http_header(const string& key, const tyhp_header& header);
  1 /*
  2 *Author        Zou Xiao hang
  3 *Email        [email protected]
  4 *File Name    parse.h
  5 *Date         2013/10/05
  6 */
  7 #include "parse.h"
  8 
  9 /*
 10  *函数作用:打印tyhp_http_header_t里的header
 11  *函数参数:tyhp_header 的const 引用
 12  *函数返回值: 无
 13  */
 14  void tyhp_print_http_header_header(const tyhp_header& head)
 15  {
 16      if(!head.empty())
 17      {
 18          tyhp_header::const_iterator cit = head.begin();
 19          while(cit != head.end())
 20          {
 21              cout<<cit->first<<":"<<cit->second<<endl;
 22              ++cit;
 23          }
 24      }
 25  }
 26 /*
 27  *函数作用:打印tyhp_http_header_t
 28  *函数参数:tyhp_http_header_t指针
 29  *函数返回值: 无
 30  */
 31  void tyhp_print_http_header(tyhp_http_header_t *phttphdr)
 32  {
 33      if(NULL == phttphdr)
 34      {
 35          perror("phttphdr == NULL");
 36          return ;
 37      }
 38 
 39      cout<<phttphdr->method<<" "<<phttphdr->url<<" "<<phttphdr->version<<endl;
 40     tyhp_print_http_header_header(phttphdr->header);
 41     cout<<endl<<phttphdr->body<<endl;
 42  }
 43 
 44 
 45 /*
 46  *函数作用:分配内存给tyhp_http_header_t
 47  *函数参数:无
 48  *函数返回值: NULL表示分配失败,其他值表示成功
 49  */
 50 tyhp_http_header_t *tyhp_alloc_http_header()
 51 {
 52     tyhp_http_header_t *phttphdr = (tyhp_http_header_t *)new tyhp_http_header_t;
 53     if(phttphdr == NULL)
 54     {
 55         perror("tyhp_alloc_http_header");
 56         exit(-1);
 57     }
 58     return phttphdr;
 59 }
 60 
 61 /*
 62  *函数作用:回收分配给tyhp_http_header_t的内存
 63  *函数参数:tyhp_http_header_t指针
 64  *函数返回值: 无
 65  */
 66 void tyhp_free_http_header(tyhp_http_header_t *phttphdr)
 67 {
 68     if(phttphdr == NULL)
 69         return ;
 70     delete phttphdr;
 71 }
 72 
 73 /*
 74  *函数作用:解析http_request
 75  *函数参数:http_request为待解析的值,phttphdr保存了解析下来的值
 76  *函数返回值: true表示解析成功,false表示解析失败
 77  */
 78 bool tyhp_parse_http_request(const string& http_request, tyhp_http_header_t *phttphdr)
 79 {
 80     if(http_request.empty())
 81     {
 82         perror("tyhp_parse_http_request: http_request is empty");
 83         return false;
 84     }
 85     if(phttphdr == NULL)
 86     {
 87         perror("tyhp_parse_http_request: phttphdr is NULL");
 88         return false;
 89     }
 90 
 91     string crlf("\r\n"), crlfcrlf("\r\n\r\n");
 92     int prev = 0, next = 0;
 93 
 94     //解析http请求包的起始行
 95     if((next = http_request.find(crlf, prev)) != string::npos)
 96     {
 97         string first_line(http_request.substr(prev, next - prev));
 98         prev = next;
 99         stringstream sstream(first_line);
100         sstream >> (phttphdr->method);
101         sstream >> (phttphdr->url);
102         sstream >> (phttphdr->version);
103     }
104     else
105     {
106         perror("tyhp_parse_http_request: http_request has not a \\r\\n");
107         return false;
108     }
109 
110     //查找"\r\n\r\n"的位置
111     int pos_crlfcrlf = http_request.find(crlfcrlf, prev);
112     if(pos_crlfcrlf == string::npos)
113     {
114         perror("tyhp_parse_http_request: http_request has not a \"\r\n\r\n\"");
115         return false;
116     }
117 
118     //解析首部行
119     string buff, key, value;
120     while(1)
121     {
122         next = http_request.find(crlf, prev+2);
123         
124         //如果找到的next不超过"\r\n\r\n"的位置
125         if(next <= pos_crlfcrlf)
126         {
127             //buff保存了一行
128             buff = http_request.substr(prev + 2, next - prev - 2);
129             int end = 0;
130             //跳过前置空白符,到达首部关键字的起始位置
131             for(; isblank(buff[end]); ++end)
132                 ;
133             int beg = end;
134             //到达首部关键字的结束位置
135             for(; buff[end] != ':' && !isblank(buff[end]); ++end)
136                 ;
137             key = buff.substr(beg, end - beg);
138             //跳至首部值的起始位置
139             for(; (!isalpha(buff[end]) && !isdigit(buff[end])); ++end)
140                 ;
141             beg = end;
142             //到达首部值的结束位置
143             for(; next != end; ++end)
144                 ;
145             value = buff.substr(beg, end - beg);
146             phttphdr->header.insert(make_tyhp_header(key, value));
147 
148             prev = next;
149         }
150         else
151         {
152             break;
153         }
154     }
155 
156     //获取http请求包的实体值(一般情况下不存在)
157     phttphdr->body = http_request.substr(pos_crlfcrlf + 4, http_request.size() - pos_crlfcrlf - 4);
158 
159     return true;
160 }
161 
162 /*
163  *函数作用:根据key的值在phttphdr所指向的tyhp_http_header_t中查找相对应的值
164  *函数参数:key为关键字,header
165  *函数返回值: -返回空值表示查找失败,否则返回相应的值
166  */
167 string tyhp_get_value_from_http_header(const string& key, const tyhp_header& header)
168 {
169     if(header.empty())
170         return "";
171     tyhp_header::const_iterator cit = header.find(key);
172     if(cit == header.end())
173         return "";
174     return (*cit).second;
175 }
  1 /*
  2 *Author        Zou Xiao hang
  3 *Email        [email protected]
  4 *File Name    utility.h
  5 *Date         2013/10/05
  6 */
  7 #ifndef _UTILITY_H_
  8 #define _UTILITY_H_
  9 
 10 #include <sys/socket.h>
 11 #include <sys/types.h>
 12 #include <stdlib.h>
 13 #include <stdio.h>
 14 #include <netdb.h>
 15 #include <sys/epoll.h>
 16 #include <strings.h>
 17 #include <string>
 18 #include <errno.h>
 19 #include <unistd.h>
 20 #include <fcntl.h>
 21 #include <utility>
 22 #include <fstream>
 23 #include <sstream>
 24 #include <map>
 25 #include <iostream>
 26 #include <string.h>
 27 #include <pthread.h>
 28 #include <netinet/tcp.h>
 29 #include <time.h>
 30 #include <sys/stat.h>
 31 
 32 using namespace std;
 33 
 34 extern string tyhp_docroot;
 35 #define TYHP_DOCROOT    1
 36 extern string tyhp_domain;
 37 #define TYHP_DOMAIN     2
 38 
 39 /***********************************  项目实用工具函数  *******************************************/
 40 /*
 41  *函数作用:得到系统时间
 42  *函数参数:无
 43  *函数返回值: 系统时间 例如:Fri, 22 May 2009 06:07:21 GMT
 44  */
 45 string tyhp_time_gmt();
 46 /*
 47  *函数作用:根据http请求包中的url和配置文件中的docroot配置选项构造真正的url
 48  *函数参数:url
 49  *函数返回值: 真正的url(绝对路径)
 50  */
 51 string tyhp_make_real_url(const string& url);
 52 /*
 53  *函数作用:测试文件是否存在
 54  *函数参数:path为绝对路径+文件名
 55  *函数返回值: -1表示文件不存在,其他值表示文件存在
 56  */
 57 inline int tyhp_is_file_existed(const char *path)
 58 {
 59     int ret = open(path, O_RDONLY | O_EXCL);
 60     close(ret);
 61     return ret;
 62 }
 63 /*
 64  *函数作用:获得文件长度
 65  *函数参数:path为绝对路径+文件名
 66  *函数返回值: 文件长度
 67  */
 68 int tyhp_get_file_length(const char *path);
 69  /*
 70  *函数作用:获得文件最后修改时间
 71  *函数参数:path为绝对路径+文件名
 72  *函数返回值: 文件最后修改时间
 73  */
 74  string tyhp_get_file_modified_time(const char *path);
 75  /*
 76  *函数作用:初始化全局变量tyhp_config_keyword_map,必须在使用tyhp_config_keyword_map前调用此函数
 77  *函数参数:无
 78  *函数返回值: 无
 79  */
 80  void tyhp_init_config_keyword_map();
 81 /*
 82  *函数作用:解析配置文件
 83  *函数参数:path为绝对路径+文件名
 84  *函数返回值: -1表示解析失败,0代表解析成功
 85  */
 86  int tyhp_parse_config(const char *path);
 87  /*
 88  *函数作用:设置文件描述符为非阻塞模式
 89  *函数参数:要设置的描述符
 90  *函数返回值: 无
 91  */
 92  void tyhp_set_nonblocking(int fd);
 93  /*
 94  *函数作用:设置套接字SO_REUSEADDR选项
 95  *函数参数:要设置的套接字
 96  *函数返回值: 无
 97  */
 98  void tyhp_set_reuse_addr(int sockfd);
 99  /*
100  *函数作用:开启套接字TCP_NODELAY选项,关闭nagle算法
101  *函数参数:要设置的套接字
102  *函数返回值: 无
103  */
104  void tyhp_set_off_tcp_nagle(int sockfd);
105  /*
106  *函数作用:关闭套接字TCP_NODELAY选项,开启nagle算法
107  *函数参数:要设置的套接字
108  *函数返回值: 无
109  */
110  void tyhp_set_on_tcp_nagle(int sockfd);
111 /*
112  *函数作用:开启套接字TCP_CORK选项
113  *函数参数:要设置的套接字
114  *函数返回值: 无
115  */
116  void tyhp_set_on_tcp_cork(int sockfd);
117  /*
118  *函数作用:关闭套接字TCP_CORK选项
119  *函数参数:要设置的套接字
120  *函数返回值: 无
121  */
122  void tyhp_set_off_tcp_cork(int sockfd);
123 /*
124  *函数作用:设置套接字SO_RCVTIMEO选项,接收超时
125  *函数参数:sockfd要设置的套接字, sec秒, usec毫秒
126  *函数返回值: 无
127  */
128  void tyhp_set_recv_timeo(int sockfd, int sec, int usec);
129 /*
130  *函数作用:设置套接字SO_SNDTIMEO选项,发送超时
131  *函数参数:sockfd要设置的套接字, sec秒, usec毫秒
132  *函数返回值: 无
133  */
134  void tyhp_set_snd_timeo(int sockfd, int sec, int usec);
135 /******************************************************************************************/
136 
137 /***********************************  系统函数的包裹函数  *******************************************/
138 int tyhp_socket(int domain, int type, int protocol);
139 void tyhp_listen(int sockfd, int backlog);
140 void tyhp_bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
141 int tyhp_accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
142 struct servent* tyhp_getservbyname(const char *name, const char *proto);
143 int tyhp_epoll_create(int size);
144 void tyhp_epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
145 int tyhp_epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
146 
147 void *tyhp_calloc(size_t nmemb, size_t size);
148 void *tyhp_malloc(size_t size);
149 void tyhp_free(void *ptr);
150 /******************************************************************************************/
151 #endif
  1 /*
  2 *Author        Zou Xiao hang
  3 *Email        [email protected]
  4 *File Name    utility.cpp
  5 *Date         2013/10/05
  6 */
  7 #include "utility.h"
  8 
  9 //存储解析文件的键值对,例如key=docroot value=/home/zxh/desktop/code/webserver
 10 map<string, int> tyhp_config_keyword_map;
 11 
 12 /***********************************  项目实用工具函数  *******************************************/
 13 /*
 14  *函数作用:得到系统时间
 15  *函数参数:无
 16  *函数返回值: 系统时间 例如:Fri, 22 May 2009 06:07:21 GMT
 17  */
 18 string tyhp_time_gmt()
 19 {
 20     time_t now;
 21     struct tm *time_now;
 22     string str_time;
 23 
 24     time(&now);
 25     time_now = localtime(&now);
 26 
 27     switch(time_now->tm_wday)
 28     {
 29         case 0:
 30             str_time += "Sun, ";
 31             break;
 32         case 1:
 33             str_time += "Mon, ";
 34             break;
 35         case 2:
 36             str_time += "Tue, ";
 37             break;
 38         case 3:
 39             str_time += "Wed, ";
 40             break;
 41         case 4:
 42             str_time += "Thu, ";
 43             break;
 44         case 5:
 45             str_time += "Fri, ";
 46             break;
 47         case 6:
 48             str_time += "Sat, ";
 49             break;
 50     }
 51     char buf[16];
 52     snprintf(buf, sizeof(buf), "%d ", time_now->tm_mday);
 53     str_time += string(buf);
 54     switch(time_now->tm_mon)
 55     {
 56         case 0:
 57             str_time += "Jan ";
 58             break;
 59         case 1:
 60             str_time += "Feb ";
 61             break;
 62         case 2:
 63             str_time += "Mar ";
 64             break;
 65         case 3:
 66             str_time += "Apr ";
 67             break;
 68         case 4:
 69             str_time += "May ";
 70             break;
 71         case 5:
 72             str_time += "Jun ";
 73             break;
 74         case 6:
 75             str_time += "Jul ";
 76             break;
 77         case 7:
 78             str_time += "Aug ";
 79             break;
 80         case 8:
 81             str_time += "Sep ";
 82             break;
 83         case 9:
 84             str_time += "Oct ";
 85             break;
 86         case 10:
 87             str_time += "Nov ";
 88             break;
 89         case 11:
 90             str_time += "Dec ";
 91             break;
 92     }
 93     snprintf(buf, sizeof(buf), "%d", time_now->tm_year + 1900);
 94     str_time += string(buf);
 95     snprintf(buf, sizeof(buf), " %d:%d:%d ", time_now->tm_hour, time_now->tm_min, time_now->tm_sec);
 96     str_time += string(buf);
 97 
 98     str_time += "GMT";
 99 
100     return str_time;
101 }
102 /*
103  *函数作用:根据http请求包中的url和配置文件中的docroot配置选项构造真正的url
104  *函数参数:url
105  *函数返回值: 真正的url(绝对路径)
106  */
107 string tyhp_make_real_url(const string& url)
108 {
109     string real_url, url2;
110 
111     int n = 0;
112     
113     if((n = url.find(tyhp_domain, 0)) != string::npos)//url中包含域名,要将其删去
114         url2 = url.substr(tyhp_domain.size(), url.size() - tyhp_domain.size());
115     else
116         url2 = url;
117 
118     if(tyhp_docroot[tyhp_docroot.size() - 1] == '/')//配置项docroot末尾有'/'
119     {
120         if(url2[0] == '/')
121             real_url = tyhp_docroot + url2.erase(0, 1);
122         else
123             real_url = tyhp_docroot + url2;
124     }
125     else//配置项docroot末尾没有'\'
126     {
127         if(url2[0] == '/')
128             real_url = tyhp_docroot + url2;
129         else
130             real_url = tyhp_docroot + '/' + url2;
131     }
132 
133     return real_url;
134 }
135 /*
136  *函数作用:获得文件长度
137  *函数参数:path为绝对路径+文件名
138  *函数返回值: 文件长度
139  */
140  int tyhp_get_file_length(const char *path)
141  {
142      struct stat buf;
143      int ret = stat(path, &buf);
144      if(ret == -1)
145      {
146          perror("tyhp_get_file_length");
147          exit(-1);
148      }
149      return (int)buf.st_size;
150  }
151   /*
152  *函数作用:获得文件最后修改时间
153  *函数参数:path为绝对路径+文件名
154  *函数返回值: 文件最后修改时间
155  */
156  string tyhp_get_file_modified_time(const char *path)
157  {
158      struct stat buf;
159      int ret = stat(path, &buf);
160      if(ret == -1)
161      {
162          perror("tyhp_get_file_length");
163          exit(-1);
164      }
165      char array[32] = {0};
166      snprintf(array, sizeof(array), "%s", ctime(&buf.st_mtime));
167      return string(array, array + strlen(array));
168  }
169 /*
170  *函数作用:初始化全局变量tyhp_config_keyword_map,必须在使用tyhp_config_keyword_map前调用此函数
171  *函数参数:无
172  *函数返回值: 无
173  */
174  void tyhp_init_config_keyword_map()
175  {
176      tyhp_config_keyword_map.insert(make_pair("docroot", TYHP_DOCROOT));
177      tyhp_config_keyword_map.insert(make_pair("domain", TYHP_DOMAIN));
178  }
179 /*
180  *函数作用:解析配置文件
181  *函数参数:path为绝对路径+文件名
182  *函数返回值: -1表示解析失败,0代表解析成功
183  */
184  int tyhp_parse_config(const char *path)
185  {
186      tyhp_init_config_keyword_map();
187      int ret = 0;
188      fstream infile(path, fstream::in);
189      string line, word;
190      if(!infile)
191      {
192          printf("%s can't open\n", path);
193          infile.close();
194          return -1;
195      }
196      while(getline(infile, line))
197      {
198          stringstream stream(line);
199          stream >> word;//keyword
200          map<string, int>::const_iterator cit= tyhp_config_keyword_map.find(word);
201          if(cit == tyhp_config_keyword_map.end())
202          {
203              printf("can't find keyword\n");
204              infile.close();
205              return -1;
206          }
207          switch (cit->second)
208          {
209              case TYHP_DOCROOT:
210                  stream >> tyhp_docroot;
211                  break;
212              case TYHP_DOMAIN:
213                  stream >> tyhp_domain;
214                  break;
215              default :
216                  infile.close();
217                  return -1;
218          }
219      }
220      infile.close();
221      return 0;
222  }
223   /*
224  *函数作用:设置文件描述符为非阻塞模式
225  *函数参数:要设置的描述符
226  *函数返回值: 无
227  */
228  void tyhp_set_nonblocking(int fd)
229  {
230     int flags = fcntl(fd, F_GETFL, 0);
231     if(flags < 0)
232     {
233         perror("fcntl: F_GETFL");
234         exit(-1);
235     }
236     flags |= O_NONBLOCK;
237     int ret = fcntl(fd, F_SETFL, flags);
238     if(ret < 0)
239     {
240         perror("fcntl");
241         exit(-1);
242     }
243  }
244   /*
245  *函数作用:设置套接字SO_REUSEADDR选项
246  *函数参数:要设置的套接字
247  *函数返回值: 无
248  */
249  void tyhp_set_reuse_addr(int sockfd)
250 {
251     int on = 1;
252     int ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
253     if(ret == -1)
254     {
255         perror("setsockopt: SO_REUSEADDR");
256         exit(-1);
257     }
258 }
259  /*
260  *函数作用:开启套接字TCP_NODELAY选项,关闭nagle算法
261  *函数参数:要设置的套接字
262  *函数返回值: 无
263  */
264  void tyhp_set_off_tcp_nagle(int sockfd)
265  {
266      int on = 1;
267      int ret = setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
268      if(ret == -1)
269      {
270          perror("setsockopt: TCP_NODELAY ON");
271         exit(-1);
272      }
273  }
274  /*
275  *函数作用:关闭套接字TCP_NODELAY选项,开启nagle算法
276  *函数参数:要设置的套接字
277  *函数返回值: 无
278  */
279  void tyhp_set_on_tcp_nagle(int sockfd)
280  {
281      int off = 0;
282      int ret = setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &off, sizeof(off));
283      if(ret == -1)
284      {
285          perror("setsockopt: TCP_NODELAY OFF");
286         exit(-1);
287      }
288  }
289 /*
290  *函数作用:开启套接字TCP_CORK选项
291  *函数参数:要设置的套接字
292  *函数返回值: 无
293  */
294  void tyhp_set_on_tcp_cork(int sockfd)
295  {
296      int on = 1;
297      int ret = setsockopt(sockfd, SOL_TCP, TCP_CORK, &on, sizeof(on));
298      if(ret == -1)
299      {
300          perror("setsockopt: TCP_CORK ON");
301         exit(-1);
302      }
303  }
304  /*
305  *函数作用:关闭套接字TCP_CORK选项
306  *函数参数:要设置的套接字
307  *函数返回值: 无
308  */
309  void tyhp_set_off_tcp_cork(int sockfd)
310  {
311      int off = 0;
312      int ret = setsockopt(sockfd, SOL_TCP, TCP_CORK, &off, sizeof(off));
313      if(ret == -1)
314      {
315          perror("setsockopt: TCP_CORK OFF");
316         exit(-1);
317      }
318  }
319 /*
320  *函数作用:设置套接字SO_RCVTIMEO选项,接收超时
321  *函数参数:sockfd要设置的套接字, sec秒, usec毫秒
322  *函数返回值: 无
323  */
324  void tyhp_set_recv_timeo(int sockfd, int sec, int usec)
325  {
326      struct timeval time= {sec, usec};
327      int ret = setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &time, sizeof(time));
328      if(ret == -1)
329      {
330          perror("setsockopt: SO_RCVTIMEO");
331         exit(-1);
332      }
333  }
334 /*
335  *函数作用:设置套接字SO_SNDTIMEO选项,发送超时
336  *函数参数:sockfd要设置的套接字, sec秒, usec毫秒
337  *函数返回值: 无
338  */
339  void tyhp_set_snd_timeo(int sockfd, int sec, int usec)
340  {
341      struct timeval time= {sec, usec};
342      int ret = setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &time, sizeof(time));
343      if(ret == -1)
344      {
345          perror("setsockopt: SO_SNDTIMEO");
346         exit(-1);
347      }
348  }
349 /******************************************************************************************/
350 
351 /***********************************  系统函数的包裹函数  *******************************************/
352 int tyhp_socket(int domain, int type, int protocol)
353 {
354     int listen_fd;
355     if((listen_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
356     {
357         perror("socket");
358         exit(-1);
359     }
360     return listen_fd;
361 }
362 void tyhp_listen(int sockfd, int backlog)
363 {
364     if(listen(sockfd, backlog) == -1)
365     {
366         perror("listen");
367         exit(-1);
368     }
369 }
370 void tyhp_bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
371 {
372     if(bind(sockfd, addr, addrlen) == -1)
373     {
374         perror("bind");
375         exit(-1);
376     }
377 }
378 int tyhp_accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
379 {
380     int ret_fd = 0;
381     for(;;)
382     {    
383         ret_fd = accept(sockfd, addr, addrlen);
384         if(ret_fd > 0)
385             break;
386         else if(ret_fd == -1)
387         {
388             //由于我们把监听套接字设置为了非阻塞模式
389             if(errno != EAGAIN && errno != EPROTO &&
390                      errno != EINTR && errno != ECONNABORTED)
391             {    
392                 perror("accept");
393                 exit(-1);
394             }
395         }
396         else
397             continue;
398     }
399     return ret_fd;
400 }
401 struct servent* tyhp_getservbyname(const char *name, const char *proto)
402 {
403     struct servent     *pservent;
404     if((pservent = getservbyname(name, proto)) == NULL)
405     {
406         perror("getservbyname");
407         exit(-1);
408     }
409     return pservent;
410 }
411 int tyhp_epoll_create(int size)
412 {
413     int epollfd;
414     epollfd = epoll_create(size);
415     if(-1 == epollfd)
416     {
417         perror("epoll_create");
418         exit(-1);
419     }
420     return epollfd;
421 }
422 void tyhp_epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
423 {
424     if(epoll_ctl(epfd, op, fd, event) == -1)
425     {
426         perror("epoll_ctl");
427         exit(-1);
428     }    
429 }
430 int tyhp_epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout)
431 {
432 again:
433     int nfds = epoll_wait(epfd, events, maxevents, timeout);
434     if(nfds == -1) //&& errno != EINTR)
435     {
436         if(errno != EINTR)
437         {
438             perror("epoll_wait");
439             exit(-1);
440         }
441         else
442             goto again;
443     }
444     return nfds;
445 }
446 
447 void *tyhp_calloc(size_t nmemb, size_t size)
448 {
449     void *ptr = calloc(nmemb, size);
450     if(NULL == ptr)
451     {
452         perror("tyhp_calloc");
453         exit(-1);
454     }
455     return ptr;
456 }
457 void *tyhp_malloc(size_t size)
458 {
459     void *ptr = malloc(size);
460     if(NULL == ptr)
461     {
462         perror("tyhp_malloc");
463         exit(-1);
464     }
465     return ptr;
466 }
467 void tyhp_free(void *ptr)
468 {
469     free(ptr);
470 }
471 /******************************************************************************************/

 

你可能感兴趣的:(http,Web)