9. 王道_Reactor

常见并发服务器方案

    1. 循环式/迭代式( iterative )服务器

无法充分利用多核CPU,不适合执行时间较长的服务
在这里插入图片描述

    1. 并发式(concurrent)服务器
      适合执行时间比较长的服务
      在这里插入图片描述
    1. prefork or pre threaded(UNP2e 第27章)
      在这里插入图片描述
    1. 反应器( reactive )服务器 (reactor模式)
      并发处理多个请求,实际上是在一个线程中完成。无法充分利用多核CPU
      不适合执行时间比较长的服务,所以为了让客户感觉是在“并发”处理而不是“循环”处理,每个请求必须在相对较短时间内执行。

在这里插入图片描述

    1. reactor + thread per request(过渡方案)
    1. reactor + worker thread(过渡方案)
    1. reactor + thread pool(能适应密集计算)
      在这里插入图片描述
    1. multiple reactors(能适应更大的突发I/O)
      reactors in threads(one loop per thread)
      reactors in processes
      在这里插入图片描述
    1. multiple reactors + thread pool
       (one loop per thread + threadpool)(突发I/O与密集计算)
      在这里插入图片描述
  • 10. proactor服务器(前摄器模式、主动器模式,基于异步I/O)

在这里插入图片描述

Reactor VS Proactor

在这里插入图片描述

  • Reactor 和 Proactor 是两种异步 I/O 模型设计模式,在高性能网络编程中经常被提及,比如在使用 libevent、libuv、IOCP、epoll 等网络库时。
  • Reactor

在这里插入图片描述
在这里插入图片描述

  • Proactor
    在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

Reactor模型封装

ReactorV1封装

1、InetAddress:网络地址类,负责所有的地址相关的操作,获取ip地址,获取端口号,strcut
sockaddr_in
2、Socket:套接字类,所有的与套接字相关的,都可以用这个类。
3、Acceptor:连接器类,将所有的,端口复用、listen、bind、accept
4、TcpConnection:TCP连接类,该对象创建完毕,就表名三次握手己经建立完毕,该连接就是一个
TCP连接,该连接就可以进行发送数据与接收数据
5、SocketIO:真正进行数据发送与接收的类。

在这里插入图片描述

  • shutdown
    在这里插入图片描述

在这里插入图片描述
├── Acceptor.cc
├── Acceptor.h
├── a.out
├── InerAddress.cc
├── InetAddress.h
├── NonCopyable.h
├── Socket.cc
├── Socket.h
├── SocketIo.cc
├── SocketIo.h
├── TcpConnection.cc
├── TcpConnection.h
└── TestTcpConnection.cc

0 directories, 13 files

  • NonCopyable.h
#ifndef __NONCOPYABLE_H__
#define __NONCOPYABLE_H__

class NonCopyable
{
protected:
    NonCopyable() {}
    ~NonCopyable() {}
    NonCopyable(const NonCopyable &) = delete;
    NonCopyable &operator=(const NonCopyable &) = delete;
};

#endif
  • Socket.h
#ifndef __SOCKET_H__
#define __SOCKET_H__

#include "NonCopyable.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>


class Socket
:NonCopyable
{
public:
    Socket();
    explicit Socket(int fd);
    ~Socket();
    int fd()const;
    void shutDownWrite();

private:
    int _fd;
};

#endif
  • Socket.cc
#include "Socket.h"


Socket::Socket()
{
    // 创建监听服务器的套接字:wq
    _fd = ::socket(AF_INET,SOCK_STREAM,0);
    if(_fd <0)
    {
        perror("socket");
        return;
    }
}

Socket::Socket(int fd)
    :_fd(fd)
{}
Socket::~Socket()
{
    close(_fd);
}
int Socket::fd()const
{
    return _fd;
}
void Socket::shutDownWrite()
{
    // 关闭写端
    int ret = shutdown(_fd,SHUT_WR);
    if(ret)
    {
        perror("shutdown");
        return;
    }
}
  • InetAddress.h
#ifndef  __INETADDRESS_H__
#define __INETADDRESS_H__

#include<arpa/inet.h>
#include<string>

using std::string;

class InetAddress
{
public:
    InetAddress(const string &ip,unsigned short port);
    InetAddress(const struct sockaddr_in &addr);
    ~InetAddress();
    string ip()const;
    unsigned short port() const;
    const sockaddr_in * getInetAddrPtr()const;

private:
    struct sockaddr_in _addr;
};

#endif
  • InetAddress.cc
#include "InetAddress.h"
#include<string.h>


InetAddress::InetAddress(const string &ip,unsigned short port)
{
    ::bzero(&_addr,sizeof(struct sockaddr_in));
    _addr.sin_family = AF_INET;
    _addr.sin_port = htons(port);
    _addr.sin_addr.s_addr = inet_addr(ip.c_str());
}


InetAddress::InetAddress(const struct sockaddr_in &addr)
    :_addr(addr)
{}

InetAddress::~InetAddress()
{

}
string InetAddress::ip()const
{
    return string(inet_ntoa(_addr.sin_addr));
}
unsigned short InetAddress::port() const
{
    return ntohs(_addr.sin_port);

}

const sockaddr_in * InetAddress::getInetAddrPtr()const
{
    return &_addr;
}
  • Acceptor.h
#ifndef  __ACCEPTOR_H__
#define __ACCEPTOR_H__

