handy网络库源码阅读
Posted dayoushen
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了handy网络库源码阅读相关的知识,希望对你有一定的参考价值。
简洁易用的C++11网络库,From:https://github.com/yedf/handy
在整理过去的资料过程中,发现过去有关注过这一个网络库,简单看了一下属于轻量级的实现,因此本文将对该库进行简单的学习之旅,目标是对网络基础知识进一步巩固。
编译和运行
库目前实现了linux和mac环境,需要支持C++11因此gcc的版本要大于4.8,在我的虚拟机ubuntu12.04是要升级gcc版本,然后使用云centos 7,之前安装的cmake版本是2.8.12,与要求的版本大于3.2不匹配,因此先升级cmake
$ cd /tmp
$ wget https://cmake.org/files/v3.3/cmake-3.3.2.tar.gz
$ tar xzvf cmake-3.3.2.tar.gz
$ cd cmake-3.3.2
$ ./bootstrap
$ gmake
$ make install
#FROM : https://blog.csdn.net/fword/article/details/79347356
升级后能顺利编译。
网络库基础知识
既然是高性能网络库,那linux必然是epoll,在raw-examples带有对epoll的测试epoll.cc(水平触发)和epoll-et.cc(边缘触发)
水平触发:当被监控的文件描述符上有可读写事件发生时,epoll_wait()会通知处理程序去读写。如果这次没有把数据一次性全部读写完(如读写缓冲区太小),那么下次调用 epoll_wait()时,它还会通知你在上没读写完的文件描述符上继续读写,当然如果你一直不去读写,它会一直通知你!如果系统中有大量你不需要读写的就绪文件描述符,而它们每次都会返回,这样会大大降低处理程序检索自己关心的就绪文件描述符的效率!
Edge_triggered(边缘触发):当被监控的文件描述符上有可读写事件发生时,epoll_wait()会通知处理程序去读写。如果这次没有把数据全部读写完(如读写缓冲区太小),那么下次调用epoll_wait()时,它不会通知你,也就是它只会通知你一次,直到该文件描述符上出现第二次可读写事件才会通知你!这种模式比水平触发效率高,系统不会充斥大量你不关心的就绪文件描述符!
水平触发和边缘触发
根据linux的man-page中说明边缘触发要求在EPOLL_CTRL_ADD的时候就对文件描述符进行EPOLLIN|EPOLLOUT|EPOLLET事件关注(建议只对客户端套接字),这能避免不断地使用EPOLL_CTL_MOD修改对EPOLLIN和EPOLLOUT事件地关注。通常情况下监听套接字为水平触发,客户套接字边缘触发,对监听套接字和客户套接字都要设置非阻塞模式。监听套接字使用水平触发的原因是,多个连接同时到达如果使用边缘触发则epoll只会通知一次,有一些TCP连接在就绪队列积累得不到及时处理,如果使用水平触发需要采取而外的处理方式(使用while循环accpet,直到accept返回-1且errno设置为EAGIN表示所有的连接处理完了)
EPOLL的系统函数定义如下:
#include <sys/epoll.h>
typedef union epoll_data {
void *ptr;
int fd;
uint32_t u32;
uint64_t u64;
} epoll_data_t;
struct epoll_event {
uint32_t events; // Epoll events
epoll_data_t data; // User data variable
};
/*
功能:创建epoll对象
[1]size无意义,要求大于0
返回值:成功为非负文件描述符,失败为-1
*/
int epoll_create(int size);
/*
功能:对epoll对象增加,修改或删除感兴趣事件,输入<文件描述符fd, 操作op, 事件epoll_event>
操作OP:增EPOLL_CTL_ADD,改EPOLL_CTL_MOD,删EPOLL_CTL_DEL
事件epoll_event.events:对应文件描述符可读EPOLLIN,可写EPOLLOUT,对方关闭EPOLLRDHUP,异常EPOLLPRI
,错误EPOLLERR,挂起EPOLLHUP,设置边缘触发EPOLLET,设置只触发一次EPOLLONESHOT,EPOLLWAKEUP,EPOLLEXCLUSIVE
返回值:0-成功,-1失败
*/
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
/*
功能:等待内核中的epoll_event事件可读或者timeout到达
[1]epfd是一个epoll实例句柄根据epoll_create得到
[2]epoll_event包含文件描述符和Epoll事件,对应内存由用户开辟
[3]最多事件数,必须大于0
[4]超时事件,单位为ms
返回值:>0有对应个文件描述符发生了事件;0超时到达;-1发生错误
*/
int epoll_wait(int epfd, struct epoll_event *events,
int maxevents, int timeout);
下面是代码节选
//epoll.cc 水平触发
//main函数
//0)忽略SIGPIPE信号,避免对等方关闭后触发了写操作引起的SIGPIPE信号,而导致进程退出
::signal(SIGPIPE, SIG_IGN);
//1)定义了回馈的报文,长度1048576是为了测试写缓冲区满了的情况
httpRes = "HTTP/1.1 200 OK
Connection: Keep-Alive
Content-Type: text/html; charset=UTF-8
Content-Length: 1048576
123456";
for (int i = 0; i < 1048570; i++) {
httpRes += '