linux网络编程--Web Server and HTTP

 基本概念

 

browser与server通信,在浏览器输入域名或IP地址:port号,浏览器进行域名解析为相应的ip地址或根据ip地址向对应server发送http请求。 其中首先要TCP协议进行三次握手,建立连接,然后http协议生成对应的http请求报文,通过TCP,IP协议发送到目标server。

HTTP: 超文本传输协议,请求和响应消息头以ASCII形式发出,消息内容类似MIME;默认端口80,本地发出请求的客户端叫做用户代理程序,和服务器之间会存在多个“中间层”,比如代理服务器、网关或者隧道。

采用请求/响应模型,客户端向server发送请求报文,包括请求方法,URL,协议版本,请求头,请求数据。

 服务器响应内容包括协议版本,成功/错误代码,服务器信息,响应头部,响应数据。

请求响应步骤:

状态码及描述:服务器编程基本框架

I/O处理单元:等待并接受客户连接,接受客户数据,返回服务器响应给客户端。但是数据收发不一定在该单元执行,也可能在逻辑单元,取决于事件处理模式。

逻辑单元:一个线程或进程,分析并处理数据,传递结果给I/O或直接给客户端,取决于事件处理模式。多个客户端->多个逻辑单元,以实现并发处理。

网络存储单元:数据库、缓存、文件,但不是必须的。

请求队列:各单元之间通信方式的抽象。I/O通知逻辑单元,逻辑单元访问存储单元等。通常被实现为池的一部分。

事件处理模式:

服务器需要处理三类事件:I/O事件,信号、定时事件。

两种处理模式:

Reactor: 常用同步IO模型实现

        主线程(IO处理单元)只监听fd是否有事发生,有就通知工作线程(逻辑单元),将socket可读可写事件放入请求队列,交给工作线程。 在工作线程中读写数据,接受新连接,处理客户请求。主线程不处理其他实质性工作。

        1. 主线程向epoll内核时间表注册socket上的读就绪事件。

        2. 主线程调用epoll_wait等待有数据可读。

        3. 当socket有数据可读,epoll_wait通知主线程,主线程将socket可读事件放入请求队列。

        4. 睡眠在请求队列的某个工作线程被唤醒,从socket上读数据,处理客户请求,往epoll内核表注册socket写就绪事件。

        5. 主线程调用epoll_wait等待socket可写。

        6. 当socket可写,epoll_wait通知主线程,主线程将socket可写事件放入请求队列。

        7. 睡眠在请求队列的某个工作线程被唤醒,往socket上写入服务器处理客户请求的结果。

Proactor: 常用异步IO实现

将所有IO操作都交给主线程和内核,工作线程仅负责业务逻辑。

        1 主线程调用aio_read向内核注册socket上读完成事件,并告诉内核用户读缓冲区的位置,以及完成时如何通知应用。

        2 主线程继续处理其他逻辑。

        3 当socket上数据被读入用户缓冲区,内核向应用发送信号,通知数据可用。

        4 应用预先定义好的信号处理函数选择一个工作线程处理客户请求,处理完后,调用aio_write向内核注册socket上写完成事件,并告诉内核用户写缓冲区位置,以及完成时如何通知应用。

        5 主线程继续处理其他逻辑

        6 当用户缓冲区内容写入socket,内核向应用发送信号,通知应用数据发完。

        7 应用预先定义的信号处理函数选择一个工作线程善后,如决定是否关闭socket.

        但在 Linux 下的异步 I/O 是不完善的,aio 系列函数是由 POSIX 定义的异步操作接口,不是真正的操作系统级别支持的,而是在用户空间模拟出来的异步,并且仅仅支持基于本地文件的 aio 异步操作,网络编程中的 socket 是不支持的,这使得基于 Linux 的高性能网络程序都是使用 Reactor 方案。
        而 Windows 里实现了一套完整的支持 socket 的异步编程接口,这套接口就是 IOCP,是由操作系统级别实现的异步 I/O,真正意义上异步 I/O,因此在 Windows 里实现高性能网络程序可以使用效率更高的 Proactor 方案。

项目实现:模拟Proactor模式

使用同步IO模拟proactor

        1. 主线程向epoll内核时间表注册socket上的读就绪事件。

        2. 主线程调用epoll_wait等待有数据可读。

        3. 当socket有数据可读,epoll_wait通知主线程,主线程从socket循环读取数据,直到没有数据可读,然后将读取到的数据封装为一个请求对象插入请求队列。

        4. 睡眠在请求队列的某个工作线程被唤醒,获得请求并处理,然后往epoll内核表注册socket写就绪事件。

        5. 主线程调用epoll_wait等待socket可写。

        6. 当socket可写,epoll_wait通知主线程,主线程往socket上写入server处理客户请求的结果。

线程池

使主线程和子线程通过一个共享的工作队列来同步,子线程都睡眠在该工作队列上。当有新任务来时,主线程将任务添加到工作队列中,唤醒一个子线程,他将从工作队列中取出任务并执行,其他子线程将继续在工作队列上睡眠。

 线程数量受限与CPU数量N:

        CPU密集型任务:N 或N+1;  (视频剪辑等消耗CPU资源)

        IO密集型:多于N。 因为IO处理较慢,多于N则为CPU处理更多的任务。

1.以空间换时间,以服务器的硬件资源换取运行效率。

2.池是一组资源的集合,在服务器启动之初就被完全创建好并初始化,称为静态资源。

3.当server进入运行阶段,开始处理客户请求,需要资源时直接从池中获取,无需动态分配。

4.当server处理完一个客户连接,可以把相关资源放回池中,无需释放资源。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值