ICode9

精准搜索请尝试: 精确搜索
首页 > 系统相关> 文章详细

linux服务器HTTP协议内容、实现程序代码

2021-12-09 12:58:01  阅读:169  来源: 互联网

标签:http 请求 int 报文 linux HTTP ev 程序代码 客户端


http协议

1. http简介

http协议叫做超文本传输协议。

  • 超文本:传输的不仅文本,还能传输图片、音频、视频等等。
  • 传输:是基于TCP/IP的一个请伴随一个响应方式传输。
  • 协议:无连接、无状态的应用层协议。

2.http工作原理

  • http协议工作于b/s框架上。浏览器作为http客户端和http服务端(web服务器)发送请求,服务端响应之后会关闭连接。
  • web服务器:作为HTTP请求的应答方,主流的三大Web服务器有Apache、Nginx,IIS。
  • 默认端口为80,改成8080或其他也可以。

3.http请求响应过程

例子:URL:http://www.example.com/filepath/index.html

  1. DNS服务器会对浏览器上输入的域名进行映射,先找到http://www.example.com的地址,http客户端会在80端口发起一个到服务器http://www.example.comTCP连接,发送请求报文,报文内容包括对filepath/index.html的请求。
  2. http服务器接受连接和请求,解析报文并检索出对象filepath/index.html,然后从从磁盘或内存中取出数据进行http报文封装并回发,发完就断开连接。
  3. 客户端接收到数据后,也断开连接,并从报文中取出资源文件。

4.http协议特点

  • 无连接:限制每次连接只处理一个请求,服务器处理完客户端的请求并受到客户应答之后就断开连接。这种方式可以节省传输时间。
  • 无状态:对于事务处理没有记忆能力,后续需要前面的消息则需要重传,这样导致每次连接传输的数据量增大,但服务器不需要先前信息时它应答更快。
  • 协议灵活:允许传输任意类型的数据对象,类型用Content-Type标记。
  • 简单快速:协议简单,使得服务器程序规模较小,因此通信速度很快。
  • 也能支持c/s模式。

5.客户端请求报文

如图,报文:请求方法+请求头部+请求数据。
请求报文

  • 请求方法:如图。请求方法
  • 请求头部:有四种,通用标头、请求表头、响应标头和实体标头。
  • 例如下图,第一行是请求方法,第二第三第四行都是请求头部及其对应值例子

6.服务器响应报文

如图,报文:状态行+消息报头+空行+响应正文
响应例如例子

7.http的优点和缺点

1. 优点

  • 简单灵活易扩展:协议简单,内容不多,相对自由。
  • 应用广泛:应用非常广,可以跨平台、跨语言开发。
  • 无连接、无状态:不需要额外的资源来记录状态信息。实现上相对简单,并且能够减轻服务的负担。

2. 缺点

  • 无连接、无状态:没有记忆性,无法支持多个事务操作,每次都要对一下协议信息,增加了不必要的数据传输,因此出现了cookie。
  • 明文传输:使用可阅读的文本形式,可以用wireshark或tcpdump直接抓包并直接修改,容易被攻击,而且不安全,同时并不能判断通信双方的身份,也不能判断报文是否被更改,因此诞生了https。

3.性能

  • 一般,现在互联网是移动和高并发,不能保证连接质量,tcp层面上HTTP协议有时候会表现得不好。
  • 请求- 应答”会导致“对头阻塞”效应,就是当一个请求阻塞时,后面的请求序列也都会阻塞住,客户端得不到响应。

程序实现

这里程序使用epoll反应堆模型作为框架实现,reactor内容可以在我的博客里面查看。如果单纯想看了解http协议可以前往我主页查看另一篇博客关于tinyhttp开源项目。

下面是用epoll反应堆reactor(C1000K)模型下实现http服务器的介绍~

基于reactor模型的HTTP服务器

客户端结构体

struct qsevent{
    int fd;				//clientfd
    int events;			//事件:读、写或异常
    int status;			//是否位于epfd红黑监听树上
    void *arg;			//参数
    long last_active;	//上次数据收发的事件

    int (*callback)(int fd, int event, void *arg);	//回调函数,单回调,后面修改成多回调
    unsigned char buffer[MAX_BUFLEN];				//数据缓冲区
    int length;										//数据长度

    /*http param*/
    int method;						//http协议请求头部
    char resource[MAX_BUFLEN];		//请求的资源
    int ret_code;					//响应状态码
};

