HTTP协议——超文本传输协议:是互联网上应用最广泛的网络协议。它是应用层的协议,底层是基于TCP通信的。
HTTP协议的工作过程:客户通过浏览器向服务器发送文档请求,服务器将请求的资源返回给浏览器,然后关闭连接。即:连接—>请求—>响应—>关闭连接。
通用——与业务无关 框架——二次开发
HTTP协议的请求与响应
服务器的特点
启动服务器——>基于TCP的初始化(创建、绑定、监听);使用线程进入事件循环(创建线程、线程分离)——>进入线程入口——>处理请求过程
1、解析请求
HTTP请求中的换行符:把未知问题转换成已知问题,将\r和\r\n转换成\n
首行格式:GET http://www.baidu.com/index.html?aa=10&b=20 HTTP/1.1
url的格式:/index.html?aa=10&b=20
以?为分隔符,?前面的是url_path,?后面的是query_string
2、根据请求计算响应并写回客户端
(1)调用open打开文件
(2)构造HTTP响应报文(首行、空行),并调用send将构造号的报文发送
(3)读文件内容(调用stat获取文件大小)并将其写到socket中
(4)关闭文件
3、错误处理:一旦触发错误处理逻辑,就直接返回一个404
缺点:应根据不同的错误原因返回不同的数据段
351 void HandlerRequst(int new_sock)//处理请求
352 {
353 int err_Code = 200;//状态码
354 HttpRequest req;//定义了一个缓冲区
355 memset(&req,0,sizeof(req));//初始化缓冲区
356 //1.解析请求
357 //a) 从socket中读取出首行
358 if(ReadLine(new_sock,req.first_line,sizeof(req.first_line)-1) < 0){
359 //TODO错误处理
360 err_Code = 404;
361 goto END;
362 }
363 printf("first_line:%s\n",req.first_line);//打印日志
364 //b) 解析首行,获取url和method
365 if(ParseFirstLine(req.first_line,&req.method,&req.url) < 0){
366 //TODO错误处理
367 err_Code = 404;
368 goto END;
369 }
370 //c) 解析url,获取url_path和query_string
371 if(ParseUrl(req.url,&req.url_path,&req.query_string) < 0){
372 //TODO错误处理
373 err_Code = 404;
374 goto END;
375 }
376 //d) 解析header,丢弃大部分header,只保留content-Length
377 if(ParseHeader(new_sock,&req.content_length)){
378 //TODO错误处理
379 err_Code = 404;
380 goto END;
381 }
382 //2.根据请求计算响应并写回客户端
383 if(strcasecmp(req.method,"GET") == 0 && req.query_string == NULL){//strcasestrcmp忽略大小写的比较
384 //a) 处理静态页面(GET+无参数)
385 err_Code = HandlerStaticFile(new_sock,&req);
386 }else if(strcasecmp(req.method,"GET") == 0 && req.query_string != NULL){
387 //b) 处理动态页面(GET+参数)
388 err_Code = HandlerCGI(new_sock,&req);
389 }else if(strcasecmp(req.method,"POST") == 0){
390 //b) 处理动态页面(POST)
391 err_Code = HandlerCGI(new_sock,&req);
392 }else{
393 //TODO错误处理
394 err_Code = 404;
395 goto END;
396 }
397 END:
398 //收尾工作,主动关闭socket,会进入TIME_WAIT(谁主动断开,谁等待)
399 if(err_Code != 200){
400 Handler404(new_sock);
401 }
402 close(new_sock);//如果不关闭,文件描述符泄漏
403 }
1
2
3
4
5
6
15
16
(1)让日期1大于等于日期2
(2)让日期2++直到与日期1相等
58 int CalculateDayApart(int year1,int month1,int day1,
59 int year2,int month2,int day2)//计算两个日期之间相隔多少天
60 {
61 //1.先让year1大于等于year2
62 if (year1 < year2)
63 {
64 int tmp = year1;
65 year1 = year2;
66 year2 = tmp;
67 }
68 if (month1 < month2){
69 int tmp = month1;
70 month1 = month2;
71 month2 = tmp;
72 }
73 if(day1 < day2)
74 {
75 int tmp = day1;
76 day1 = day2;
77 day2 = tmp;
78 }
79 //2.让日期2++直到与日期1相等
80 int count= 0;
81 while (year1 == year2 && month1 == month2 && day1 == day2){
82 int ret = day2 + 1;
83 if (ret > GetMonthDay(year2, month2)){
84 int monthday = GetMonthDay(year2, month2);
85 ret -= monthday;
86 month2++;
87 if (month2 == 13){
88 month2 = 1;
89 year2++;
90 }
91 }
92 day2 = ret;
93 count++;
94 }
95 return count;
96 }