////// @file Data.h/// @brief 套接字发送接收的封装/// @author guozhiming/// @date 2007-05-21///#ifndef __DATA__#define __DATA__#include "def.h"#include "RecvMessThread.h"#include "SendMessThread.h"class G_RecvMessThread;class G_SendMessThread;class G_Data{ public: /// @brief 构造函数 G_Data(G_RecvMessThread *recvMessThread); G_Data(); /// @brief 析构函数 ~G_Data(); /// @brief 接收数据并存到缓冲池中 /// /// @param nSocket 套接字 /// /// @return 如果收到数据返回成功 , 如果client关闭返回false bool recvData(int nSocket); /// @brief 发送数据 /// /// @param nSocket 套接字 /// @param pData 数据包 /// @param nLen 数据包长度 /// /// @return int sendData(int nSocket , const void *pStr , unsigned int nLen); private: /// @brief 发送数据 /// /// @param nSocket 套接字 /// @param ptr 发送数据 /// @param nLen 数据长度 /// /// @return 发送数据长度 int sendn(int nSocket , const void *pStr , unsigned int nLen); /// @brief 从套接口接受数据 /// /// @param nSocket 套接口 /// @param pStr 存放数据 /// @param nLen 长度 /// /// @return 返回接受数据长度 int recvn(int nSocket , void *pStr , unsigned int nLen); /// @brief 对数据进行打包 /// /// @param pStr 输入数据 /// @param nLen 数据包长度 /// @param pBuffer 输出数据 /// /// @return int packet(const void *pStr , unsigned int nLen , char *pBuffer); /// @brief 对数据进行解包 /// /// @param in 输入数据 /// @param fromLen 从什么地方开始 /// @param nLen 数据长度 /// @param out 输出数据 /// //void unPacket(const char *in , unsigned int fromLen , unsigned int nLen , char *out); void unPacket(const void *in , unsigned int fromLen , unsigned int nLen , void *out); /// @brief 返回数据包大小 /// /// @param pData 数据包 /// /// @return 包的大小 int packetSize(const char *pStr); G_RecvMessThread *g_recvMessThread; /// @brief 数据包大小 static const unsigned int G_MAXDATABUFFSIZE = 65535; //这个够大。。 /// @brief 数据包包头大小 static const unsigned int G_PHLEN = sizeof(unsigned int);};#endif
#include "Data.h"G_Data::G_Data(G_RecvMessThread *recvMessThread) : g_recvMessThread(recvMessThread){}G_Data::G_Data(){}G_Data::~G_Data(){}//封装了发送函数。。。一定要这么做吗?以前看书,书上也这么干,忘了原因。int G_Data::sendn(int nSocket , const void *pStr , unsigned int nLen){ int n = nLen , nRet; char *str = (char*)pStr; while(n > 0) { nRet = send(nSocket , str , n , MSG_NOSIGNAL); if(nRet <= 0) { if(errno == EINTR) { continue; } return -1; } n -= nRet; str += nRet; } return (nLen - n);}//用epoll通知的方式,也需要这样吗?int G_Data::recvn(int nSocket , void *pStr , unsigned int nLen){ int n = nLen; char *str = (char*)pStr; while(n > 0) { int nRet = recv(nSocket , str , n , MSG_NOSIGNAL); if(nRet <= 0) { if(errno == EINTR) { continue; } break; } n -= nRet; str += nRet; } return (nLen - n);}int G_Data::packet(const void *pStr , unsigned int nLen , char *pBuffer){ bcopy(pStr , &pBuffer[G_PHLEN] , nLen); *(unsigned int *)pBuffer = nLen; return (nLen + G_PHLEN);}int G_Data::packetSize(const char *pStr){ return (*(unsigned int*)pStr);}void G_Data::unPacket(const void *in , unsigned int fromLen , unsigned int nLen , void *out){ bcopy(&((char*)in)[G_PHLEN+fromLen] , out , nLen);}int G_Data::sendData(int nSocket , const void *pStr , unsigned int nLen){ char pBuffer[G_MAXDATABUFFSIZE]; bzero(pBuffer , sizeof(pBuffer)); if(!pStr) { return -1; } int nSize = packet(pStr , nLen , pBuffer); int nRet = sendn(nSocket , pBuffer , nSize); return nRet;}bool G_Data::recvData(int nSocket){ char pBuffer[G_MAXDATABUFFSIZE]; char pStr[G_MAXDATABUFFSIZE]; bzero(pBuffer , sizeof(pBuffer)); bzero(pStr , sizeof(pStr)); int fromLen = 0 , n; int nSize = recvn(nSocket , pBuffer , sizeof(pBuffer)); ///返回接收数据大小 if(nSize <= 0) { return false; } while(1) { n = packetSize(&pBuffer[fromLen]); /// 返回数据真正大小 unPacket(pBuffer , fromLen , n , pStr); ///把真正数据存放到pStr中 g_recvMessThread->pushData((std::string)pStr); ///放到数据池队列中 //收到的数据放入队列中,这是ok的。recv要开那么多线程吗?recv是阻塞的? n += sizeof(unsigned int); fromLen += n; if(fromLen == nSize) { break; ///如果数据都取完了退出循环 } } return true;}
////// @file SendMessThread.h/// @brief 发送消息线程 server->client/// @author guozhiming/// @date 2007-05-18///#ifndef __G_SENDMESSTHREAD__#define __G_SENDMESSTHREAD__#include "def.h"#include "Thread.h"#include "ThreadPool.h"#include "Queue.h"#include "Data.h"class G_Data;class G_SendMessThread : public G_Thread{ public: /// @brief 构造函数 G_SendMessThread(); /// @brief 析构函数 ~G_SendMessThread(); void Run(); void addEpoll(int nSocket); //这里也开了epoll,接受和发送都开。但是recv开了那么多线程,每个都开epoll void modEpoll(int nSocket); //void delEpoll(int nSocket); int sendMessage(int nSocket , const void *pStr); private: /// @brief epoll_create 返回文件描述符 int epfd; struct epoll_event event[100] , ev; /// @brief 存放套接字和数据multimap multimap g_sockDataMap;//用标准c++类。只有那个queue封装了mutex,有必要吗? /// @brief multimap插入值 typedef pair g_mapPair; /// @brief 数据发送对象 G_Data *g_data;};#endif
#include "Log.h"#include "SendMessThread.h"G_SendMessThread::G_SendMessThread(){ bzero(&ev , sizeof(struct epoll_event)); epfd = epoll_create(256); g_data = new G_Data();}G_SendMessThread::~G_SendMessThread(){ close(epfd); if(g_data) { delete g_data; g_data = NULL; }}void G_SendMessThread::addEpoll(int nSocket){ ev.data.fd = nSocket; ev.events = EPOLLOUT | EPOLLERR;//这里加err。。。。 epoll_ctl(epfd , EPOLL_CTL_ADD , nSocket , &ev);}void G_SendMessThread::modEpoll(int nSocket){ ev.data.fd = nSocket; ev.events = EPOLLOUT | EPOLLERR; epoll_ctl(epfd , EPOLL_CTL_MOD , nSocket , &ev);}/*void G_SendMessThread::delEpoll(int nSocket){ ev.data.fd = nSocket; epoll_ctl(epfd , EPOLL_CTL_DEL , nSocket , &ev);}*/int G_SendMessThread::sendMessage(int nSocket , const void *pStr){ char *str = (char*)pStr; g_sockDataMap.insert(g_mapPair(nSocket , (std::string)str)); ///把套接口和数据插入map中}void G_SendMessThread::Run(){ multimap ::iterator map_interator; int nfds , i , sock; std::string buffer; while(1) { nfds = epoll_wait(epfd , event , 100 , 500); for(i=0; i sendData(sock , (void*)map_interator->second.c_str() , strlen(map_interator->second.c_str())); g_sockDataMap.erase(map_interator); } usleep(100); } } }}
////// @file Server.h/// @brief 服务器框架基类/// @author guozhiming/// @date 2007-05-24///#ifndef __SERVER__#define __SERVER__#include "def.h"class G_Server{ public: /// @brief 析构函数 virtual ~G_Server(); /// @brief 初始化服务器程序字类需要继承这个函数 /// /// @return virtual bool init(); /// @brief 结束服务器程序回收资源 // virtual void final() = 0; protected: /// @brief 构造函数 G_Server(); private: static G_Server *instance ;};#endif
#include "Server.h"#include "Log.h"G_Server *G_Server::instance = NULL;static void ctrlcHandle(int signum){ debug_output("ctrl-c signal .....\n");}G_Server::G_Server(){ instance = this;}G_Server::~G_Server(){}bool G_Server::init(){ debug_output("%s\n" , __PRETTY_FUNCTION__); ///定义ctrl-c信号 struct sigaction act; act.sa_handler = ctrlcHandle; sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGINT , &act , NULL);//屏蔽这个信号。。就做了这么一件事。。这么坑。}