int http_response(struct qsevent *ev)

当客户端发送tcp连接时,服务端的listenfd会触发输入事件会调用ev->callback即accept_cb回调函数响应连接并获得clientfd,连接之后,http数据报文发送上来,服务端的clientfd触发输入事件会调用ev->callback即recv_cb回调函数进行数据接收,并解析http报文。

int http_request(struct qsevent *ev)
{
    char linebuf[1024] = {0};//用于从buffer中获取每一行的请求报文
    int idx = readline(ev->buffer, 0, linebuf);//读取第一行请求方法,readline函数,后面介绍
    if(strstr(linebuf, "GET"))//strstr判断是否存在GET请求方法
    {
        ev->method = HTTP_METHOD_GET;//GET方法表示客户端需要获取资源

        int i = 0;
        while(linebuf[sizeof("GET ") + i] != ' ')i++;//跳过空格
        linebuf[sizeof("GET ") + i] = '\0';
        sprintf(ev->resource, "./%s/%s", HTTP_METHOD_ROOT, linebuf+sizeof("GET "));//将资源的名字以文件路径形式存储在ev->resource中
        printf("resource:%s\n", ev->resource);//回显
    }
    else if(strstr(linebuf, "POST"))//POST的请求方法,暂时没写,方法差不多
    {}
    return 0;
}

int http_response(struct qsevent *ev)

服务器对客户端的响应报文数据进行http封装储存在buffer中,事件触发时在send_cb回调函数发送给客户端。详细解释请看代码注释。

int http_response(struct qsevent *ev)
{
    if(ev == NULL)return -1;
    memset(ev->buffer, 0, MAX_BUFLEN);//清空缓冲区准备储存报文

    printf("resource:%s\n", ev->resource);//resource:客户端请求的资源文件,通过http_reques函数获取
    int filefd = open(ev->resource, O_RDONLY);//只读方式打开获得文件句柄
    if(filefd == -1)//获取失败则发送404 NOT FOUND
    {
        ev->ret_code = 404;//404状态码
        ev->length = sprintf(ev->buffer,//将下面数据传入ev->buffer
        					 /***状态行***/
        					 /*版本号 状态码 状态码描述 */
                             "HTTP/1.1 404 NOT FOUND\r\n"
                             /***消息报头***/
                             /*获取当前时间*/
                             "date: Thu, 11 Nov 2021 12:28:52 GMT\r\n"
                             /*响应正文类型;              编码方式*/
                             "Content-Type: text/html;charset=ISO-8859-1\r\n"
                             /*响应正文长度          空行*/
                             "Content-Length: 85\r\n\r\n"
                             /***响应正文***/
                             "<html><head><title>404 Not Found</title></head><body><H1>404</H1></body></html>\r\n\r\n");
    }
    else 
    {
        struct stat stat_buf;			//文件信息
        fstat(filefd, &stat_buf);		//fstat通过文件句柄获取文件信息
        if(S_ISDIR(stat_buf.st_mode))	//如果文件是一个目录
        {

            printf(ev->buffer, //同上,将404放入buffer中
                   "HTTP/1.1 404 Not Found\r\n"
                   "Date: Thu, 11 Nov 2021 12:28:52 GMT\r\n"
                   "Content-Type: text/html;charset=ISO-8859-1\r\n"
                   "Content-Length: 85\r\n\r\n"
                   "<html><head><title>404 Not Found</title></head><body><H1>404</H1></body></html>\r\n\r\n" );

        } 
        else if (S_ISREG(stat_buf.st_mode)) //如果文件是存在
        {

            ev->ret_code = 200;		//200状态码

            ev->length = sprintf(ev->buffer, //length记录长度,buffer储存响应报文
                                 "HTTP/1.1 200 OK\r\n"
                                 "Date: Thu, 11 Nov 2021 12:28:52 GMT\r\n"
                                 "Content-Type: text/html;charset=ISO-8859-1\r\n"
                                 "Content-Length: %ld\r\n\r\n", 
                                 stat_buf.st_size );//文件长度储存在stat_buf.st_size中

        }
        return ev->length;//返回报文长度
    }
}

git clone代码

自行git clone git clone https://github.com/qiushii/reactor.git

标签:http,请求,int,报文,linux,HTTP,ev,程序代码,客户端
来源: https://blog.csdn.net/yuqiushiya/article/details/121802368

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有