muduo库阅读(39)——Net部分:接收者Accpetor
来源:互联网 发布:长绸扇子淘宝 编辑:程序博客网 时间:2024/04/30 14:09
Accpetor的作用如下:
1、创建监听(接收者)套接字
2、设置套接字选项
3、创建监听套接字的事件处理器,主要用于处理监听套接字的读事件(出现读事件表示有新的连接到来)
4、绑定地址
5、开始监听
1、创建监听(接收者)套接字
2、设置套接字选项
3、创建监听套接字的事件处理器,主要用于处理监听套接字的读事件(出现读事件表示有新的连接到来)
4、绑定地址
5、开始监听
6、等待事件到来
写服务器应用程序必须要考虑到服务器资源不足的情况,其中常见的一个是打开的文件数量(文件描述符数量)不能超过系统限制,当接受的连接太多时就会到达系统的限制,即表示打开的套接字文件描述符太多,从而导致accpet失败,返回EMFILE错误,但此时连接已经在系统内核建立好了,所以占用了系统的资源,我们不能让接受不了的连接继续占用系统资源,如果不处理这种错误就会有越来越多的内核连接建立,系统资源被占用也会越来越多,直到系统崩溃。一个常见的处理方式就是,先打开一个文件,预留一个文件描述符,出现EMFILE错误的时候,把打开的文件关闭,此时就会空出一个可用的文件描述符,再次调用accept就会成功,接受到客户连接之后,我们马上把它关闭,这样这个连接在系统中占用的资源就会被释放。关闭之后又会有一个文件描述符空闲,我们再次打开一个文件,占用文件描述符,等待下一次的EMFILE错误。
/* * 接收者Accpetor */namespace muduo{namespace net{class EventLoop;class InetAddress;////// Acceptor of incoming TCP connections.///class Acceptor : boost::noncopyable{public:// 新链接到来的回调函数typedef boost::function<void (int sockfd, const InetAddress&)> NewConnectionCallback;Acceptor(EventLoop* loop, const InetAddress& listenAddr, bool reuseport);~Acceptor();// 设置新链接到来的回调函数void setNewConnectionCallback(const NewConnectionCallback& cb){ newConnectionCallback_ = cb; }// 是否正在监听bool listenning() const { return listenning_; }// 监听void listen();private:// 处理读事件,acceptChannel_的读事件回调函数void handleRead();// 所属的ReactorEventLoop* loop_;// 监听/接收者套接字Socket acceptSocket_;// 监听套接字的事件处理器(主要处理读事件,即新链接到来的事件)Channel acceptChannel_;// 新链接到来的回调函数NewConnectionCallback newConnectionCallback_;// 是否正在监听bool listenning_;// 预留的空闲文件描述符,用于备用int idleFd_;};}}
/* * 构造函数,创建套接字,并设置套接字选项,然后绑定地址 * 设置事件处理的读事件回调函数 */Acceptor::Acceptor(EventLoop* loop, const InetAddress& listenAddr, bool reuseport): loop_(loop), acceptSocket_(sockets::createNonblockingOrDie()), acceptChannel_(loop, acceptSocket_.fd()), listenning_(false), idleFd_(::open("/dev/null", O_RDONLY | O_CLOEXEC)){assert(idleFd_ >= 0);// 地址复用acceptSocket_.setReuseAddr(true);// 端口复用acceptSocket_.setReusePort(reuseport);// 绑定地址acceptSocket_.bindAddress(listenAddr);// 设置读事件的回调函数acceptChannel_.setReadCallback(boost::bind(&Acceptor::handleRead, this));}Acceptor::~Acceptor(){acceptChannel_.disableAll();acceptChannel_.remove();::close(idleFd_);}// 监听void Acceptor::listen(){loop_->assertInLoopThread();listenning_ = true;acceptSocket_.listen();// 启用事件处理器的读功能acceptChannel_.enableReading();}void Acceptor::handleRead(){loop_->assertInLoopThread();InetAddress peerAddr;// 接受一个链接int connfd = acceptSocket_.accept(&peerAddr);if (connfd >= 0){// 调用新链接到来回调函数if (newConnectionCallback_){newConnectionCallback_(connfd, peerAddr);}else{sockets::close(connfd);}}// 发生错误else{LOG_SYSERR << "in Acceptor::handleRead";// 发生文件描述符不够用的情况if (errno == EMFILE){// 关闭预留的文件描述符::close(idleFd_);// 然后立即打开,即可得到一个可用的文件描述符,马上接受新链接idleFd_ = ::accept(acceptSocket_.fd(), NULL, NULL);// 然后立即关闭这个连接,表示服务器不再提供服务,因为系统资源已经不足// 服务器使用这个方法莱拒绝客户的连接::close(idleFd_);idleFd_ = ::open("/dev/null", O_RDONLY | O_CLOEXEC);}}}
0 0
- muduo库阅读(39)——Net部分:接收者Accpetor
- muduo库阅读(43)——Net部分:轮询器的epoll实现——EPollPoller
- muduo库阅读(29)——Net部分:Reactor(EventLoop事件循环)
- muduo库阅读(31)——Net部分:定时器(计时器)Timer
- muduo库阅读(32)——Net部分:定时器(计时器)ID类TimerId
- muduo库阅读(23)——Net部分:应用层缓冲区类
- muduo库阅读(24)——Net部分:网络地址类
- muduo库阅读(25)——Net部分:服务器端的套接字类
- muduo库阅读(26)——Net部分:套接字常用操作的封装
- muduo库阅读(27)——Net部分:字节顺序转换的封装
- muduo库阅读(28)——Net部分:各类回调函数的定义
- muduo库阅读(30)——Net部分:事件处理器Channel
- muduo库阅读(33)——Net部分:定时器队列TimerQueue
- muduo库阅读(34)——Net部分:轮询器基类Poller
- muduo库阅读(36)——Net部分:事件循环线程池EventLoopThreadPool
- muduo库阅读(37)——Net部分:压缩数据流ZlibOutputStream
- muduo库阅读(38)——Net部分:TCP连接TcpConnection
- muduo库阅读(40)——Net部分:TCP服务器TcpServer
- 重磅!8大策略让你对抗机器学习数据集里的不均衡数据
- 最大熵理论及其应用
- requestWindowFeature()使用简介
- 关键字高亮
- eXtremeDB HA 306 312 error
- muduo库阅读(39)——Net部分:接收者Accpetor
- 在按钮事件上添加参数传递
- Ubuntu 15 下 Qt 配置mysql链接及基本操作
- html5桌面通知(Web Notifications)实例解析
- 数据库索引浅析
- mysql now() , curdate() , curtime()
- vs2013中如何安装OpencvSharp并使用
- 类簇
- 文件上传smart