前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >缩略moduo库(6):acceptor

缩略moduo库(6):acceptor

作者头像
看、未来
发布2021-10-09 14:06:04
2810
发布2021-10-09 14:06:04
举报

文章目录

Socket

代码语言:javascript
复制
#pragma once

#include "nocopyable.hpp"

class InetAddress;

//封装sockfd
class Socket:public nocpoyable{

public:
    explicit Socket(int sockfd)
        :sockfd_(sockfd)
    {}

    ~Socket();

    int fd(){ return sockfd_;}

    void bindAddress(const InetAddress &localaddr);
    void listen();
    int accept(InetAddress* peeraddr);
    void setReuseAddr(bool on);
    void setReusePort(bool on);
    
private:
    int sockfd_;
};
代码语言:javascript
复制
#include "socket.hpp"
#include "InetAddr.hpp"
#include "logger.hpp"

#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <strings.h>

Socket::~Socket(){
    close(sockfd_);
}

void Socket::bindAddress(const InetAddress &localaddr){
    if (0 == bind(sockfd_, (sockaddr *)localaddr.getSockAddr(), sizeof(sockaddr_in))){
        LOG_FATAL("sockets::bindOrDie");
    }
}

void Socket::listen(){
    if (0 != ::listen(sockfd_, 1024)){
        LOG_FATAL("sockets::listenOrDie");
    }
}

int Socket::accept(InetAddress *peeraddr){
    sockaddr_in addr;
    socklen_t len;
    bzero(&addr, sizeof(sockaddr_in));

    int confd = ::accept(sockfd_, (sockaddr *)&addr, &len);
    if (confd >= 0){
        peeraddr->setSockAddr(addr);
    }
    return confd;
}

void Socket::setReuseAddr(bool on){
    int optval = on ? 1 : 0;
    ::setsockopt(sockfd_, SOL_SOCKET, SO_REUSEADDR,
                 &optval, static_cast<socklen_t>(sizeof optval));
}

void Socket::setReusePort(bool on){
    int optval = on ? 1 : 0;
    int ret = ::setsockopt(sockfd_, SOL_SOCKET, SO_REUSEPORT,
                           &optval, static_cast<socklen_t>(sizeof optval));
    if (ret < 0 && on){
        LOG_FATAL("SO_REUSEPORT failed.");
    }
}

Acceptor

代码语言:javascript
复制
#pragma once

#include "nocopyable.hpp"
#include "channel.hpp"
#include "socket.hpp"

#include <functional>

class EventLoop;
class InetAddress;

class Accept : public nocpoyable
{
public:
    using NewConnectionCallBack = std::function<void(int sockfd, const InetAddress &)>;

    Accept(EventLoop *loop, const InetAddress &listenAddr, bool reuseport);
    ~Accept();

    void setNewConnectionCallback(const NewConnectionCallBack &cb){
        newConnectionCallback_ = cb;
    }

    void listen();

    bool listening() const { return listening_; }

private:
    void handleRead();

    EventLoop *loop_;   //mainloop
    Socket acceptSocket_;
    Channel acceptChannel_;
    NewConnectionCallBack newConnectionCallback_;
    bool listening_;
    int idleFd_;
};
代码语言:javascript
复制
#include "accept.hpp"
#include "logger.hpp"
//#include "eventloop.hpp"
#include "InetAddr.hpp"

#include <sys/socket.h>
#include <sys/types.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>

static int createNonblcking(){
    int sockfd = ::socket(AF_INET,SOCK_STREAM |SOCK_NONBLOCK,IPPROTO_TCP);
    if(sockfd < 0){
        LOG_FATAL("%s:%s:%d listen socket create err:%d\n",__FILE__,__FUNCTION__,__LINE__,errno);
    }
}

Accept::Accept(EventLoop *loop, const InetAddress &listenAddr, bool reuseport)
    : loop_(loop),
      acceptSocket_(createNonblcking()),
      acceptChannel_(loop, acceptSocket_.fd()),
      listening_(false),
      idleFd_(::open("/dev/null", O_RDONLY | O_CLOEXEC))
{
   
    acceptSocket_.setReuseAddr(true);
    acceptSocket_.setReusePort(reuseport);
    acceptSocket_.bindAddress(listenAddr);

    //监听到有客户端连接,执行一个回调,甩给字loop
    acceptChannel_.setReadCallback(std::bind(&Accept::handleRead, this));
}

Accept::~Accept()
{
    acceptChannel_.disableAll();
    acceptChannel_.remove();
    ::close(idleFd_);
}

void Accept::listen()
{
    listening_ = true;
    acceptSocket_.listen();
    acceptChannel_.enableReading();
}

void Accept::handleRead(){
    InetAddress peerAddr;
    int connfd = acceptSocket_.accept(&peerAddr);
    if (connfd >= 0){
        if (newConnectionCallback_){
            newConnectionCallback_(connfd, peerAddr);
        }
        else{
            ::close(connfd);
        }
    }
    else{
        LOG_ERROR("in Acceptor::handleRead");
        if (errno == EMFILE){
            ::close(idleFd_);
            idleFd_ = ::accept(acceptSocket_.fd(), NULL, NULL);
            ::close(idleFd_);
            idleFd_ = ::open("/dev/null", O_RDONLY | O_CLOEXEC);
        }
    }
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-09-05 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 文章目录
  • Socket
  • Acceptor
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档