简洁易用的c++11网络库,from:
在整理过去的资料过程中,发现过去有关注过这一个网络库,简单看了一下属于轻量级的实现,因此c/c++开发分享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 okrnconnection: keep-aliverncontent-type: text/html; charset=utf-8rncontent-length: 1048576rnrn123456"; for (int i = 0; i < 1048570; i++) { httpres += '