#include"Socket.h"
#include"InetAddress.h"
#include<string>
using std::string;

class Acceptor
{
public:
    Acceptor(const string &ip,unsigned short port);
    ~Acceptor();
    void ready();
    void setReuseAddr();
    void setReusePort();
    void bind();
    void listen();
    int accetp();
    int fd()const;
private:
    Socket _listenSock;
    InetAddress _servAddr;
};



#endif
  • Acceptor.cc
#include "Acceptor.h"


Acceptor::Acceptor(const string &ip,unsigned short port)
:_listenSock(),_servAddr(ip,port)
{

}
Acceptor::~Acceptor()
{}
void Acceptor:: ready()
{
    setReuseAddr();
    setReusePort();
    bind();
    listen();
}
void Acceptor:: setReuseAddr()
{
    int on = 1;
    int ret = setsockopt(_listenSock.fd(),SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
    if(-1 == ret)
    {
        perror("setSockopt");
        return;
    }
}
void Acceptor:: setReusePort()
{
    int on = 1;
    int ret = setsockopt(_listenSock.fd(),SOL_SOCKET,SO_REUSEPORT,&on,sizeof(on));
    if(-1 == ret)
    {
        perror("setSockopt");
        return;
    }

}
void Acceptor:: bind()
{
    int ret = ::bind(_listenSock.fd(),(struct sockaddr*)_servAddr.getInetAddrPtr(),sizeof(struct sockaddr));
    if(-1 == ret)
    {
        perror("bind");
        return;
    }
}
void Acceptor:: listen()
{
    int ret = ::listen(_listenSock.fd(),128);
    if(-1 == ret)
    {
        perror("listen");
        return;
    }

}
int Acceptor:: accetp()
{
    int connfd = ::accept(_listenSock.fd(),nullptr,nullptr);
    if(-1 == connfd)
    {
        perror("listen");
        return -1;
    }
    return connfd;
}
int Acceptor:: fd()const
{
    return _listenSock.fd();
}
  • SocketIo.h
#ifndef  __SOCKETIO_H__
#define __SOCKETIO_H__

class SocketIo
{
public:
   explicit SocketIo(int fd);
    ~SocketIo() ;
    int readn(char *buf,int len);
    int readLine(char *buf,int len);
    int writen(const char *buf,int len);
private:
    int _fd;
};

#endif
  • SocketIo.cc
#include"SocketIo.h"
#include<sys/types.h>
#include<sys/socket.h>
#include <unistd.h>
#include <errno.h>
#include<stdio.h>

SocketIo::SocketIo(int fd)
:_fd(fd){}
SocketIo::~SocketIo()
{}
int SocketIo::readn(char *buf,int len)
{
    int left = len;
    char *pstr = buf;
    int ret = 0;

    while(left>0)
    {
        ret = read(_fd,pstr,left);
        if(-1 == ret && errno == EINTR)
        {
            continue;
        }
        else if(-1 == ret)
        {
            perror("read error -1");
            return len-ret;
        }
        else if(0 == ret)
        {
            break;
        }
        else
        {
            pstr+=ret;
            left-=ret;
        }
    }
    return len-left;
}
int SocketIo::readLine(char  *buf,int len)
{
    int left = len -1;
    char *pstr = buf;
    int ret = 0,total = 0;
    while(left>0)
    {   // 不会将缓冲区中的数据清空
        ret = recv(_fd,pstr,left,MSG_PEEK);  // MSG_PEEK:只会将数据从内核拷出而不会移走数据:wq

        if(-1 == ret && errno == EINTR)
        {
            continue;
        }
        else if(-1 == ret)
        {
            perror("readLine  error -1");
            return len-ret;
        }
        else if(0 == ret)
        {
            break;
        }
        else
        {
            for(int idx = 0;idx<ret;++idx)
            {
                if(pstr[idx] == '\n')
                {
                    int sz = idx+1;
                    readn(pstr,sz);
                    pstr+=sz;
                    *pstr = '\0';
                    return total+sz;
                }
            }
            readn(pstr,ret);// 从内核态k拷贝到t用户态
            total+=ret;
            pstr += ret;
            left-=ret;
        }
    }
}
int SocketIo::writen(const char *buf,int len)
{
    int left = len;
    const char *pstr = buf;
    int ret = 0;

    while(left>0)
    {
        ret = write(_fd,pstr,left);
        if(-1 == ret && errno == EINTR)
        {
            continue;
        }
        else if(-1 == ret)
        {
            perror("write error -1");
            return len-ret;
        }
        else if(0 == ret)
        {
            break;
        }
        else
        {
            pstr+=ret;
            left-=ret;
        }

    }
}
  • TcpConnection.h
#ifndef __TCPCONNECTION_H__
#define __TCPCONNECTION_H__
#include"Socket.h"
#include "SocketIo.h"
#include "InetAddress.h"
#include <iostream>

class TcpConnection
{
public:
    TcpConnection(int fd);
    ~TcpConnection();
    void send(const string &msg);
    string receive();
    string toString();
private:
    InetAddress getLocalAddr();
    InetAddress getPeerAddr();
private:
    Socket _sock;
    SocketIo _sockIo;
    InetAddress _localAddr;
    InetAddress _peerAddr;
};


#endif
  • TcpConnection.cc
#include "TcpConnection.h"
#include <sstream>

TcpConnection::TcpConnection(int fd)
:_sock(fd),_sockIo(fd),_localAddr(getLocalAddr()),_peerAddr(getPeerAddr())
{}
TcpConnection::~TcpConnection()
{

}
void TcpConnection::send(const string &msg)
{
    _sockIo.writen(msg.c_str(),msg.size());
}

string TcpConnection::receive()
{
    char buf[65535] = {0};
    _sockIo.readLine(buf,sizeof(buf));

    return string(buf);
}
string TcpConnection::toString()
{
    std::ostringstream oss;
    oss<<_localAddr.ip()<<":"
        <<_localAddr.port()<<"---->"
        <<_peerAddr.ip()<<":"
        <<_peerAddr.port();
    return oss.str();
}

// 获取本端的地址信息
InetAddress TcpConnection::getLocalAddr()
{
    struct sockaddr_in addr;
    socklen_t len = sizeof(struct sockaddr);
    int ret = getsockname(_sock.fd(),(struct sockaddr*)&addr,&len);
    if(-1 == ret)
    {
        perror("getsockname");
    }
    return InetAddress(addr);

}
// 获取对端的地址信息
InetAddress TcpConnection::getPeerAddr()
{
    struct sockaddr_in addr;
    socklen_t len = sizeof(struct sockaddr);
    int ret = getpeername(_sock.fd(),(struct sockaddr*)&addr,&len);
    if(-1 == ret)
    {
        perror("getPerrname");
    }
    return InetAddress(addr);
}
  • TestTcpConnection.cc
#include "Acceptor.h"
#include "TcpConnection.h"
#include <unistd.h>
#include <iostream>
using std::cout;
using std::endl;

void test()
{
    Acceptor acceptor("127.0.0.1",8888);
    acceptor.ready(); // 此时处于监听状态

    // 三次握手就已经建立,可以创建一条TCP链接
    TcpConnection con(acceptor.accetp());
    cout<<con.toString()<<"  has connected"<<endl;

    while(1)
    {
        cout<<">> recv msg from client :"<<con.receive()<<endl;
        con.send("hello baby\n");
    }
}


int main()
{
    test();
    std::cout << "Hello world" << std::endl;
    return 0;
}

缺点只能与一个客户端通信

ReactorV2封装

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

框架


void waitEpollFd()
{
    nready = epoll_wait;
    if (-1 == nready && errno == EINTR)
    {
        //....
    }
    else if (-1 == nready)
    {
        perror;
        return;
    }
    else if (0 == nready)
    {
        printf("");
    }
    else
    {
        for (idx = 0; idx < nready; ++idx)
            ;
        {
            if (fd == listenfd)
            {
                // 处理新的链接
                handleNewConnetion();
            }
            else
            {
                // 数据的收发
                handleMessage(fd);
            }
        }
    }
}
void handleNewConnetion()
{
    // 三次握手就建立
    peerfd = accptor.accept;
    // 创建tcp链接
    TcpConnecttion con(peerfd);
    // 注册三个回调函数
    con.setConnectCallback();
    con.setMessageCallback();
    con.setCloseCallback();
    // 把peerfd与con存在数据结构里面去map<peerfd, con>
    con.handleConnectionCallback();
}
void handleMessage(fd)
{
    // 本来应该做数据的发送与接收
    n = recv;
    if (n > 0)
    {
        write();
    }
    else if (n < 0)
    {
        // 异常处理
    }
    else
    {
        // n = 0
        // 断开连接
        // 文件描述符fd从红黑树上删除
    }
}

天坑


#include <iostream>
#include <functional>
using namespace std;

void print()
{
    cout << "print" << endl;
}
using funPtr = function<void()>;

class A2
{

public:
    void set(funPtr &cb)
    {
        _Fun2 = std::move(cb);
    }

    funPtr _Fun2;
};
class A1
{

public:
    A1(funPtr &&cb)
    {
        _Fun1 = std::move(cb);
    }
    void setA2()
    {
        printf("%d\n", _Fun1 == NULL); // 0
        A2 a2;
        a2.set(_Fun1);
        printf("%d\n", _Fun1 == NULL); // 1
    }

    funPtr _Fun1;
};

int main()
{
    A1 a1(print);
    a1.setA2();
    return 0;
}

在这里插入图片描述
在这里插入图片描述在这里插入图片描述
在这里插入图片描述

注意参看其中的TcpConnection.cc和EventLoop.cc,TestEventLoop.cc

[yangpipi Reactor]$bash mycat.bash  *.cc *.h
======== Acceptor.cc ========
#include "Acceptor.h"


Acceptor::Acceptor(const string &ip,unsigned short port)
:_listenSock(),_servAddr(ip,port)
{

}
Acceptor::~Acceptor()
{}
void Acceptor:: ready()
{
    setReuseAddr();
    setReusePort();
    bind();
    listen();
}
void Acceptor:: setReuseAddr()
{
    int on = 1;
    int ret = setsockopt(_listenSock.fd(),SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
    if(-1 == ret)
    {
        perror("setSockopt");
        return;
    }
}
void Acceptor:: setReusePort()
{
    int on = 1;
    int ret = setsockopt(_listenSock.fd(),SOL_SOCKET,SO_REUSEPORT,&on,sizeof(on));
    if(-1 == ret)
    {
        perror("setSockopt");
        return;
    }

}
void Acceptor:: bind()
{
    int ret = ::bind(_listenSock.fd(),(struct sockaddr*)_servAddr.getInetAddrPtr(),sizeof(struct sockaddr));
    if(-1 == ret)
    {
        perror("bind");
        return;
    }
}
void Acceptor:: listen()
{
    int ret = ::listen(_listenSock.fd(),128);
    if(-1 == ret)
    {
        perror("listen");
        return;
    }

}
int Acceptor::accept()
{
    int connfd = ::accept(_listenSock.fd(),nullptr,nullptr);
    if(-1 == connfd)
    {
        perror("accept");
        return -1;
    }
    return connfd;
}
int Acceptor:: fd()const
{
    return _listenSock.fd();
}



======== EventLoop.cc ========
#include "EventLoop.h"

EventLoop::EventLoop(Acceptor &acceptor)
:_epfd(createEpollFd()),_acceptor(acceptor),
    _isLooping(false),_evtList(1024)
{
    addEpollReadFd(acceptor.fd()); // 注意这里使用了Acceptor中的成员,所以头文件就不能只是前向声明需要包含头文件
    // 把listefd放到红黑树上进行监听:w
    //
}
EventLoop::~EventLoop()
{
    if(_epfd)
    {
        close(_epfd);
    }
}
void EventLoop:: loop()
{
    _isLooping = true;
    while(_isLooping)
    {
        waitEpollFd();
    }
}
void EventLoop:: unloop()
{
    _isLooping = false;
}

void EventLoop:: waitEpollFd()
{
    int nready = -1;
    do
    {
        nready = ::epoll_wait(_epfd,&*_evtList.begin(),_evtList.size(),5000); // 注意这里的vector如何接入C语言参数

    }while(-1 == nready && errno == EINTR);

    if(-1 == nready)
    {
        perror("nready == -1\n");
        return;
    }
    else if(0 == nready)
    {
        printf(">> epoll_wait timeout\n");
    }
    else
    {
        if(nready == (int)_evtList.size()) //监听超过上限
        {
            _evtList.resize(2*nready);
        }
        for(int idx = 0;idx<nready;++idx)
        {
            int fd = _evtList[idx].data.fd;
            if(fd == _acceptor.fd()) // 有新的连接请求进来
            {
                if(_evtList[idx].events & EPOLLIN) // 判断该事件是否是读事件
                {
                    handleNewConnection();
                }
            }
            else
            {
                if(_evtList[idx].events & EPOLLIN)
                {
                    handleMessage(fd);
                }
            }
        }
    }
}

void EventLoop::handleNewConnection()
{
    //只要peerfd有正确的返回值,就证明三次握手建立成功
    int peerfd = _acceptor.accept();
    if(peerfd == -1)
    {
        perror("_acceptor.acceptc出错");
        return;
    }
    addEpollReadFd(peerfd); // 将peerfd放到红黑树中

    TcpConnectionPtr con(new TcpConnection(peerfd));
    //con->setConnectionCallback(std::move(_onConnectionCb));// 消息建立
    //con->setMessageCallback(std::move(_onMessageCb));   //消息到达
    //con->setCloseCallback(std::move(_onCloseCb));   // 连接的断开
    con->setConnectionCallback(_onConnectionCb);// 消息建立
    con->setMessageCallback(_onMessageCb);   //消息到达
    con->setCloseCallback(_onCloseCb);   // 连接的断开

    _conns.insert(std::make_pair(peerfd,con));
    con->handleConnectionCallback();
    //std::cout<<con->toString()<<" has connected"<<std::endl;
}

void EventLoop:: handleMessage(int fd)
{   // 找到对应的cnewf
    auto iter = _conns.find(fd);
    if(iter != _conns.end())
    {
        // 用TCP连接里面定义一个函数
        // isClose,里面执行recv,recv的返回值就等于0
        bool flag = iter->second->isClosed();
        printf("size() = %zu\n",_conns.size());
        // 连接是断开的
        if(flag)
        {
            iter->second->hansetCloseCallback();
            delEpollReadFd(fd); // 将文件描述符从红黑树上删除
            ::close(fd);
            _conns.erase(iter); // 将文件描述符从map种删除
        }
        else
        {
            //连接是正常的
            iter->second->hansetMessageCallback();
        }

    }
    else
    {
        printf("该连接是断开的\n");
    }
}

int EventLoop::createEpollFd()
{
    int fd = epoll_create(100);
    if(-1 == fd)
    {
        perror("epoll_create");
        return -1;
    }
    return fd;
}

void EventLoop:: addEpollReadFd(int fd)
{
    struct epoll_event evt;
    evt.events = EPOLLIN;
    evt.data.fd = fd;

    int ret = ::epoll_ctl(_epfd,EPOLL_CTL_ADD,fd,&evt);
    if(ret == -1)
    {
        perror("epoll_ctl add");
        return;
    }
}

void EventLoop:: delEpollReadFd(int fd)
{
    struct epoll_event evt;
    evt.events = EPOLLIN;
    evt.data.fd = fd;

    int ret = ::epoll_ctl(_epfd,EPOLL_CTL_DEL,fd,&evt);
    if(ret == -1)
    {
        perror("epoll_ctl del");
        return;
    }

}

void EventLoop:: setConnectionCallback(TcpConnectionCallback&& cb)
{
   _onConnectionCb = std::move(cb);
   // _onConnectionCb = cb;
}

void EventLoop:: setMessageCallback(TcpConnectionCallback&& cb)
{
    _onMessageCb = std::move(cb);
   //_onMessageCb = cb;
}

void EventLoop:: setCloseCallback(TcpConnectionCallback&& cb)
{
     _onCloseCb = std::move(cb);
   // _onCloseCb = cb;
}
======== InetAddress.cc ========
#include "InetAddress.h"
#include<string.h>


InetAddress::InetAddress(const string &ip,unsigned short port)
{
    ::bzero(&_addr,sizeof(struct sockaddr_in));
    _addr.sin_family = AF_INET;
    _addr.sin_port = htons(port);
    _addr.sin_addr.s_addr = inet_addr(ip.c_str());
}


InetAddress::InetAddress(const struct sockaddr_in &addr)
    :_addr(addr)
{}

InetAddress::~InetAddress()
{

}
string InetAddress::ip()const
{
    return string(inet_ntoa(_addr.sin_addr));
}
unsigned short InetAddress::port() const
{
    return ntohs(_addr.sin_port);

}

const sockaddr_in * InetAddress::getInetAddrPtr()const
{
    return &_addr;
}
======== Socket.cc ========
#include "Socket.h"


Socket::Socket()
{
    // 创建监听服务器的套接字:wq
    _fd = ::socket(AF_INET,SOCK_STREAM,0);
    if(_fd <0)
    {
        perror("socket");
        return;
    }
}

Socket::Socket(int fd)
    :_fd(fd)
{}
Socket::~Socket()
{
    close(_fd);
}
int Socket::fd()const
{
    return _fd;
}
void Socket::shutDownWrite()
{
    // 关闭写端
    int ret = shutdown(_fd,SHUT_WR);
    if(ret)
    {
        perror("shutdown");
        return;
    }
}
======== SocketIo.cc ========
#include"SocketIo.h"
#include<sys/types.h>
#include<sys/socket.h>
#include <unistd.h>
#include <errno.h>
#include<stdio.h>

SocketIo::SocketIo(int fd)
:_fd(fd){}
SocketIo::~SocketIo()
{}
int SocketIo::readn(char *buf,int len)
{
    int left = len;
    char *pstr = buf;
    int ret = 0;

    while(left>0)
    {
        ret = read(_fd,pstr,left);
        if(-1 == ret && errno == EINTR)
        {
            continue;
        }
        else if(-1 == ret)
        {
            perror("read error -1");
            return len-ret;
        }
        else if(0 == ret)
        {
            break;
        }
        else
        {
            pstr+=ret;
            left-=ret;
        }
    }
    return len-left;
}
int SocketIo::readLine(char  *buf,int len)
{
    int left = len -1;
    char *pstr = buf;
    int ret = 0,total = 0;
    while(left>0)
    {   // 不会将缓冲区中的数据清空
        ret = recv(_fd,pstr,left,MSG_PEEK);  // MSG_PEEK:只会将数据从内核拷出而不会移走数据:wq

        if(-1 == ret && errno == EINTR)
        {
            continue;
        }
        else if(-1 == ret)
        {
            perror("readLine  error -1");
            return len-ret;
        }
        else if(0 == ret)
        {
            break;
        }
        else
        {
            for(int idx = 0;idx<ret;++idx)
            {
                if(pstr[idx] == '\n')
                {
                    int sz = idx+1;
                    readn(pstr,sz);
                    pstr+=sz;
                    *pstr = '\0';
                    return total+sz;
                }
            }
            readn(pstr,ret);// 从内核态k拷贝到t用户态
            total+=ret;
            pstr += ret;
            left-=ret;
        }
    }
    return total;
}
int SocketIo::writen(const char *buf,int len)
{
    int left = len;
    const char *pstr = buf;
    int ret = 0;

    while(left>0)
    {
        ret = write(_fd,pstr,left);
        if(-1 == ret && errno == EINTR)
        {
            continue;
        }
        else if(-1 == ret)
        {
            perror("write error -1");
            return len-ret;
        }
        else if(0 == ret)
        {
            break;
        }
        else
        {
            pstr+=ret;
            left-=ret;
        }

    }
}
======== TcpConnection.cc ========
#include "TcpConnection.h"
#include <sstream>

TcpConnection::TcpConnection(int fd)
:_sock(fd),_sockIo(fd),_localAddr(getLocalAddr()),_peerAddr(getPeerAddr())
{}
TcpConnection::~TcpConnection()
{

}
void TcpConnection::send(const string &msg)
{
    _sockIo.writen(msg.c_str(),msg.size());
}

string TcpConnection::receive()
{
    char buf[65535] = {0};
    _sockIo.readLine(buf,sizeof(buf));

    return string(buf);
}
string TcpConnection::toString()
{
    std::ostringstream oss;
    oss<<_localAddr.ip()<<":"
        <<_localAddr.port()<<"---->"
        <<_peerAddr.ip()<<":"
        <<_peerAddr.port();
    return oss.str();
}

// 获取本端的地址信息
InetAddress TcpConnection::getLocalAddr()
{
    struct sockaddr_in addr;
    socklen_t len = sizeof(struct sockaddr);
    int ret = getsockname(_sock.fd(),(struct sockaddr*)&addr,&len);
    if(-1 == ret)
    {
        perror("getsockname");
    }
    return InetAddress(addr);

}
// 获取对端的地址信息
InetAddress TcpConnection::getPeerAddr()
{
    struct sockaddr_in addr;
    socklen_t len = sizeof(struct sockaddr);
    int ret = getpeername(_sock.fd(),(struct sockaddr*)&addr,&len);
    if(-1 == ret)
    {
        perror("getPerrname");
    }
    return InetAddress(addr);
}

void TcpConnection:: setConnectionCallback(TcpConnectionCallback cb)// 消息建立
{
     _onConnectionCb = std::move(cb);

}
void TcpConnection:: setMessageCallback(TcpConnectionCallback cb)   //消息到  达
{
    _onMessageCb = std::move(cb);
}
void TcpConnection:: setCloseCallback(TcpConnectionCallback cb)   // 连接的断开
{
   _onCloseCb = std::move(cb);
}
//void TcpConnection:: setConnectionCallback(TcpConnectionCallback &cb)// 消息建立
//{
//    // _onConnectionCb = std::move(cb);
//     _onConnectionCb = cb;
//
//}
//void TcpConnection:: setMessageCallback(TcpConnectionCallback &cb)   //消息到  达
//{
//    //_onMessageCb = std::move(cb);
//    _onMessageCb = cb;
//}
//void TcpConnection:: setCloseCallback(TcpConnectionCallback &cb)   // 连接的断开
//{
//   // _onCloseCb = std::move(cb);
//   _onCloseCb = cb;
//}
// 执行回调函数
void TcpConnection:: handleConnectionCallback()
{
    printf("执行conn1  %d\n",_onConnectionCb!=NULL);
    if(_onConnectionCb)
    {
    printf("执行conn=2printf \n");
        //_onConnectionCb(shared_ptr(this)); 只能指针的误用
        _onConnectionCb(shared_from_this());
    }
}

void TcpConnection:: hansetMessageCallback()
{
    if(_onMessageCb)
    {
        _onMessageCb(shared_from_this());
    }
}
void TcpConnection:: hansetCloseCallback()
{
    if(_onCloseCb)
    {
        _onCloseCb(shared_from_this());
    }
}

bool TcpConnection::isClosed()const
{
    char buf[10] ={};
    int ret = ::recv(_sock.fd(),buf,sizeof(buf),MSG_PEEK); // 最后一个参数不取0,目的不是取出数据:w
    return (ret==0);
}

======== TestEventLoop.cc ========
#include "Acceptor.h"
#include "TcpConnection.h"
#include "EventLoop.h"
#include <unistd.h>
#include <iostream>
using std::cout;
using std::endl;

void onConnection(const TcpConnectionPtr &con )
{
    cout<<con->toString()<<" has connected"<<endl;
}

void onMessage(const TcpConnectionPtr &con)
{
    string msg = con->receive();
    cout<<" recv msg "<<msg<<endl;
    // 接受与发送之间,消息msg是没有做任何处理
    con->send(msg);
}

void onClose(const TcpConnectionPtr &con)
{

    cout<<con->toString()<<" has closed"<<endl;
}

void test()
{
    Acceptor acceptor("127.0.0.1",1234);
    acceptor.ready(); // 此时处于监听状态

    EventLoop loop(acceptor);
    loop.setConnectionCallback(std::move(onConnection));
    loop.setMessageCallback(std::move(onMessage));
    loop.setCloseCallback(std::move(onClose));
    //loop.setConnectionCallback(onConnection);
   // loop.setMessageCallback(onMessage);
    //loop.setCloseCallback(onClose);
    loop.loop();
}


int main()
{
    test();
    std::cout << "Hello world" << std::endl;
    return 0;
}

======== Acceptor.h ========
#ifndef  __ACCEPTOR_H__
#define __ACCEPTOR_H__

#include"Socket.h"
#include"InetAddress.h"
#include<string>
using std::string;

class Acceptor
{
public:
    Acceptor(const string &ip,unsigned short port);
    ~Acceptor();
    void ready();
    void setReuseAddr();
    void setReusePort();
    void bind();
    void listen();
    int accept();
    int fd()const;
private:
    Socket _listenSock;
    InetAddress _servAddr;
};



#endif
======== EventLoop.h ========
#ifndef  __EVENTLOOP_H__
#define __EVENTLOOP_H__

#include "Acceptor.h"
#include "TcpConnection.h"
#include<sys/epoll.h>
#include <unistd.h>
#include <vector>
#include <map>
#include <memory>
#include <functional>

using std::vector;
using std::map;
using std::shared_ptr;
using std::function;
using TcpConnectionPtr = shared_ptr<TcpConnection>;
using TcpConnectionCallback = function<void(const TcpConnectionPtr&)>;
class EventLoop
{
public:
    EventLoop(Acceptor &acceptor);
    ~EventLoop();
    void loop();
    void unloop();
    void setConnectionCallback(TcpConnectionCallback&& cb);// 消息建立
    void setMessageCallback(TcpConnectionCallback&& cb);   //消息到  达
    void setCloseCallback(TcpConnectionCallback&& cb);   // 连接的断开
private:
    void waitEpollFd();
    void handleNewConnection();
    void handleMessage(int fd);
    int createEpollFd();
    void addEpollReadFd(int fd);
    void delEpollReadFd(int fd);


private:
    int _epfd;
    Acceptor &_acceptor;
    bool _isLooping;
    vector<struct epoll_event> _evtList;
    //map<int,shared_ptr<TcpConnection>> _conns;  // netfd和TcpConnecton都是唯一的
    map<int,TcpConnectionPtr> _conns;  // netfd和TcpConnecton都是唯一的

    // 三个回调函数
   TcpConnectionCallback   _onConnectionCb;
   TcpConnectionCallback   _onMessageCb;
   TcpConnectionCallback   _onCloseCb;
};

#endif
======== InetAddress.h ========
#ifndef  __INETADDRESS_H__
#define __INETADDRESS_H__

#include<arpa/inet.h>
#include<string>

using std::string;

class InetAddress
{
public:
    InetAddress(const string &ip,unsigned short port);
    InetAddress(const struct sockaddr_in &addr);
    ~InetAddress();
    string ip()const;
    unsigned short port() const;
    const sockaddr_in * getInetAddrPtr()const;

private:
    struct sockaddr_in _addr;
};

#endif
======== NonCopyable.h ========
#ifndef __NONCOPYABLE_H__
#define __NONCOPYABLE_H__

class NonCopyable
{
protected:
    NonCopyable() {}
    ~NonCopyable() {}
    NonCopyable(const NonCopyable &) = delete;
    NonCopyable &operator=(const NonCopyable &) = delete;
};

#endif
======== Socket.h ========
#ifndef __SOCKET_H__
#define __SOCKET_H__

#include "NonCopyable.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>


class Socket
:NonCopyable
{
public:
    Socket();
    explicit Socket(int fd);
    ~Socket();
    int fd()const;
    void shutDownWrite();

private:
    int _fd;
};

#endif
======== SocketIo.h ========
#ifndef  __SOCKETIO_H__
#define __SOCKETIO_H__

class SocketIo
{
public:
   explicit SocketIo(int fd);
    ~SocketIo() ;
    int readn(char *buf,int len);
    int readLine(char *buf,int len);
    int writen(const char *buf,int len);
private:
    int _fd;
};

#endif
======== TcpConnection.h ========
#ifndef __TCPCONNECTION_H__
#define __TCPCONNECTION_H__
#include"Socket.h"
#include "SocketIo.h"
#include "InetAddress.h"
#include <iostream>
#include <functional>
#include <memory>

using std::shared_ptr;
using std::function;
class TcpConnection:public std::enable_shared_from_this<TcpConnection>
{
    using TcpConnectionPtr = shared_ptr<TcpConnection>;
    using TcpConnectionCallback = function<void(const TcpConnectionPtr&)>;
public:
    TcpConnection(int fd);
    ~TcpConnection();
    void send(const string &msg);
    string receive();
    string toString();
    // 注册回调函数
    void setConnectionCallback(TcpConnectionCallback cb);// 消息建立
    void setMessageCallback(TcpConnectionCallback cb);   //消息到  达
    void setCloseCallback(TcpConnectionCallback cb);   // 连接的断开

    // 执行回调函数
    void handleConnectionCallback();
    void hansetMessageCallback();
    void hansetCloseCallback();

    bool isClosed()const;
private:
    InetAddress getLocalAddr();
    InetAddress getPeerAddr();
private:
    Socket _sock;
    SocketIo _sockIo;
    InetAddress _localAddr;
    InetAddress _peerAddr;
    TcpConnectionCallback   _onConnectionCb;
    TcpConnectionCallback   _onMessageCb;
    TcpConnectionCallback   _onCloseCb;
};


#endif

ReactorV3封装

  • 主要是加入了TcpServer

在这里插入图片描述
在这里插入图片描述

上几个版本的问题

在这里插入图片描述
在这里插入图片描述

解决方案:业务逻辑的处理交给其他的线程
在这里插入图片描述
在这里插入图片描述

Reactorv4

在这里插入图片描述
在这里插入图片描述

 	  class MyTask
    9 {
   10 public:
   11     MyTask(const string &msg,const TcpConnectionPtr &con)
   12         :_msg(msg),_con(con)
   13     {
   14
   15     }
   16
   17     void process()
   18     {
   19         // process函数中去进行真正的业务逻辑的处理
   20         // 现在计算线程(ThreadPool)处理完业务逻辑之后,需要
   21         // 将处理完数据发送给IO线程(EveneLoop/Reactor)
   22         // IO线程如何与计算线程进行通信i
   23                                                                                                                                                                                                                 24         _con->send(_msg);
   25     }
   26 private:
   27     string _msg;
   28     TcpConnectionPtr _con;
   29 };

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


[yangpipi C++]$cat EventFd.c
#include <sys/eventfd.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>             /* Definition of uint64_t */

#define handle_error(msg) \
        do { perror(msg); exit(EXIT_FAILURE); } while (0)

int main(int argc, char *argv[])
{
        int efd, j;
        uint64_t u;
        ssize_t s;

        if (argc < 2) {
                fprintf(stderr, "Usage: %s <num>...\n", argv[0]);
                exit(EXIT_FAILURE);
        }

        efd = eventfd(10, 0);
        if (efd == -1)
                handle_error("eventfd");

        switch (fork()) {
        case 0:
                for (j = 1; j < argc; j++) {
                        printf("Child writing %s to efd\n", argv[j]);
                        u = strtoull(argv[j], NULL, 0);
                        /* strtoull() allows various bases */
                        s = write(efd, &u, sizeof(uint64_t));
                        if (s != sizeof(uint64_t))
                                handle_error("write");
                }
                printf("Child completed write loop\n");

                exit(EXIT_SUCCESS);

        default:
                sleep(2);

                printf("Parent about to read\n");
                s = read(efd, &u, sizeof(uint64_t));
                if (s != sizeof(uint64_t))
                        handle_error("read");
                printf("Parent read %llu (0x%llx) from efd\n",
                           (unsigned long long) u, (unsigned long long) u);
                exit(EXIT_SUCCESS);

        case -1:
                handle_error("fork");
        }
}

封装Eventfd

在这里插入图片描述
在这里插入图片描述


[yangpipi EventFd]$bash mycat.bash  *
======== EventFd.cc ========
#include "EventFd.h"
#include <unistd.h>
#include <sys/eventfd.h>
#include <poll.h>

EventFd::EventFd(EventFdCallback &&cb)
:_evtfd(createEventFd()),
    _cb(std::move(cb)),
    _isStarted(false)
{

}

EventFd::~EventFd()
{
    if(_evtfd)
    {
        close(_evtfd);
    }
}

void EventFd:: start()
{
    struct pollfd pfd;
    pfd.fd = _evtfd;
    pfd.events = POLLIN;

    _isStarted = true;
    while(_isStarted)
    {
        int nready = ::poll(&pfd,1,5000);
        if(-1 == nready && errno == EINTR)
        {
            continue;
        }
        else if(-1 == nready)
        {
            perror("-1 == nreadt");
            return;
        }
        else if(0 == nready)
        {
            printf(">> poll timeout\n");
        }
        else
        {
            if(pfd.revents & POLLIN)
            {
                handleRead(); // 进行read
                if(_cb)
                {
                    _cb(); // zz执行相应的任务
                }
            }
        }
    }
}

void EventFd:: stop()
{
    _isStarted = false;
}

void EventFd::wakeup()
{
    uint64_t one = 1;
    int ret = ::write(_evtfd,&one,sizeof(one));
    if(ret != sizeof(one))
    {
        perror("write");
        return;
    }
}

void EventFd:: handleRead()
{
    uint64_t one = 1;
    int ret = ::read(_evtfd,&one,sizeof(one));
    if(ret != sizeof(one))
    {
        perror("write");
        return;
    }

}

int EventFd::createEventFd()
{
    int fd = eventfd(10,0);
    if(-1 == fd)
    {
        perror("eventfd");
        return -1;
    }

    return fd;
}
======== EventFd.h ========
#ifndef  __EVENTFD_H__
#define __EVENTFD_H__
#include <functional>
using std::function;


class EventFd
{
    using EventFdCallback = function<void()>;
public:
    EventFd(EventFdCallback &&cb);
    ~EventFd();
    void start();
    void stop();
    void wakeup();
private:
    void handleRead();
    int createEventFd();
private:
    int _evtfd;
    EventFdCallback _cb;
    bool _isStarted;
};
#endif
======== mycat.bash ========
for file in "$@"; do
    echo "======== $file ========"
    cat "$file"
done

======== TestEventFd.cc ========
#include "EventFd.h"
#include "Thread.h"
#include <iostream>
#include <unistd.h>



using std::cout;
using std::endl;
using std::bind;

void process()
{
    cout<<"The process is running"<<endl;
}
void test()
{
    EventFd ef(bind(process));
    Thread th(bind(&EventFd::start,&ef));
    //ef.start(); // 将其写道另外的线程中
    th.start();

    int cnt = 20;
    while(cnt--)
    {
        cout<<"cnt = "<<cnt<<endl;
        ef.wakeup();
        sleep(1);
    }

    ef.stop();
    th.join();
}
int main()
{
    test();
    return 0;
}

======== Thread.cc ========
#include<iostream>
#include<pthread.h>


#include "Thread.h"

Thread::Thread(ThreadCallback &&cb)
    :_thid(0),
    _isRuning(false),
    _cb(std::move(cb))
    {}

Thread::~Thread()
{
    if(_isRuning)
    {
        pthread_detach(_thid);
    }
}

void Thread::start()
{
    // threadFunc应设置为静态成员函数,因为成员函数的第一个参数为this,第三个参数需要传入一个函数
    // 由于threadFunc设置为静态成员函数导致在其内部没有this,不能调用run函数
    int ret = pthread_create(&_thid,nullptr,threadFunc,this);
    if(ret)
    {
        perror("pthread_create");
        return;
    }
    _isRuning = true;
}

void Thread::join()
{
    if(_isRuning)
    {
        pthread_join(_thid,nullptr);
        _isRuning = false;
    }
}

void * Thread::threadFunc(void *arg)
{
    Thread *pth = static_cast<Thread*>(arg);
    if(pth)
    {
     pth->_cb();// 回调函数的形式
    }
    pthread_exit(nullptr); //return nullptr;
}

======== Thread.h ========
#ifndef __THREAD_H__
#define __THREAD_H__

#include<pthread.h>
#include<functional>

using ThreadCallback = std::function<void()>;

class Thread
{
public:
    Thread(ThreadCallback &&cb);
    ~Thread();
    void start();
    void join();
private:
    // 线程入口函数
    static void *threadFunc(void *arg);
private:
    pthread_t _thid;
    bool _isRuning;
    // 要去实现的任务
    ThreadCallback _cb;
};

#endif

其他

  • read/write和recv/send区别
    在这里插入图片描述
    在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值