介绍
C++ Windows实现EchoServer非阻塞服务端(TPC协议)
Windows IDE:Visual Studio 2022
我们将采用分文件编写方式
支持库
#include <winsock2.h> #include <string>
代码
main.h
#define _WINSOCK_DEPRECATED_NO_WARNINGS #include <winsock2.h> #include <string> #pragma comment(lib,"ws2_32.lib") class EchoServer { private: int port = 0; WORD sockVersion; WSADATA data; int InitCode; SOCKET socketFD = 0; SOCKET clientFD = 0; sockaddr_in sin{}; sockaddr_in clientAddr{}; timeval timeout{}; fd_set wait{}; bool serverIsOpen = false; int bufferSize = 1024; bool isBlock = false; public: EchoServer(); ~EchoServer(); int initServer(int port, bool noBlock = true); void openServre(); std::string getClientIP(); int sendClientDate(std::string date); std::string getClientDate(bool fastRead = false); void CloseServer(); void setTimeout(int s = 3, int us = 0); protected: virtual void handleConnect() = 0; };
这里使用了虚函数handleConnect作为接口
main.cpp
#include "main.h" EchoServer::EchoServer() { sockVersion = MAKEWORD(2, 2); InitCode = WSAStartup(sockVersion, &data); setTimeout(); } EchoServer::~EchoServer() { WSACleanup(); } int EchoServer::initServer(int port, bool noBlock) { if (InitCode != 0) return -3; socketFD = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (socketFD == INVALID_SOCKET) return -2; if (noBlock) { u_long on = 1; if (ioctlsocket(socketFD, FIONBIO, &on) < 0) { return -4; } } isBlock = !noBlock; sin.sin_family = AF_INET; sin.sin_port = htons(port); sin.sin_addr.S_un.S_addr = INADDR_ANY; if (bind(socketFD, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR) return -5; if (listen(socketFD, 5) == SOCKET_ERROR) return -1; return 0; } void EchoServer::openServre() { serverIsOpen = true; DWORD start, end, elapsedTime; while (serverIsOpen) { if (!isBlock) start = GetTickCount64(); int clientAddrSize = sizeof(clientAddr); clientFD = accept(socketFD, (SOCKADDR*)&clientAddr, &clientAddrSize); if (clientFD != INVALID_SOCKET) { handleConnect(); closesocket(clientFD); continue; } if (!isBlock) end = GetTickCount64(); if (!isBlock) elapsedTime = end - start; if (!isBlock) Sleep(elapsedTime); } } std::string EchoServer::getClientIP() { std::string result = ""; result.append(inet_ntoa(clientAddr.sin_addr)); return result; } int EchoServer::sendClientDate(std::string date) { timeval tv = timeout; FD_ZERO(&wait); FD_SET(clientFD, &wait); if (select(clientFD + 1, NULL, &wait, NULL, &tv) > 0) { return send(clientFD, date.c_str(), date.size(), 0); } return -1; } std::string EchoServer::getClientDate(bool fastRead) { std::string result = ""; char* buffer = new char[bufferSize + 1]; int len = 0,ready; buffer[len] = '\0'; timeval tv = timeout; FD_ZERO(&wait); FD_SET(clientFD, &wait); while (true) { if (isBlock) goto getMessage; ready = select(clientFD + 1, &wait, NULL, NULL, &tv); if (ready > 0) { if (FD_ISSET(clientFD, &wait)) { getMessage: len = recv(clientFD, buffer, bufferSize, 0); if (len > 0) { buffer[len] = '\0'; result.append(buffer); if (len < bufferSize && fastRead) { break; } if (isBlock) continue; } else break; } } else break; } delete[] buffer; return result; } void EchoServer::CloseServer() { if (socketFD) closesocket(socketFD); serverIsOpen = false; } void EchoServer::setTimeout(int s, int us) { timeout.tv_sec = s; timeout.tv_usec = us; }
示例
#include <iostream> #include "main.h" class EchoServerRewirte : public EchoServer { void handleConnect() { std::string result = getClientDate(); std::string ip = getClientIP(); std::cout << result << "来自IP:" << ip << "\n"; sendClientDate("close"); CloseServer(); } }; int main() { EchoServerRewirte echoServer; echoServer.initServer(1001); echoServer.openServre(); return 0; }
文章有(1)条网友点评
这个代码有问题,在读取的时候容易出错,就当作参考吧