缩略moduo库(6):acceptor

2021-10-09 14:06:04 浏览数 (1)

文章目录

    • Socket
    • Acceptor

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:%dn",__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);
        }
    }
}

0 人点赞