首页 > 其他分享 >websever

websever

时间:2023-08-04 11:13:33浏览次数:33  
标签:Reactor EPOLLONESHOT SIGPIPE 事件 线程 websever socket

1 在浏览器键入url,按下回车会经历如下行为

浏览器向 DNS 服务器请求解析该 URL 中的域名所对应的 IP 地址;
解析出 IP 地址后,根据该 IP 地址和默认端口 80,和服务器建立 TCP 连接;
浏览器发出读取文件( URL 中域名后面部分对应的文件)的 HTTP 请求,该请求报文作为 TCP 三次握手的第三个报文的数据发送给服务器;
服务器对浏览器请求作出响应,并把对应的 HTML 文本发送给浏览器;
释放 TCP 连接;
浏览器将该 HTML 文本并显示内容。

2 两种高效的事件处理模式

Reactor 和 Proactor ,同步 I/O 模型通常用于实现 Reactor 模式,异步 I/O 模型通常用于实现 Proactor 模式。

Reactor和Proactor模式的主要区别就是真正的读取和写入操作是由谁来完成的
Reactor来了事件操作系统通知应用进程,让应用进程来处理;
Proactor来了事件操作系统来处理,处理完再通知应用进程。

Reactor模式:

3 EPOLLONESHOT事件

即使可以使用 ET 模式,一个 socket 上的某个事件还是可能被触发多次。因为在ET模式下事件只有状态发生变化时才触发通知,比如读缓冲区有了新的可读数据,或者写缓冲区有空位可以写入时。

而这在并发程序中就会引起一个问题。比如读事件被触发时,一个线程被唤醒来处理数据,而在数据的处理过程中该文件描述符上又有新数据可读( EPOLLIN 再次被触发),此时另外一个线程被唤醒来读取这些新的数据。

于是就出现了两个线程同时操作一个 socket 的局面。一个 socket 连接在任一时刻都只被一个线程处理,可以使用 epoll 的 EPOLLONESHOT 事件实现。

对于注册了 EPOLLONESHOT 事件的文件描述符,操作系统最多触发其上注册的一个可读、可写或者异常事件,且只触发一次,除非我们使用 epoll_ctl 函数重置该文件描述符上注册的 EPOLLONESHOT 事件。这样,当一个线程在处理某个 socket 时,其他线程是不可能有机会操作该 socket 的。

但反过来思考,注册了 EPOLLONESHOT 事件的 socket 一旦被某个线程处理完毕, 该线程就应该立即重置这个socket 上的 EPOLLONESHOT 事件,以确保这个 socket 下一次可读时,其 EPOLLIN 事件能被触发,进而让其他工作线程有机会继续处理这个 socket 。

4 SIGPIPE信号详解

当服务器close一个连接时,若client端接着发数据。根据TCP协议的规定,会收到一个RST响应,client再往这个服务器发送数据时,系统会发出一个SIGPIPE信号给进程,告诉进程这个连接已经断开了,不要再写了,而该信号会默认结束进程。

为了避免进程退出, 可以捕获SIGPIPE信号, 或者忽略它, 给它设置SIG_IGN信号处理函数:signal(SIGPIPE, SIG_IGN);

在linux下写socket的程序的时候,如果尝试send到一个disconnected socket上,就会让底层抛出一个SIGPIPE信号。这个信号的缺省处理方法是退出进程,大多数时候这都不是我们期望的。因此我们需要重载这个信号的处理方法。调用以下代码,即可安全的屏蔽SIGPIPE:signal (SIGPIPE, SIG_IGN);

5 SIGALARM和SIGTERM

SIGALARM 终止进程 计时器到时
SIGTERM 终止进程 软件终止信号,通常用来要求程序自己正常退出

6 websever实现流程概述

牛客上的websever是用同步IO模拟实现Proactor模式,但个人认为这样相比于Reactor模式没有什么区别,仅仅是把读写操作从工作线程中抽离了出来,由主线程进行读写,并非达到了真正的异步IO的效用,所以要是介绍项目的时候个人认为还是描述成Reactor模式比较好

主线程准备工作:

  • 通过main的参数获取有效端口号
  • 设置SIGPIPE信号的捕捉忽略处理
  • 创建监听socket,设置端口复用来及时释放端口并重用,绑定地址信息
  • 创建epoll对象并添加要监听的fd
  • 创建管道,用于对SIGALRM和SIGTERM的信号捕捉通知,写管道设置非阻塞,读管道加入epoll检测
  • 初始化http_conn类的客户端数组users,共用一个epoll_fd的定时器链表;初始化线程池,动态创建线程,设置线程分离;设定定时器
  • 开始监听套接字连接
  • epoll_wait阻塞等待事件的发生

主线程循环遍历事件数组处理不同的事件:

 
工作线程解析http报文

7 参考

Linux高并发服务器

标签:Reactor,EPOLLONESHOT,SIGPIPE,事件,线程,websever,socket
From: https://www.cnblogs.com/dreamer-q/p/17595246.html

相关文章