使用libevent和boost编写一个简单的tcp服务器
2017-03-28 00:00
239 查看
摘要: 使用libevent和boost编写一个简单的tcp服务器
写这个东西主要是为了学习libevent的基本用法,以及学习下boost的线程库。 程序结构比较简单: 1. 首先是建立一个监听socke。 2. 将这个监听的socket绑定到一个event事件上,然后等待有客户过来连接。 3. 如果响应到监听socket可读,则accept尝试连接的客户端。 4. 开启一个线程来处理所有和这个连接过来的客户端之间的交互。(实际上什么事情也没做,就是cout了下每次recv的数据大小) 代码如下: 1. 首先是程序入口,main函数 main函数主要是注册了一个监听使用的socket。另外一旦进入了监听状态,就不好退出程序,所以一开始就注册了一个信号响应函数, 专门用来响应程序退出的信号。 //创建监听socket,然后等待这个socket有客户来链接 //每个链接一个线程去处理 int main(int argc, char* argv[]) { //首先处理好kill -2信号 struct sigaction sigact = {0}; sigact.sa_sigaction = On_Exit; if ( -1 == sigaction(2, &sigact, NULL)) { log("建立响应函数失败"); return 0; } //建立一个非阻塞的socket句柄 int sockfd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); if (-1 == sockfd) { log("创建监听socket失败", ERROR); return 0; } log("创建监听socket成功"); //bind sockaddr_in sinAddr; sinAddr.sin_family = AF_INET; sinAddr.sin_port = htons(LISTEN_PORT); sinAddr.sin_addr.s_addr = inet_addr("172.21.169.160"); if( -1 == bind(sockfd, (sockaddr*)&sinAddr, sizeof(sockaddr_in))) { log("监听本地端口失败", ERROR); return 0; } //进入listen if (-1 == listen(sockfd, SOMAXCONN)) { log("监听本地端口失败", ERROR); return 0; } log("监听本地端口成功"); //进入accept状态 log("即将进入监听状态"); EnterAcceptWhile(sockfd); close(sockfd); log("监听线程成功结束了"); return 0; } 2. 进入libevent的消息循环 //基于event的消息响应机制 void EnterAcceptWhile(int nFd) { if (g_pEventLoop == NULL) g_pEventLoop = event_base_new(); //绑定事件 struct event* pListenEvent = event_new(g_pEventLoop, nFd, EV_PERSIST|EV_READ, On_Sock_Accept, NULL); if (pListenEvent == NULL) { log ("建立监听事件失败"); return; } //加入监听事件,持续 event_add(pListenEvent, NULL); //分派消息 int nLoopRst = 0; if (0 == (nLoopRst = event_base_dispatch(g_pEventLoop))) { log("事件循环正常停止了"); } else if (1 == nLoopRst) { log("没有事件关联到这个消息循环了"); } else { log("消息循环出现了错误", ERROR); } event_free(pListenEvent); event_base_free(g_pEventLoop); g_pEventLoop = NULL; } 3. 一旦响应到有客户端过来连接,就会进入On_Sock_Accept函数。因此这个函数应该尽可能的短小。 //响应客户端连接 void On_Sock_Accept(int nFd, short sFlags, void* pArg) { if (!(sFlags&EV_READ)) { log("接受到了一个莫名其妙的消息", WARNING); return; } log("响应到一个客户端过来连接了"); socklen_t sockLen; sockaddr sa; int nAcceptFd = accept(nFd, &sa, &sockLen); //这里应该启动一个线程来处理这个请求事务的,而不应该在这里做大量的复杂操作 SocketThread st(nAcceptFd); boost::thread thread_ST(st); } 4. 在上个函数中,开了一个线程专门处理来自这个客户端的请求。 类SocketThread的代码如下: SocketThread::SocketThread(int nFd) { m_nFd = nFd; } void SocketThread::operator() () { if (m_nFd == -1) return; //读取数据,等到读取完成之后,输出出来,最后关闭掉socket连接 char* pszTemp = new char[1024]; memset(pszTemp, 0, 1024); int nRecvSize = 0; while( 0 < (nRecvSize = recv(m_nFd, pszTemp, 1024, 0))) { //读到数据了 std::cout << "thread id: " << boost::this_thread::get_id() << " 接受到了:" << nRecvSize << "字节的数据" << std::endl; } delete[] pszTemp; pszTemp = NULL; if (nRecvSize == 0) { std::cout << "客户端已经关闭了" << std::endl; } else if (nRecvSize < 0) { std::cout << "接受客户端数据失败,请检查原因" << std::endl; } close(m_nFd); m_nFd = -1; } 5. 最后是响应信号2, 退出libevent的消息循环 其实这里存在问题:如果退出消息循环的时候还有很多的工作者线程正在运行,应该要先让他们把事情做完再退出的。 //响应退出消息 void On_Exit(int nSigId, siginfo_t* pSigInfo, void* pArg) { log("准备结束监听了", WARNING); if (g_pEventLoop != NULL) { //打破监听循环 event_base_loopbreak(g_pEventLoop); } }
相关文章推荐
- 使用libevent和boost编写一个简单的tcp服务器
- 使用libevent和boost编写一个简单的tcp服务器
- 使用ATL编写一个简单的COM服务器
- 使用ATL编写一个简单的COM服务器
- Java编写一个简单的TCP通信程序。服务器发送一条字符串,客户端接收该信息并显示。
- Node.js 写一个简单的服务器和TCP服务器,以及sumblimeText3简单使用
- 如何使用TCP/IP与服务器进行通信-一个简单的聊天程序
- 使用ATL编写一个简单的COM服务器
- 【实验 1-1】编写一个简单的 TCP 服务器和 TCP 客户端程序。程序均为控制台程序窗口。
- 使用libevent写的一个简单服务器的代码
- 使用ATL编写一个简单的COM服务器
- 【ROS总结】教程Actionlib——使用Execute Callback编写一个简单的行为服务器
- 如何使用TCP/IP与服务器进行通信-一个简单的聊天程序
- 利用boost::asio实现一个简单的服务器框架
- Windows 上静态编译 Libevent 2.0.10 并实现一个简单 HTTP 服务器
- Windows 上静态编译 Libevent 2.0.10 并实现一个简单 HTTP 服务器
- 使用C++与SFML编写一个简单的撞球游戏Part1——新建工程以及设置
- 使用OTP原理构建一个非阻塞的TCP服务器
- Windows 上静态编译 Libevent 2.0.10 并实现一个简单 HTTP 服务器
- boost::asio一个简单的echo服务器