探秘Linux网络设计:Reactor模型与高效http静态服务器构建

简介: 本文将深入探讨Linux网络设计中的Reactor模型,并展示如何利用该模型构建高效的http静态服务器。在现代互联网环境中,快速响应和高吞吐量对于提供卓越用户体验至关重要。通过理解Reactor模型的基本概念和工作原理,我们将揭示它在构建高并发应用中的关键作用。本文还将详细介绍如何利用Reactor模型优化网络通信,实现快速的http请求处理和静态资源传输。通过实践经验的分享,包括事件驱动编程、多线程和多进程处理以及负载均衡等技巧,读者将获得构建高效http静态服务器的实际指导和启示。

1、Reactor简介

Reactor意译“反应堆”,是一种事件驱动机制,程序需要提供回调函数,注册到reactor中。
Reactor模型包含三个重要组件:多路复用器,事件分离器,事件处理器。多路复用器在Linux上一般是select、poll、epoll;事件分离器是调用对应注册的回调函数;事件处理器是回调函数的执行,如读、写数据操作。
mermaid-diagram-2023-07-16-123128.png

一个程序监控多个IO,所有要处理的事件注册到一个中心IO多路复用器epoll上,由epoll进行管理,当epoll检测到一个IO事件到来或准备就绪时,epoll触发相对应的IO事件;reactor就是对所有的事件做成反应堆模式,当事件触发时,调用相对应的回调函数。比如,IO的可读事件调用读数据的回调函数,IO的可写事件调用发送数据回调函数。
每个IO相互独立,都有自己相对应的回调函数,互不影响。

2、Reactor存在的理由

1、epoll是对IO的管理,检测接入的IO,触发IO事件;reactor是对事件的管理,不同的事件调用不同的回调函数;这样带来的好处是每个事件对应不同的回调函数,每个事件数据互不影响。
2、事件封装;对未处理的事件放在独立的buffer中;对于http服务器可以优先处理一部分数据。

3、sendfile()说明

在HTTP服务器中,返回资源文件时可以使用sendfile函数来发送body部分,提高效率。
函数原型:

#include <sys/sendfile.h>

ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);

说明:
sendfile在一个文件描述符和另一个文件描述符之间复制数据。由于这种复制是在内核中完成的,因此sendfile比读和写的组合更有效,后者需要在用户空间之间传输数据。
参数说明:

参数 含义
out_fd 为读取而打开的文件描述符,通常是文件的fd
in_fd 为写入而打开的文件描述符
out_fd 如果offset不为NULL,则它指向保存文件偏移量的变量,将从该变量开始从infd读取数据。如果偏移量为NULL,则从当前文件偏移量开始从in fd读取数据,并通过调用更新文件偏移量。
count 在文件描述符之间复制的字节数

返回值:
如果传输成功,则返回写入out_ fd的字节数。请注意,成功调用sendfile()可能会写入比请求更少的字节;如果存在未发送的字节,调用方应准备重试调用。传输失败返回负数。

错误代码:

错误码 含义
EAGAIN 已使用ONONBLOCK选择非阻塞I/O,sendfile需要写入阻塞。
EBADF 未打开输入文件进行读取,或未打开输出文件进行写入。
EFAULT 地址不正确。
EINVAL 描述符无效或已锁定,或者类似mmap的操作不可用于in_fd,或者计数为负。
EINVAL out_ fd设置了O_APPEND。sendfile()当前不支持此操作。
EIO 从in_ fd读取时出现未指定错误。
ENOMEM 内存不足,无法从in_ fd读取。
EOVERFLOW 计数太大,该操作将导致超过输入文件或输出文件的最大大小。
ESPIPE 偏移量不为NULL,但输入文件不可搜索(2)。

4、HTTP常用的请求方法

方法 含义
GET 获取资源
POST 提交数据
PUT 更新数据
DELETE 删除数据

5、HTTP静态服务器

HTTP静态服务器可以基于Reactor,实现高并发,reactor的实现可参考上一篇:开启极速之旅:了解Linux网络设计中的Reactor模型与百万级并发实践

5.1 接收数据逻辑 -- recv

HTTP服务器接受请求时,不必接收完所有的数据才进行数据解析,可以读一部分数据先进行解析,再解析后面的数据。
可以按行解析,如HTTP请求时,可以先解析GET方法所在行的数据,里面就包含了请求资源的位置。
mermaid-diagram-2023-07-16-123542.png

5.2 发送数据逻辑 -- send

HTTP服务器返回数据和接收数据的类似,可以先发送http的头数据,再发送内容。
数据拷贝到自己的buffer,发送数据,发送完重新设置事件,设为读就绪。
mermaid-diagram-2023-07-16-123630.png

