网络编程模型

一.网络编程关注的问题

连接建立

在这里插入图片描述
这个过程主要是TCP 三次握手过程:
在这里插入图片描述

第一次握手

客户主动(active open)去connect服务器,并且发送SYN 假设序列号为J, 服务器是被动打开(passive open),此时客户端状态出于SYN_SENT状态

1.半连接队列未满

服务器将该链接的状态变为SYN_RCVD,服务器把连接信息放到半连接队列里面

2.半连接队列未满

服务器不会将该连接的状态变为syn_RCVD,且该链接将会丢弃。SYN FLOOD攻击就是利用了这个原理,对于解决这个问题有以下几种方法
1)cookie源认证:
   原理是syn报文首先由DDOS防护系统来响应syn_ack。带上特定的sequence number (记为cookie)。真实的客户端会返回一个ack 并且Acknowledgment number 为cookie+1。 而伪造的客户端,将不会作出响应。这样我们就可以知道那些IP对应的客户端是真实的,将真实客户端IP加入白名单。下次访问直接通过,而其他伪造的syn报文就被拦截。下面为防护示意图:
   在这里插入图片描述
(2)reset认证:
   Reset认证利用的是TCP协议的可靠性,也是首先由DDOS防护系统来响应syn。防护设备收到syn后响应syn_ack,将Acknowledgement number (确认号)设为特定值(记为cookie)。当真实客户端收到这个报文时,发现确认号不正确,将发送reset报文,并且sequence number 为cookie + 1。 而伪造的源,将不会有任何回应。这样我们就可以将真实的客户端IP加入白名单。
   在这里插入图片描述

第二次握手

服务器在收到SYN后,它会发送一个SYN以及一个ACK(应答)给客户, ACK的序列号是 J+1表示是给SYN J的应答,新发送的SYN K 序列号是K,此时服务器出于SYC_ACK状态

第三次握手

客户在收到新SYN K, ACK J+1 后,把状态置为ESTABLISHED,也回应ACK K+1 以表示收到了,然后两边就可以开始数据发送数据了,这时服务端也处于ESTABLISHED.全连接队列(accept queue)的最大值 /proc/sys/net/core/somaxconn (默认128)
在这里插入图片描述
全连接队列值 = min(backlog, somaxconn),这里的backlog是listen(int sockfd, int backlog)函数里面的那个参数backlog.

连接断开

在这里插入图片描述
TCP四次挥手:
在这里插入图片描述

第一次挥手

主动关闭方(active close)close会发送fin,seq报文序列号给对端,这个时候主动关闭方出于状态fin-wait-1状态。

第二次挥手

被动方收到fin包号,会返回一个ack包,这个时候被动关闭方状态会变为close_wait状态。主动方收到ack包后,状态将会变成fin-wait-2状态。此时整个连接处于半关闭状态。

第三次挥手

被动关闭方主动调用close,发送fin给主动关闭方,被动关闭方状态将变成last-ack状态。

第四次挥手

主动关闭方收到fin包后,然后将发送ack给被动关闭方,在等待2MSL后将变为close状态,被动关闭方在收到ack后,也会变为close状态

四次挥手中常见问题:
1.tcp连接大量CLOSE_WAIT和TIME_WAIT状态的出现和解决方法:这个请参考链接https://blog.csdn.net/lqglqglqg/article/details/54616380

消息到达

1.阻塞io模型和非io模型
(1)阻塞在哪里:阻塞在网络线程里
(2)什么来决定阻塞还是非阻塞:通过fcntl函数来设置
在这里插入图片描述
(3)具体的差异:io函数在数据未到达的时是否立刻返回
在这里插入图片描述
在这里插入图片描述
2.网络处理模型
(1)阻塞IO模型 + 多线程
在这里插入图片描述

优点:每个线程处理一个fd连接bio, 处理及时
缺点:线程利用率较低,线程的数量时有限的

