设为首页 加入收藏

TOP

handy网络库源码阅读(一)
2019-09-23 11:11:46 】 浏览:221
Tags: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\r\nConnection: Keep-Alive\r\nContent-Type: text/html; charset=UTF-8\r\nContent-Length: 1048576\r\n\r\n123456";
    for (int i = 0; i < 1048570; i++) {
        httpRes += '\0';
    }
//2)创建epoll实例
int epollfd = epoll_create(1);
//3)创建socket监听套接字listenfd,设置非阻塞模式,bind,listen和加入到epollfd关注
int listenfd = socket(AF_INET, SOCK_STREAM, 0);
int r = ::bind(listenfd, (struct sockaddr *) &addr, sizeof(struct sockaddr));
r = listen(listenfd, 20);
setNonBlock(listenfd);
updateEvents(epollfd, listenfd, EPOLLIN, EPOLL_CTL_ADD); //epoll_ctrl(epollfd,EPOLL_CTL_ADD,listenfd,ev.EPOLLIN)关注监听套接字的可读事件
//4)循环epoll_wait等待内核事件
for (;;) {  //实际应用应当注册信号处理函数,退出时清理资源
        loop_once(epollfd, listenfd, 10000); /
首页 上一页 1 2 3 4 5 6 7 下一页 尾页 1/9/9
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇C++的派生类构造函数是否要带上基.. 下一篇《游戏引擎构架Game Engine Archi..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目