5.3 HTTP服务器实现

HTTP请求包中GET所在行包含的数据有三部分:请求方法(GET),请求的资源,协议版本号。

5.3.1、HTTP请求包解析

业务分析是recv完之后的操作,一般recv最好是按行读取数据,方便数据分析和处理。
简单示例:

// 读取一行数据
int readline(char *buffer,int idx,char *linebuffer)
{
   
   
    int len=strlen(buffer);
    for(;idx<len;idx++)
    {
   
   
        if(buffer[idx]=='\r' && buffer[idx+1]=='\n')
            return idx+2;
        *(linebuffer++)=buffer[i];
    }
    return  -1;
}

int nty_http_request(struct ntyevent *ev/*用于解析的结构体*/)
{
   
   
    char linebuffer[1024];
    readline(ev->buffer,0,linebuffer);
    if(strstr(linebuffer,"GET "))
    {
   
   
        ev->method=HTTP_METHOD_GET;//标识为HTTP的GET方法
        //解析资源包
        int i = strlen("GET ");
        while (linebuffer[i] != ' ')
            i++;
        linebuffer[i] = '\0';

        sprintf(ev->resource, "%s%s", HTTP_WEB_ROOT,linebuffer + 4);//将请求资源保存
;    }
    else if(strstr(linebuffer,"POST "))
    {
   
   
        /*处理POST方法*/
    }
    return 0;
}

nty_http_request函数在recv之后调用。

5.3.2、HTTP打包发送

HTTP服务器应答需要打包数据,包括HTTP Header和body。在send之前操作,一般将HTTP header和body分开发送。
简单示例:

// http header 打包
int nty_http_response_get_method(struct ntyevent *ev)
{
   
   
    int len;
    int filefd = open(ev->resource, O_RDONLY);
    if (filefd == -1)
    {
   
   
        len = sprintf(ev->wbuffer,
            "HTTP/1.1 200 OK\r\n"
            "Accept-Ranges: bytes\r\n"
            "Content-Length: 78\r\n"
            "Content-Type: text/html\r\n"
            "Date: Sat, 06 Aug 2022 13:16:46 GMT\r\n\r\n"
            "<html><head><title>FLY.TestWeb</title></head><body><h1>FLY.</h1><body/></html>");

        ev->wlength = len;
    }
    else
    {
   
   
        struct stat stat_buf;
        fstat(filefd, &stat_buf);
        close(filefd);
        len = sprintf(ev->wbuffer,
            "HTTP/1.1 200 OK\r\n"
            "Accept-Ranges: bytes\r\n"
            "Content-Length: %ld\r\n"
            "Content-Type: text/html\r\n"
            "Date: Sat, 06 Aug 2022 13:16:46 GMT\r\n\r\n"
            ,stat_buf.st_size);
        ev->wlength = len;
    }
    return len;
}
int nty_http_response(struct ntyevent *ev/*用于解析的结构体*/)
{
   
   
    if(ev->method==HTTP_METHOD_GET)//获取HTTP的请求方法
    {
   
   
        nty_http_response_get_method(ev);//http头打包
    }
    else if(ev->method==HTTP_METHOD_POST)//获取HTTP的请求方法
    {
   
   
    }
}

// 发送数据回调函数
int send_cb(struct ntyevent *ev)
{
   
   
    ......
    send(fd,ev->wbuffer,ev->length,0);//发送http的头数据

    int filefd=open(ev->resource,O_RDONLY);//只读方式打开文件
    struct stat stat_buff;

    // 设置阻塞模式
    fstat(filefd,&stat_buff);
    int flag = fcntl(fd, F_GETFL, 0);
    flag &= ~O_NONBLOCK;
    fcntl(fd, F_SETFL, flag);

    sendfile(filefd,fd,NULL,st_size);// 发送http body

    // 还原非阻塞模式
    flag |= O_NONBLOCK;
    fcntl(fd, F_SETFL, flag);

    close(filefd);

    send(fd, "\r\n", 2, 0);
    ......
}

6 content-type常用类型

参数 含义
text/html HTML格式
application/x-www-form-urlencoded form 表单数据被编码
application/json JSON数据格式
text/plain 纯文本格式
text/xml XML格式
image/gif gif图片格式
image/jpeg jpg图片格式
image/png png图片格式
application/octet-stream 二进制流数据

image.png