(2)io多路复用
用一个线程来检测多个IO事件
在这里插入图片描述
水平触发的时候,io函数既可以时阻塞的也可以时非阻塞的;边缘触发的时候,io函数只能是非阻塞的。

epoll基础
重要数据结构:

struct eventpoll {
//...
	struct rb_root rbr;	//管理epoll监听事件
	struct list_head rdlist;   //保存epoll_wait返回满足条件的事件	
};

struct epitem {
// ...
struct rb_node rbn; // 红⿊树节点
struct list_head rdllist; // 双向链表节点
struct epoll_filefd ffd; // 事件句柄信息
struct eventpoll *ep; // 指向所属的eventpoll对象
struct epoll_event event; // 注册的事件类型
// ...
}

struct epoll_event {
__uint32_t events;
epoll_data_t data; // 保存 关联数据
};

typedef union epoll_data {
void *ptr;
int fd;
uint32_t u32;
uint64_t u64;
}epoll_data_t;

epoll_create系统调⽤
在这里插入图片描述
size参数告诉内核这个epoll对象会处理的事件⼤致数量,⽽不是能够处理的事件的最⼤数。在现在linux版本中,这个size参数已经没有意义了;返回:epoll对象句柄;之后针对该epoll的操作需要通过该句柄来标识该epoll对象;

epoll_ctl系统调用
在这里插入图片描述
epoll_ctl向epoll对象添加,修改或删除事件; 返回:0表示成功,-1表示错误,根据errno错误码判断错误类型

**op类型:**
	EPOLL_CTL_ADD   	添加新的事件到epoll中
	EPOLL_CTL_MOD 		修改epoll中的事件
	EPOLL_CTL_DEL		 删除epoll中的事件

**event.events 取值**:
	EPOLLIN 		表示该连接上有数据可读(tcp连接远端主动关闭连接,也是可读事件,因为需要处理发送来的FIN包;FIN包就是read 返回 0)
	EPOLLOUT  		表示该连接上可写发送(主动向上游服务器发起⾮阻塞tcp连接,连接建⽴成功事件相当于可写事件)
	EPOLLRDHUP 	表示tcp连接的远端关闭或半关闭连接
	EPOLLPRI 		表示连接上有紧急数据需要读
	EPOLLERR 		表示连接发⽣错误
	EPOLLHUP		 表示连接被挂起
	EPOLLET 		将触发⽅式设置为边缘触发,系统默认为⽔平触发
	EPOLLONESHOT 	表示该事件只处理⼀次,下次需要处理时需重新加⼊epoll

**epoll_wait系统调⽤**

在这里插入图片描述
收集 epoll 监控的事件中已经发⽣的事件,如果 epoll 中没有任何⼀个事件发⽣,则最多等待timeout 毫秒后返回。
返回:表示当前发⽣的事件个数
返回:0表示本次没有事件发⽣;
返回:-1表示出现错误,需要检查errno错误码判断错误类型。
注意:
events 这个数组必须在⽤户态分配内存,内核负责把就绪事件复制到该数组中;
maxevents 表示本次可以返回的最⼤事件数⽬,⼀般设置为 events 数组的⻓度;
timeout表示在没有检测到事件发⽣时最多等待的时间;如果设置为0,检测到rdllist为空⽴刻返回;如果设置为-1,⼀直等待;
在这里插入图片描述
所有添加到epoll的事件都会与网卡驱动程序建立回调关系,相应的事件发生时会调用这里的回调方法,他会把这样的事件放在rdlist双向链表中。

reactor模型

组成: 非阻塞的io + io多路复用
特征: 基于事件循环,以事件驱动或者事件回调的方式来实现业务逻辑
表述:将连接的io处理转化为事件处理

**单reactor模型**	
代表: redis

在这里插入图片描述

单reactor模型 + 任务队列 + 线程池

代表: skynet
在这里插入图片描述

多reactor

代表: memcache在这里插入图片描述

epoll处理细节图

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值