常见并发服务器方案
-
- 循环式/迭代式( iterative )服务器
无法充分利用多核CPU,不适合执行时间较长的服务

-
- 并发式(concurrent)服务器
适合执行时间比较长的服务

- 并发式(concurrent)服务器
-
- prefork or pre threaded(UNP2e 第27章)

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

-
- reactor + thread per request(过渡方案)
-
- reactor + worker thread(过渡方案)
-
- reactor + thread pool(能适应密集计算)

- reactor + thread pool(能适应密集计算)
-
- multiple reactors(能适应更大的突发I/O)
reactors in threads(one loop per thread)
reactors in processes

- multiple reactors(能适应更大的突发I/O)
-
- multiple reactors + thread pool
(one loop per thread + threadpool)(突发I/O与密集计算)

- multiple reactors + thread pool
-
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区别






753

被折叠的 条评论
为什么被折叠?