相关实践学习
CentOS 7迁移Anolis OS 7
龙蜥操作系统Anolis OS的体验。Anolis OS 7生态上和依赖管理上保持跟CentOS 7.x兼容,一键式迁移脚本centos2anolis.py。本文为您介绍如何通过AOMS迁移工具实现CentOS 7.x到Anolis OS 7的迁移。
目录
相关文章
|
2天前
|
前端开发 网络协议 安全
【网络原理】——HTTP协议、fiddler抓包
HTTP超文本传输,HTML,fiddler抓包,URL,urlencode,HTTP首行方法,GET方法,POST方法
|
2天前
|
存储 JSON 缓存
【网络原理】——HTTP请求头中的属性
HTTP请求头,HOST、Content-Agent、Content-Type、User-Agent、Referer、Cookie。
|
4天前
|
JSON Dart 前端开发
鸿蒙应用开发从入门到入行 - 篇7:http网络请求
在本篇文章里,您将掌握鸿蒙开发工具DevEco的基本使用、ArkUI里的基础组件,并通过制作一个简单界面掌握使用
37 8
|
3天前
|
数据采集 安全 搜索推荐
HTTP代理IP纯净度 提升用户网络体验的核心竞争力
随着互联网发展,使用HTTP动态代理IP的需求日益增加。高纯净度的代理IP在隐私与安全、网络体验和业务运营方面至关重要。它能保护用户信息、提高数据安全性、确保访问速度和连接稳定,并提升业务效率与信誉度。
20 2
|
5天前
|
网络协议 安全 网络安全
探索网络模型与协议:从OSI到HTTPs的原理解析
OSI七层网络模型和TCP/IP四层模型是理解和设计计算机网络的框架。OSI模型包括物理层、数据链路层、网络层、传输层、会话层、表示层和应用层,而TCP/IP模型则简化为链路层、网络层、传输层和 HTTPS协议基于HTTP并通过TLS/SSL加密数据,确保安全传输。其连接过程涉及TCP三次握手、SSL证书验证、对称密钥交换等步骤,以保障通信的安全性和完整性。数字信封技术使用非对称加密和数字证书确保数据的机密性和身份认证。 浏览器通过Https访问网站的过程包括输入网址、DNS解析、建立TCP连接、发送HTTPS请求、接收响应、验证证书和解析网页内容等步骤,确保用户与服务器之间的安全通信。
36 1
|
8天前
|
缓存 负载均衡 监控
HTTP代理服务器在网络安全中的重要性
随着科技和互联网的发展,HTTP代理IP中的代理服务器在企业业务中扮演重要角色。其主要作用包括:保护用户信息、访问控制、缓存内容、负载均衡、日志记录和协议转换,从而在网络管理、性能优化和安全性方面发挥关键作用。
31 2
|
9天前
|
监控 安全 BI
什么是零信任模型?如何实施以保证网络安全?
随着数字化转型,网络边界不断变化,组织需采用新的安全方法。零信任基于“永不信任,永远验证”原则,强调无论内外部,任何用户、设备或网络都不可信任。该模型包括微分段、多因素身份验证、单点登录、最小特权原则、持续监控和审核用户活动、监控设备等核心准则,以实现强大的网络安全态势。
|
8天前
|
安全 网络协议 网络安全
网络不稳定导致HTTP代理频繁掉线的分析
随着数字化时代的加速发展,网络安全、隐私保护及内容访问自由成为用户核心需求。HTTP代理服务器因其独特技术优势受到青睐,但其掉线问题频发。本文分析了HTTP代理服务器不稳定导致掉线的主要原因,包括网络问题、服务器质量、用户配置错误及IP资源问题等方面。
40 0
|
1月前
|
网络协议 网络安全 网络虚拟化
本文介绍了十个重要的网络技术术语,包括IP地址、子网掩码、域名系统(DNS)、防火墙、虚拟专用网络(VPN)、路由器、交换机、超文本传输协议(HTTP)、传输控制协议/网际协议(TCP/IP)和云计算
本文介绍了十个重要的网络技术术语,包括IP地址、子网掩码、域名系统(DNS)、防火墙、虚拟专用网络(VPN)、路由器、交换机、超文本传输协议(HTTP)、传输控制协议/网际协议(TCP/IP)和云计算。通过这些术语的详细解释,帮助读者更好地理解和应用网络技术,应对数字化时代的挑战和机遇。
107 3
|
1月前
|
存储 网络协议 安全
30 道初级网络工程师面试题,涵盖 OSI 模型、TCP/IP 协议栈、IP 地址、子网掩码、VLAN、STP、DHCP、DNS、防火墙、NAT、VPN 等基础知识和技术,帮助小白们充分准备面试,顺利踏入职场
本文精选了 30 道初级网络工程师面试题,涵盖 OSI 模型、TCP/IP 协议栈、IP 地址、子网掩码、VLAN、STP、DHCP、DNS、防火墙、NAT、VPN 等基础知识和技术,帮助小白们充分准备面试,顺利踏入职场。
90 2