当前位置:首页 > 编程笔记 > 正文
已解决

使用libevent实现回显服务器

来自网友在路上 155855提问 提问时间:2023-11-02 21:08:31阅读次数: 55

最佳答案 问答题库558位专家为你答疑解惑

说明

使用libevent实现了一个回显一行字符串的服务器:客户端发送一行字符串,以’\n’结尾,服务器接受完一行后就原封不动地发回给客户端。以下实现未使用bufferevent,使用libevent的bufferevent,代码会更简单。

libevent教程可参看http://www.wangafu.net/~nickm/libevent-book/01_intro.html

代码

#include <iostream>
#include "event2/event.h"
#include "event2/thread.h"
#include <set>
#include <process.h>#pragma comment(lib, "event.lib")
#pragma comment(lib, "Ws2_32.lib")struct ClientSocketItem
{ClientSocketItem(){hSocket = NULL;memset(szRecv, 0, sizeof(szRecv));nRecvSize = 0;bNeedWrite = false;nWriteOffset = 0;pReadEvent = nullptr;pWriteEvent = nullptr;}SOCKET hSocket;struct event* pReadEvent;struct event* pWriteEvent;char szRecv[1024];unsigned int nRecvSize;std::string strIp;bool bNeedWrite;//接受完成,可以发送unsigned int nWriteOffset = 0;
};std::set<ClientSocketItem*> g_Clients;void onTimeOut(evutil_socket_t fd, short events, void * pParams )
{std::cout << "time is out" << std::endl;
}bool InitSocket()
{WORD wVersionRequested = MAKEWORD(2, 2);WSADATA wsaData = { 0 };int err = WSAStartup(wVersionRequested, &wsaData);if (err != 0){return false;}if (LOBYTE(wsaData.wVersion) != 2 ||HIBYTE(wsaData.wVersion) != 2){WSACleanup();return false;}return true;
}void CloseClientItem(ClientSocketItem* pItem)
{if (!pItem){return;}evutil_closesocket(pItem->hSocket);event_del(pItem->pReadEvent);event_del(pItem->pWriteEvent);event_free(pItem->pReadEvent);event_free(pItem->pWriteEvent);delete pItem;g_Clients.erase(pItem);
}void onClientRead(evutil_socket_t fd, short events, void* pParam)
{ClientSocketItem* pClient = (ClientSocketItem*)pParam;if (!pClient){return;}//std::cout << "read callback" << std::endl;char c = 0; //测试用,每次只读一个字符int nRecvValue = recv(pClient->hSocket, &c, 1, 0);if (nRecvValue > 0){pClient->szRecv[pClient->nRecvSize] = c;pClient->nRecvSize += 1;std::cout << "read one char: " << c << std::endl;if (c == '\n'){std::cout << "read finished" << std::endl;pClient->bNeedWrite = true;}return;}else if (0 == nRecvValue){std::cout << "peer client closed" << std::endl;CloseClientItem(pClient);return ;}else{int nError = WSAGetLastError();if (WSAEWOULDBLOCK != nError){std::cerr << "recv failed with error " << nError << std::endl;CloseClientItem(pClient);return ;}std::cout << "next recv" << std::endl;return;}
}void onClientWrite(evutil_socket_t fd, short events, void* pParam)
{ClientSocketItem* pClient = (ClientSocketItem*)pParam;if (!pClient){return;}//std::cout << "write callback" << std::endl;if (!pClient->bNeedWrite){return;}//测试用,每次只发送一个字符int nRet = send(pClient->hSocket, pClient->szRecv + pClient->nWriteOffset, 1, 0);if (nRet >= 0){std::cout << "send one char: " << pClient->szRecv[pClient->nWriteOffset] << std::endl;pClient->nWriteOffset += 1;if (pClient->nWriteOffset == pClient->nRecvSize){std::cout << "send finished, close client(" << pClient->strIp.c_str()<< ")" << std::endl;pClient->bNeedWrite = false;CloseClientItem(pClient);return;}return;}else{int nError = WSAGetLastError();if (WSAEWOULDBLOCK != nError){std::cerr << "send failed with error " << nError << std::endl;CloseClientItem(pClient);return;}std::cout << "next send" << std::endl;return;}
}void onEventListen(evutil_socket_t fd, short events, void * pParam)
{event_base* pEventBase = (event_base*)(pParam);sockaddr_in mPeerAddr = { 0 };int nAddrLen = sizeof(sockaddr);evutil_socket_t hClientSocket = accept(fd, (sockaddr*)(&mPeerAddr), &nAddrLen);if (INVALID_SOCKET == hClientSocket){std::cout << "accept failed with error "<< WSAGetLastError() << std::endl;return;}ClientSocketItem* pClient = new ClientSocketItem();pClient->hSocket = hClientSocket;g_Clients.insert(pClient);std::cout << "accept success" << std::endl;pClient->pReadEvent = event_new(pEventBase, hClientSocket,EV_READ | EV_PERSIST, onClientRead, pClient);pClient->pWriteEvent = event_new(pEventBase, hClientSocket,EV_WRITE | EV_PERSIST, onClientWrite, pClient);event_add(pClient->pReadEvent, nullptr);event_add(pClient->pWriteEvent, nullptr);}unsigned __stdcall WorkThreadFun(void* pParam)
{event_base* pEventBase = (event_base*)pParam;int nRet = event_base_dispatch(pEventBase);std::cout << "event loop quit with " << nRet << std::endl;return 0;
}int main(int argc, char** argv)
{if (!InitSocket()){return -1;}evutil_socket_t hListenSocket = socket(AF_INET, SOCK_STREAM, 0);if (INVALID_SOCKET == hListenSocket){std::cerr << "create socket failed with error " << WSAGetLastError()<< std::endl;return -1;}evutil_make_socket_nonblocking(hListenSocket);sockaddr_in mSockAddrIn = { 0 };mSockAddrIn.sin_family = AF_INET;mSockAddrIn.sin_port = htons((u_short)8878);//mSockAddrIn.sin_addr.S_un.S_addr = inet_addr("0.0.0.0");InetPton(AF_INET, TEXT("0.0.0.0"), &(mSockAddrIn.sin_addr));if (SOCKET_ERROR == bind(hListenSocket, (sockaddr*)(&mSockAddrIn),sizeof(sockaddr))){std::cerr << "bind failed with error " << WSAGetLastError() << std::endl;return -1;}if (SOCKET_ERROR == listen(hListenSocket, SOMAXCONN)){std::cerr << "listen failed with error " << WSAGetLastError() << std::endl;return -1;}evthread_use_windows_threads();event_base* pEventBase = event_base_new();if (!pEventBase){return -1;}//struct event* pTimeOutEvent = event_new(pEventBase, -1, EV_PERSIST, onTimeOut, nullptr);//timeval tv{ 3, 0 };//event_add(pTimeOutEvent, &tv);struct event* pListenEvent = event_new(pEventBase, hListenSocket,EV_READ | EV_PERSIST, onEventListen, pEventBase);event_add(pListenEvent, nullptr);_beginthreadex(nullptr, 0, WorkThreadFun, pEventBase, 0, nullptr);
//
//
//	int nRet = event_base_dispatch(pEventBase);
//
//	std::cout << "event loop quit with " << nRet << std::endl;while (true){Sleep(3000);}return 0;
}
查看全文

99%的人还看了

猜你感兴趣

版权申明

本文"使用libevent实现回显服务器":http://eshow365.cn/6-30530-0.html 内容来自互联网,请自行判断内容的正确性。如有侵权请联系我们,立即删除!