模型图如下(event loop + thread pool)(event用epoll,线程同步用队列)
说明:一个中转线程负责连接外部服务器维持tcp连接,接收外部来的请求,转发请求给服务线程处理,服务线程处理完后通知中转线程回复,主要业务代码如下:
1,ProxyThread.cpp
#include "ProxyThread.h" #include "Singletone.h" #include "SwitchSvr.h" TC_Epoller *ProxyThread::_epoller; map<int, ProxyConnect *> *ProxyThread::_mapSocket; struct WupProtocol { static int checkRequest(const char *buf, size_t len) { if(len < 4){ return 0; } Tint ti; strncpy(ti.byte, buf, 4); int bodyLen = ti.integer; if(bodyLen <= (int)len - 4){ return bodyLen; } return 0; } static int parseProxy(string &in, string &out) { try { int bodylen = checkRequest(in.c_str(), in.length()); if(bodylen > 0) { out = in.substr(0, bodylen+4); in = in.substr(bodylen+4); return TC_EpollServer::PACKET_FULL; } else { return TC_EpollServer::PACKET_LESS; } } catch(exception &ex) { return TC_EpollServer::PACKET_ERR; } return TC_EpollServer::PACKET_LESS; } }; void ProxyThread::Init(const string &sConf) { LOG_DEBUG << "ProxyThread::Init succ" << endl; } void ProxyThread::Reload() { LOG_DEBUG << "ProxyThread::Reload succ" << endl; } void ProxyThread::CreateThread() { pthread_t thread; if( !m_bStart ) { m_bStart = true; if(pthread_create(&thread, NULL, Run, (void*)this) != 0) { throw runtime_error("Create ProxyThread fail"); } } } int ProxyThread::registerProxy(ProxyConnect *connect) { LOG_DEBUG << "registerProxy start ip:" << connect->ip << " port:" << connect->port << endl; char msg[1024] = "connect"; Tint ti; ti.integer = strlen(msg); SendData sendData; sendData.fd = connect->socket.getfd(); sendData.buffer.assign(ti.byte, 4); sendData.buffer += msg; int iRet = SendBuffer(sendData.fd, sendData); if(iRet < 0){ CloseFD(sendData.fd); return -1; } return 0; } int ProxyThread::checkSocket(ProxyConnect *connect) { if(!connect->socket.isValid()){ try{ int oldfd = connect->socket.getfd(); connect->socket.createSocket(SOCK_STREAM, AF_INET); connect->socket.setblock(false); connect->socket.setKeepAlive(); connect->first = true; connect->_recvbuffer.clear(); connect->_sendbuffer.clear(); try{ connect->socket.connect(connect->ip, connect->port); } catch(TC_SocketConnect_Exception &ex) { //connect->socket.close(); if(errno != EINPROGRESS) { connect->socket.close(); LOG_ERROR << "Connect Proxy " << connect->ip << ":" << connect->port << " Exception:" << errno << endl; return -1; } } if(errno != EINPROGRESS) { connect->socket.close(); return -1; } if(oldfd != connect->socket.getfd()){ _mapSocket->erase(oldfd); } _mapSocket->insert(pair<int, ProxyConnect *>(connect->socket.getfd(), connect)); LOG_DEBUG << "proxy connected fd:" << connect->socket.getfd() << " errno:" << errno << endl; _epoller->add(connect->socket.getfd(), connect->socket.getfd(), EPOLLIN); registerProxy(connect); } catch(TC_Socket_Exception &ex) { LOG_ERROR << "Connect Proxy Socket Error:" << string(ex.what()) << endl; connect->socket.close(); return -1; } catch(...) { LOG_ERROR << "Connect Proxy Unknown Error:" << errno << endl; return -1; } } return 0; } void ProxyThread::ConnectProxy() { LOG_DEBUG << "ProxyThread::ConnectProxy Begin" << endl; _epoller = new TC_Epoller(false); _epoller->create(100); TC_Config conf; conf.parseFile(ServerConfig::BasePath + ServerConfig::ServerName + ".conf"); vector<string> proxys = conf.getDomainVector("/Config/Proxys"); for(unsigned int i = 0;i < proxys.size();i ++){ ProxyConnect *connect = new ProxyConnect(); connect->ip = conf.get("/Config/Proxys/" + proxys[i] + "<ip>", "127.0.0.1"); connect->port = atoi(conf.get("/Config/Proxys/" + proxys[i] + "<port>", "9999").c_str()); checkSocket(connect); } LOG_DEBUG << "ProxyThread::ConnectProxy End" << endl; } int ProxyThread::ParseProtocol(string &_recv, int fd, bool &first){ try { while(true){ string ro; LOG_DEBUG << "ProxyThread:ParseProtocol:" << recv << endl; int b = WupProtocol::parseProxy(_recv, ro); if(b == TC_EpollServer::PACKET_LESS) { break; } else if(b == TC_EpollServer::PACKET_FULL) { if(first){ LOG_DEBUG << "First Package: " << ro << endl; first = false; } else { if(Singletone::getInstance()->from_queue.size()<10000){ // overloaded RecvData *o = new RecvData(); o->fd = fd; o->buffer = ro; Singletone::getInstance()->from_queue.push_back(o); LOG_DEBUG << "Push Message Package: " << ro << endl; }else{ LOG_ERROR << "Recv Queue OverLoaded . Drop Message !" <<endl; } } } if(_recv.empty()){ break; } } } catch(exception &ex) { LOG_ERROR << "recv protocol error: " << string(ex.what()) << endl; return -1; } catch(...) { LOG_ERROR << "recv protocol error: " << endl; return -1; } return 1; } int ProxyThread::RecvBuffer(int fd){ map<int ,ProxyConnect *>::iterator it = _mapSocket->find(fd); if(it != _mapSocket->end()){ ProxyConnect *connect = it->second; char buffer[8192] = "