对使用AcceptEx建立的连接调用shutdown函数关闭返回失败

IOCP中shutdown问题及解决
本文记录了一个在实现服务器网络库过程中遇到的关于IOCP的问题:shutdown调用失败。通过设置SO_UPDATE_ACCEPT_CONTEXT选项解决了该问题。文章详细介绍了如何为新建立的连接套接字设置此选项。
是我在去年写服务器网络库遇到的一个问题,当时令我非常意外,那时一直以为是程序代码编写的问题。后来查阅了大量英文邮件列表,才发现是IOCP本身的一个问题。为避免读者陷于同样的问题,这里把它列出来,并给出解决方法。

 

       对每个使用AcceptEx接受的连接套结字使用setsockopt设置SO_UPDATE_ACCEPT_CONTEXT选项,这个选项原义是把listen套结字一些属性(包括socket内部接受/发送缓存大小等等)拷贝到新建立的套结字,却可以使后续的shutdown调用成功。

 

/* SO_UPDATE_ACCEPT_CONTEXT is required for shutdown() to work fine*/

       setsockopt( sockClient,

                            SOL_SOCKET,

                            SO_UPDATE_ACCEPT_CONTEXT,

                            (char*)&m_sockListen,

                            sizeof(m_sockListen) ) ;

#pragma once #include <windows.h> #include <winsock2.h> #include <ws2tcpip.h> #include <mswsock.h> #include <vector> #include <memory> #include <functional> #include <string> #include <iostream> #include <mutex> #include <unordered_map> #include <atomic> #include <thread> #include <queue> #pragma comment(lib, "ws2_32.lib") #pragma comment(lib, "mswsock.lib") namespace IOCP2 { //定义常量 constexpr int BUFFER_SIZE = 4096; //定义IO操作类型 enum IO_OPERATION{ ACCEPT, READ, WRITE }; //节点类型 enum NODE_TYPE { NODE, SERVER, CLIENT }; /** * I/O上下文数据============================================================================= */ class IOContext { public: //该I/O操作唯一标识符,相同的I/O操作,参数的地址相同,通过 GetQueuedCompletionStatus返回的 LPOVERLAPPED可反向获取 IOContext: OVERLAPPED m_overlapped; //描述数据缓冲区的信息,用于 WSARecv和 WSASend。 WSABUF m_dataBuf; //I/O操作类型 IO_OPERATION m_operation; //缓冲区数据 char m_buffer[BUFFER_SIZE]; SOCKET m_socket; public: IOContext() { ZeroMemory(&this->m_overlapped,sizeof(OVERLAPPED)); this->m_dataBuf.len = BUFFER_SIZE; this->m_dataBuf.buf = this->m_buffer; this->m_operation = IO_OPERATION::READ; this->m_socket = INVALID_SOCKET; } ~IOContext(){} /** * * @param other * @return */ bool operator == (const IOContext& other) { return &this->m_overlapped == &other.m_overlapped; } /** * * @param other * @return */ bool operator != (const IOContext& other) { return &this->m_overlapped != &other.m_overlapped; } }; /** * 套接字控制工具,用于调用Windows扩展功能======================================================= */ class WSAIoctlTool { private: //服务器接收链接函数地址 static GUID guidAcceptEx; //获取接受到的链接地址的函数的地址 static GUID guidGetAcceptExSockaddrs; private: /** * * @tparam FUNC_POINTERE * @param targetSocket * @param funcGuID * @param funcPointer * @return */ template<typename FUNC_POINTERE> static bool WSAIoctlFun(SOCKET& targetSocket,GUID& funcGuID, FUNC_POINTERE& funcPointer) { DWORD bytesReceived; return WSAIoctl( targetSocket, SIO_GET_EXTENSION_FUNCTION_POINTER, &funcGuID, sizeof(funcGuID), &funcPointer, sizeof(funcPointer), &bytesReceived, nullptr, nullptr) != SOCKET_ERROR; } public: /** *异步接收套接字连接 * @param sListenSocket 监听 socket(bind+ listen后的 socket) * @param sAcceptSocket 预先创建的 socket,用于接受新连接 * @param lpOutputBuffer 接收数据的缓冲区,同时包含本地和远程地址信息 * @param lpdwBytesReceived 返回实际接收的字节数(仅在同步操作时有效) * @param lpOverlapped 用于异步操作的 OVERLAPPED结构 * @return */ static bool acceptExFun(SOCKET sListenSocket,SOCKET sAcceptSocket,PVOID lpOutputBuffer, LPDWORD lpdwBytesReceived,LPOVERLAPPED lpOverlapped) { LPFN_ACCEPTEX lpAcceptEx = nullptr; if (!WSAIoctlTool::WSAIoctlFun(sListenSocket,WSAIoctlTool::guidAcceptEx,lpAcceptEx)) return false; return lpAcceptEx(sListenSocket,sAcceptSocket,lpOutputBuffer,0,sizeof(sockaddr_in)+16,sizeof(sockaddr_in)+16,lpdwBytesReceived,lpOverlapped) != FALSE; } /** *获取连接的地址 * @param sAcceptSocket //AcceptEx的套接字 * @param lpOutputBuffer //AcceptEx 返回的缓冲区 * @return ip:port */ static std::string GetAcceptExSockaddrsFun(SOCKET sAcceptSocket, PVOID lpOutputBuffer) { LPFN_GETACCEPTEXSOCKADDRS lpGetAcceptExSockaddrs = nullptr; //获取客户端地址信息 sockaddr_in* localAddr = nullptr; sockaddr_in* remoteAddr = nullptr; int localAddrLen = 0; int remoteAddrLen = 0; constexpr const int addressBufferSize = sizeof(sockaddr_in) + 16; if (!WSAIoctlTool::WSAIoctlFun(sAcceptSocket,WSAIoctlTool::guidGetAcceptExSockaddrs,lpGetAcceptExSockaddrs)) return NULL; //使用使用GetAcceptExSockaddrs获取地址信息 lpGetAcceptExSockaddrs(lpOutputBuffer,0,addressBufferSize, addressBufferSize, (sockaddr**)&localAddr, &localAddrLen, (sockaddr**)&remoteAddr, &remoteAddrLen); char clientIP[INET_ADDRSTRLEN]; inet_ntop(AF_INET,&(remoteAddr->sin_addr),clientIP,INET_ADDRSTRLEN); unsigned short clientPort = ntohs(remoteAddr->sin_port); return std::string(clientIP,INET_ADDRSTRLEN)+":"+std::to_string(clientPort); } }; class RemoteNodesData; /** * 节点Socket上下文数据======================================================================= */ class NodeSocketContextData { private: SOCKET m_socket; std::string m_IPPortStr; std::shared_ptr<IOContext> m_readContext; //void指针存储overlapped地址,overlapped地址一样说明是同一个I/O操作 std::unordered_map<void*,std::shared_ptr<IOContext>> m_writeContexts; private: /** * * @param context */ void deleteReadContext(std::shared_ptr<IOContext>& context) { //不是同一个cosntext if (&this->m_readContext.get()->m_overlapped != &context->m_overlapped) return; this->m_readContext.reset(); } /** * * @param context */ void setWriteContext(std::shared_ptr<IOContext>& context) { this->m_writeContexts[&context->m_overlapped] = context; } /** * * @param context */ void setReadContext(std::shared_ptr<IOContext>& context) { this->m_readContext = context; } /** * * @param context */ void deleteWriteContext(std::shared_ptr<IOContext>& context) { this->m_writeContexts.erase(&context->m_overlapped); } public: NodeSocketContextData() { this->m_socket = INVALID_SOCKET; this->m_IPPortStr = ""; this->m_readContext = nullptr; } /** * * @param ipPortStr * @param socket */ NodeSocketContextData(const std::string& ipPortStr,SOCKET& socket) { this->m_socket = socket; this->m_IPPortStr = ipPortStr; } ~NodeSocketContextData() { this->m_writeContexts.clear(); } /** * * @return */ std::string& getIPPortStr() { return this->m_IPPortStr; } /** * * @return */ SOCKET& getSocket() { return this->m_socket; } /** * * @param socket */ void setSocket(SOCKET& socket) { this->m_socket = socket; } public: friend class RemoteNodesData; }; /** * 远程节点数据=============================================================================== */ class RemoteNodesData { private: std::unordered_map<std::string, std::shared_ptr<NodeSocketContextData>> m_remoteNodes; std::unordered_map<SOCKET,std::string> m_remoteNodesSocketIPPortStrMap; std::mutex m_remoteNodesMx; public: RemoteNodesData() {} ~RemoteNodesData() {} /** * 是否存在节点 * @param socket * @return */ bool hashNode(SOCKET& socket) { auto it = this->m_remoteNodesSocketIPPortStrMap.find(socket); return it != this->m_remoteNodesSocketIPPortStrMap.end(); } /** * 是否存在该节点 * @param IPPortStr * @return */ bool hashNode(const std::string& IPPortStr) { auto it = this->m_remoteNodes.find(IPPortStr); return it != this->m_remoteNodes.end(); } /** * * @param IPPortStr * @return */ SOCKET getNodeSocketByIPPortStr(std::string& IPPortStr) { auto it = this->m_remoteNodes.find(IPPortStr); if (it == this->m_remoteNodes.end()) return INVALID_SOCKET; return it->second->getSocket(); } /** * * @param remoteNode */ void addRemoteNode(std::shared_ptr<NodeSocketContextData>& remoteNode) { std::lock_guard<std::mutex> lock(this->m_remoteNodesMx); if (remoteNode.get() == nullptr || remoteNode.get()->getIPPortStr() == "" || remoteNode.get()->getSocket() == INVALID_SOCKET) return; this->m_remoteNodesSocketIPPortStrMap[remoteNode.get()->getSocket()] = remoteNode.get()->getIPPortStr(); this->m_remoteNodes[remoteNode.get()->getIPPortStr()] = remoteNode; } /** * 调用函数会清除Socket * @param ipPortStr */ void deleteRemeoteNodesByIPPortStr(const std::string& ipPortStr) { std::lock_guard<std::mutex> lock(this->m_remoteNodesMx); if (ipPortStr == "" || ipPortStr.empty()) return; auto it = this->m_remoteNodes.find(ipPortStr); //不存在该节点数据 if (it == this->m_remoteNodes.end()) return; SOCKET socket = it->second.get()->getSocket(); this->m_remoteNodesSocketIPPortStrMap.erase(socket); this->m_remoteNodes.erase(it); //清除Socket closesocket(socket); } /** * 调用函数会清除Socket * @param socket */ void deleteRemeoteNodesBySocket(SOCKET& socket) { std::lock_guard<std::mutex> lock(this->m_remoteNodesMx); if (socket == INVALID_SOCKET) return; auto it = this->m_remoteNodesSocketIPPortStrMap.find(socket); //不存在该节点数据 if (it == this->m_remoteNodesSocketIPPortStrMap.end()) return; this->m_remoteNodes.erase(it->second); this->m_remoteNodesSocketIPPortStrMap.erase(it); //清除Socket closesocket(socket); } /** * * @param context */ void addRemeoteNodeReadContext(std::shared_ptr<IOContext> & context) { std::lock_guard<std::mutex> lock(this->m_remoteNodesMx); if (context.get()->m_socket == INVALID_SOCKET) return; auto it = this->m_remoteNodesSocketIPPortStrMap.find(context->m_socket); //该socket对应的节点数据不存在 if (it == this->m_remoteNodesSocketIPPortStrMap.end()) return; this->m_remoteNodes[it->second]->setReadContext(context); } /** * * @param context */ void deleteRemeoteNodeReadContext(std::shared_ptr<IOContext> & context) { std::lock_guard<std::mutex> lock(this->m_remoteNodesMx); if (context.get()->m_socket == INVALID_SOCKET) return; auto it = this->m_remoteNodesSocketIPPortStrMap.find(context->m_socket); //该socket对应的节点数据不存在 if (it == this->m_remoteNodesSocketIPPortStrMap.end()) return; this->m_remoteNodes[it->second]->deleteReadContext(context); } /** * * @param context */ void addRemeoteNodeWriteContext(std::shared_ptr<IOContext> & context) { std::lock_guard<std::mutex> lock(this->m_remoteNodesMx); if (context.get()->m_socket == INVALID_SOCKET) return; auto it = this->m_remoteNodesSocketIPPortStrMap.find(context->m_socket); //该socket对应的节点数据不存在 if (it == this->m_remoteNodesSocketIPPortStrMap.end()) return; this->m_remoteNodes[it->second]->setWriteContext(context); } /** * * @param context */ void deleteRemeoteNodeWriteContext(std::shared_ptr<IOContext> & context) { std::lock_guard<std::mutex> lock(this->m_remoteNodesMx); if (context.get()->m_socket == INVALID_SOCKET) return; auto it = this->m_remoteNodesSocketIPPortStrMap.find(context->m_socket); //该socket对应的节点数据不存在 if (it == this->m_remoteNodesSocketIPPortStrMap.end()) return; this->m_remoteNodes[it->second]->deleteWriteContext(context); } /** * 遍历处理节点 * @param handleFun 传入的处理函数 返回false退出循环 返回true退出循环 */ void traverseHandleNodes(std::function<bool(std::shared_ptr<NodeSocketContextData>&)> handleFun) { std::lock_guard<std::mutex> lock(this->m_remoteNodesMx); for (auto& pair : this->m_remoteNodes) if (!handleFun(pair.second)) return; } /** * 清除数据 */ void clear() { this->m_remoteNodesSocketIPPortStrMap.clear(); this->m_remoteNodes.clear(); } }; /** * 预备服务器信息============================================================================== */ class PrePareServerInformation { public: int m_port; const char* m_IP; public: /** * * @param IP * @param port */ PrePareServerInformation(const char* IP , int port) { this->m_port = port; this->m_IP = IP; } ~PrePareServerInformation(){} }; /** * 节点接口================================================================================ */ class NodeInterface { protected: HANDLE m_iocpHandle; std::vector<std::thread> m_workerThreads; size_t m_maxConcurrentThreads = 1;//线程数 std::atomic<bool> m_running; static std::unordered_map<NODE_TYPE,const std::string> ipPortStrMap; //回调函数 std::function<void(SOCKET)> m_onConnected = NULL; std::function<void(SOCKET)> m_onDisconnected = NULL; std::function<void(SOCKET,const char*,int)> m_onDataReceived = NULL; //远程节点数据 RemoteNodesData m_remoteNodesData; static std::mutex handleErrorMx; //注册IOContext上下文Map,需要new新IOcontext时的登记列表 std::unordered_map<void*,std::shared_ptr<IOContext>> m_registerIOContexts; std::mutex m_registerIOContextsMx; protected: /** * * @return */ virtual NODE_TYPE getNodeType() {} /** * 跳转处理函数 * @param context * @param bytesTransferred */ virtual void jumpHandleFun(std::shared_ptr<IOContext>& context ,DWORD bytesTransferred ){} /** * 启动回调函数 */ virtual void startCallBackFun() {} /** * 关闭回调函数 */ virtual void shutDownCallBackFun() {} /** * * @return */ const std::string& getNodeTypeStr() { return NodeInterface::ipPortStrMap[this->getNodeType()]; } /** * 注册上下文 * @param socket * @param IOOperation */ void registerIOContext(SOCKET socket, IO_OPERATION IOOperation) { if (socket == INVALID_SOCKET) return; IOContext* context = new IOContext(); context->m_operation = IOOperation; context->m_socket = socket; this->m_registerIOContexts[&context->m_overlapped] = std::shared_ptr<IOContext>(context); } /** * 注册上下文 * @return */ std::shared_ptr<IOContext> registerIOContext() { std::shared_ptr<IOContext> context(new IOContext()); std::cout << "Register IOContext = " << &context<< std::endl; this->m_registerIOContexts[&context.get()->m_overlapped] = context; return context; } /** * * @param context */ void registerIOContext(std::shared_ptr<IOContext>& context) { this->m_registerIOContexts[&context.get()->m_overlapped] = context; } /** * * @param overlappedAddress */ void deleteRegisterIOContext(void* overlappedAddress) { auto it = this->m_registerIOContexts.find(overlappedAddress); if (it == this->m_registerIOContexts.end()) return; std::lock_guard<std::mutex> lock(this->m_registerIOContextsMx); std::cout << "Delete RegisterIOContext" << std::endl; it = this->m_registerIOContexts.find(overlappedAddress); if (it == this->m_registerIOContexts.end()) return; this->m_registerIOContexts.erase(it); } /** * * @param overlappedAddress * @return */ std::shared_ptr<IOContext> getRegisterIOContext(void* overlappedAddress) { auto it = this->m_registerIOContexts.find(overlappedAddress); if (it == this->m_registerIOContexts.end()) return nullptr; return it->second; } /** * * @param message * @param fatal */ void handleError(const char* message, bool fatal = false) { std::lock_guard<std::mutex> lock(NodeInterface::handleErrorMx); DWORD error = WSAGetLastError(); std::string nodeTypeStr = this->getNodeTypeStr()+":"; std::string str= error == 0 ? "Unknown" : strerror( error ); std::cout <<nodeTypeStr<< message << " failed with error" << error << ":" << str << std::endl; if (!fatal) return; WSACleanup(); ExitProcess(1); } /** * * @param socket */ void closeSocket(SOCKET& socket) { if (this->m_onDisconnected != NULL) this->m_onDisconnected(socket); this->m_remoteNodesData.deleteRemeoteNodesBySocket(socket); } /** * * @param context */ void postRead(std::shared_ptr<IOContext>& context) { DWORD flags = 0; DWORD bytesRead; context.get()->m_operation = IO_OPERATION::READ; if (WSARecv( context.get()->m_socket, &context.get()->m_dataBuf, 1, &bytesRead, &flags, &context.get()->m_overlapped, NULL) == SOCKET_ERROR) { DWORD error = WSAGetLastError(); if (error != ERROR_IO_PENDING) { this->handleError("WSARecv"); this->closeSocket(context.get()->m_socket); } } } /** * * @param IP * @param port * @param data * @param length */ void postWrite(const char* IP, int port, const char* data, int length) { std::string IPPortStr = std::string(IP) + ":" + std::to_string(port); //不存在该节点 if (!this->m_remoteNodesData.hashNode(IPPortStr)) return; //注册上下文 std::shared_ptr<IOContext> writeContext = this->registerIOContext(); writeContext.get()->m_socket = this->m_remoteNodesData.getNodeSocketByIPPortStr(IPPortStr); writeContext.get()->m_operation = IO_OPERATION::WRITE; memcpy(writeContext.get()->m_buffer,data,length); writeContext.get()->m_dataBuf.len = length; DWORD bytesSent; if (WSASend( writeContext.get()->m_socket, &writeContext.get()->m_dataBuf, 1, &bytesSent, 0, &writeContext.get()->m_overlapped, NULL) == SOCKET_ERROR) { DWORD error = WSAGetLastError(); if (error != WSA_IO_PENDING) { handleError("WSASend"); this->closeSocket(writeContext.get()->m_socket); return; } } //加入节点读写上下文 this->m_remoteNodesData.addRemeoteNodeWriteContext(writeContext); } /** * * @param socket * @param data * @param length */ void postWrite(SOCKET socket, const char* data, int length) { //Socket为空 if (socket == INVALID_SOCKET) return; //注册上下文 std::shared_ptr<IOContext> writeContext = this->registerIOContext(); writeContext.get()->m_socket = socket; writeContext.get()->m_operation = IO_OPERATION::WRITE; memcpy(writeContext.get()->m_buffer,data,length); writeContext.get()->m_dataBuf.len = length; DWORD bytesSent; if (WSASend( writeContext.get()->m_socket, &writeContext.get()->m_dataBuf, 1, &bytesSent, 0, &writeContext.get()->m_overlapped, NULL) == SOCKET_ERROR) { DWORD error = WSAGetLastError(); if (error != WSA_IO_PENDING) { handleError("WSASend"); this->closeSocket(writeContext.get()->m_socket); this->deleteRegisterIOContext(&writeContext.get()->m_overlapped); return; } } //加入节点读写上下文 this->m_remoteNodesData.addRemeoteNodeWriteContext(writeContext); } /** * 处理读操作 * @param context * @param bytesTransfered */ void handleRead(std::shared_ptr<IOContext>& context, DWORD bytesTransferred) { //客户端断开连接 if (bytesTransferred == 0) { this->closeSocket(context.get()->m_socket); return; } if (this->m_onDataReceived != NULL) { this->m_onDataReceived(context.get()->m_socket,context.get()->m_buffer,bytesTransferred); } //继续投递读操作 this->postRead(context); } /** * * @param context * @param bytesTransferred */ void handleWrite(std::shared_ptr<IOContext>& context, DWORD bytesTransferred) { if (!context) return; this->deleteRegisterIOContext(&context.get()->m_overlapped); //写入完成,释放上下文 this->m_remoteNodesData.deleteRemeoteNodeWriteContext(context); //context.reset(); } /** * 工作线程 */ void workerThread() { DWORD bytesTransferred; ULONG_PTR completionKey; LPOVERLAPPED overlapped; while (this->m_running) { std::cout << this->getNodeTypeStr() << "等待I/O端口返回=========" << std::endl; BOOL result = GetQueuedCompletionStatus(this->m_iocpHandle,&bytesTransferred,&completionKey,&overlapped,INFINITE); std::cout << this->getNodeTypeStr() << "I/O端口返回数据=========" << std::endl; //处理错误或者超时 if (!result) { DWORD error = GetLastError(); //超时 if (overlapped == NULL && error == WAIT_TIMEOUT) continue; if (error != WAIT_TIMEOUT && error != ERROR_NETNAME_DELETED) this->handleError("GetQueuedCompletionStatus"); //客户端断开连接 if (overlapped != NULL) { //获取注册的上下文 std::shared_ptr<IOContext> context = this->getRegisterIOContext(overlapped); if (context == nullptr) continue; if (context.get()->m_operation == IO_OPERATION::READ || context.get()->m_operation == IO_OPERATION::WRITE) this->closeSocket(context.get()->m_socket); } continue; } //收到退出信号 if (bytesTransferred == 0 && completionKey == NULL && overlapped == NULL) break; //获取注册的上下文 std::shared_ptr<IOContext> context = this->getRegisterIOContext(overlapped); if (context == nullptr) continue; this->jumpHandleFun(context,bytesTransferred); } } public: void setOnConnected(std::function<void(SOCKET)> callback) {this->m_onConnected = callback;} void setOnDisconnected(std::function<void(SOCKET)> callback) {this->m_onDisconnected = callback;} void setOnDataReceived(std::function<void(SOCKET,const char* ,int)> callback){this->m_onDataReceived =callback;} /** * 启动节点 */ void start() { //已经启动 if (this->m_running) return; this->startCallBackFun(); //启动失败 if (!this->m_running) return; std::cout << this->getNodeTypeStr() << ":startCallBackFun is runned!" << std::endl; //join线程 for (std::thread& worker : this->m_workerThreads) if (worker.joinable())worker.join(); } /** * 关闭节点 */ void shutDown() { if (!this->m_running) return; this->m_running = false; //关闭所有远程节点的Socket auto closeSocketFun = [](std::shared_ptr<NodeSocketContextData>& remoteNode)->bool { if(remoteNode->getSocket() == INVALID_SOCKET) return true; //关闭socket closesocket(remoteNode.get()->getSocket()); return true; }; //封装遍历处理函数 //传入遍历处理远程节点数据函数 this->m_remoteNodesData.traverseHandleNodes(closeSocketFun); //清除远程节点数据 this->m_remoteNodesData.clear(); //关闭IOCP句柄 if (this->m_iocpHandle != NULL) { CloseHandle(this->m_iocpHandle); this->m_iocpHandle = NULL; } //调用节点关闭回调函数 this->shutDownCallBackFun(); //唤醒所有工作线程, 发送退出信号 for (size_t i = 0; i < this->m_workerThreads.size();i++) PostQueuedCompletionStatus(this->m_iocpHandle,0,(ULONG_PTR)NULL,NULL); //等待所有工作线程 for (std::thread& thred:this->m_workerThreads) if (thred.joinable()) thred.join(); this->m_workerThreads.clear(); WSACleanup(); } /** * * @param IP * @param port * @param message */ void send(const char* IP, int port, const char* message) { if (!this->m_running) return; this->postWrite(IP,port,message,strlen(message)); } /** * * @param socket * @param message */ void send(SOCKET socket, const char* message) { if (!this->m_running) return; this->postWrite(socket,message,strlen(message)); } NodeInterface() {} virtual ~NodeInterface() {} }; /** * 服务器================================================================================== */ class Server: public NodeInterface { private: int m_port; SOCKET m_listenSocket; //static constexpr不需要类外定义 static constexpr NODE_TYPE nodeType = IOCP2::NODE_TYPE::SERVER; private: /** * 投递新的接收连接操作 */ void postAccept() { SOCKET clientSocket = WSASocket(AF_INET,SOCK_STREAM,IPPROTO_TCP,NULL,0,WSA_FLAG_OVERLAPPED); if (clientSocket == INVALID_SOCKET) { this->handleError("WSASocket for accept"); return; } //注册上下文,防止上下文被析构 std::shared_ptr<IOContext> context = this->registerIOContext(); context.get()->m_operation = IO_OPERATION::ACCEPT; context.get()->m_socket = clientSocket; DWORD bytesReceived; //接收连接 if (!WSAIoctlTool::acceptExFun( this->m_listenSocket, clientSocket, context.get()->m_buffer, &bytesReceived, &context.get()->m_overlapped)) { DWORD error = WSAGetLastError(); if (error == ERROR_IO_PENDING) return; this->handleError("AcceptEx"); //删除注册上下文 this->deleteRegisterIOContext(&context.get()->m_overlapped); closesocket(clientSocket); } } /** * 处理接收连接 * @param context */ void handleAccept(std::shared_ptr<IOContext>& context) { //调用连接到客户端回调函数 if (this->m_onConnected != NULL) this->m_onConnected(context.get()->m_socket); //将新socket关联到IOCP if (CreateIoCompletionPort( (HANDLE)context.get()->m_socket, this->m_iocpHandle, (ULONG_PTR)context.get()->m_socket, 0) == NULL) { this->handleError("CreateIoCompletionPort for client socket"); closesocket(context.get()->m_socket); return; } //获取客户端信息 std::string IPPortStr = WSAIoctlTool::GetAcceptExSockaddrsFun(context.get()->m_socket,context.get()->m_buffer); //获取到的数据为空 if (IPPortStr.empty() || IPPortStr == "") { this->handleError("GetAcceptExSockaddrs"); return; } //加入远程节点数据 std::shared_ptr<NodeSocketContextData> nodeContextData(new NodeSocketContextData(IPPortStr,context.get()->m_socket)); this->m_remoteNodesData.addRemoteNode(nodeContextData); /*//注册上下文 this->registerIOContext(context);*/ //为新连接投递读操作 this->postRead(context); //将读操作的上下文加入节点管理,防止提前释放 //this->m_remoteNodesData.addRemeoteNodeReadContext(context); //继续投递接收连接操作 this->postAccept(); } /** * * @param context * @param bytesTransferred */ void jumpHandleFun(std::shared_ptr<IOContext> &context, DWORD bytesTransferred) override { switch (context->m_operation) { case IO_OPERATION::ACCEPT: this->handleAccept(context); break; case IO_OPERATION::READ: this->handleRead(context, bytesTransferred); break; case IO_OPERATION::WRITE: this->handleWrite(context, bytesTransferred); break; } } /** * 启动回调函数 */ void startCallBackFun() override { //初始化WinSocket WSADATA WSAData; if (WSAStartup(MAKEWORD(2,2), &WSAData) != 0) { this->handleError("WSAStartup",true); return; } //创建监听socket this->m_listenSocket = WSASocket(AF_INET,SOCK_STREAM,IPPROTO_TCP,NULL,0,WSA_FLAG_OVERLAPPED); if (this->m_listenSocket == INVALID_SOCKET) { this->handleError("WSASocket",true); return; } //绑定地址 sockaddr_in serverAddr; serverAddr.sin_family = AF_INET; serverAddr.sin_addr.s_addr = htonl(INADDR_ANY); serverAddr.sin_port = htons(this->m_port); if (bind(this->m_listenSocket,(sockaddr*)&serverAddr,sizeof(serverAddr)) == SOCKET_ERROR) { this->handleError("bind",true); closesocket(this->m_listenSocket); return; } //创建IOCP this->m_iocpHandle =CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,0); if (this->m_iocpHandle == NULL) { handleError("CreateIoCompletionPort",true); closesocket(this->m_listenSocket); return; } //将监听socket关联到IOCP if (CreateIoCompletionPort( (HANDLE)this->m_listenSocket, this->m_iocpHandle, (ULONG_PTR)this->m_listenSocket, 0) == NULL) { this->handleError("CreateIoCompletionPort for listen socket",true); closesocket(this->m_listenSocket); CloseHandle(this->m_iocpHandle); return; } //开始监听 if (listen(this->m_listenSocket,SOMAXCONN) == SOCKET_ERROR) { this->handleError("listen",true); closesocket(this->m_listenSocket); CloseHandle(this->m_iocpHandle); return; } //创建工作线程 this->m_running = true; for (size_t i = 0; i < this->m_maxConcurrentThreads; i++) this->m_workerThreads.emplace_back(&IOCP2::Server::workerThread,this); //投递初始化接收连接操作 this->postAccept(); } /** * 关闭回调函数 */ void shutDownCallBackFun() override { if (this->m_listenSocket == INVALID_SOCKET) return; closesocket(this->m_listenSocket); this->m_listenSocket = INVALID_SOCKET; } public: /** * * @return */ NODE_TYPE getNodeType() override { return Server::nodeType; } /** * * @param port */ Server(int port) { this->m_port = port; this->m_running = false; } ~Server() override { this->shutDown(); } }; /** * 客户端================================================================================== */ class Client: public NodeInterface { private: static constexpr NODE_TYPE nodeType = NODE_TYPE::CLIENT; //预备服务器信息 std::queue<PrePareServerInformation> m_prePareServers; private: /** * * @param context * @param bytesTransferred */ void jumpHandleFun(std::shared_ptr<IOContext> &context, DWORD bytesTransferred) override { switch (context.get()->m_operation) { case IO_OPERATION::READ: this->handleRead(context,bytesTransferred); break; case IO_OPERATION::WRITE: this->handleWrite(context,bytesTransferred); break; default: break; } } /** * * @param prePareServer */ void connectServer(PrePareServerInformation& prePareServer) { //创建Socket SOCKET serverSocket = WSASocket(AF_INET,SOCK_STREAM,IPPROTO_TCP,NULL,0,WSA_FLAG_OVERLAPPED); if (serverSocket == INVALID_SOCKET) { this->handleError("WSASocket",true); return; } //解析服务器地址 sockaddr_in serverAddr; serverAddr.sin_family = AF_INET; serverAddr.sin_port = htons(prePareServer.m_port); inet_pton(AF_INET,prePareServer.m_IP,&serverAddr.sin_addr); //连接服务器 if (connect(serverSocket,(sockaddr*)&serverAddr,sizeof(serverAddr)) == SOCKET_ERROR) { DWORD errror = WSAGetLastError(); this->handleError("connect"); closesocket(serverSocket); return; } //将socket关联到IOCP if (CreateIoCompletionPort( (HANDLE)serverSocket, this->m_iocpHandle, (ULONG_PTR)serverSocket, 0) == NULL) { this->handleError("CreateIoCompletionPort"); closesocket(serverSocket); CloseHandle(this->m_iocpHandle); return; } this->m_running = true; //加入远程节点 std::string IPPortStr = std::string(prePareServer.m_IP)+":"+std::to_string(prePareServer.m_port); std::shared_ptr<NodeSocketContextData> nodeContextData(new NodeSocketContextData(IPPortStr,serverSocket)); this->m_remoteNodesData.addRemoteNode(nodeContextData); //注册上下文 std::shared_ptr<IOContext> context = this->registerIOContext(); context.get()->m_socket = serverSocket; //投递读操作 this->postRead(context); //调用连接回调函数 if (this->m_onConnected != NULL) this->m_onConnected(serverSocket); } /** * 启动回到调函数 */ void startCallBackFun() override { //初始化WinSocket WSAData wsaData; if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) { this->handleError("WSAStartup",true); return; } //创建IOCP this->m_iocpHandle = CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,0); if (this->m_iocpHandle == NULL) { this->handleError("CreateIoCompletionPort",true); return; } //连接服务器 while (!this->m_prePareServers.empty()) { this->connectServer(this->m_prePareServers.front()); std::cout << "client:connectServer......."<< std::endl; this->m_prePareServers.pop(); } // 仅当有有效连接时才创建工作线程 if (this->m_running) for (size_t i = 0; i < this->m_maxConcurrentThreads ; i++) this->m_workerThreads.emplace_back(&IOCP2::Client::workerThread,this); } /** * 关闭回调函数 */ void shutDownCallBackFun() override { } public: /** * * @param IP * @param port */ void addServer(const char* IP, int port) { if (this->m_running) return; this->m_prePareServers.push(std::move(PrePareServerInformation(IP,port))); } /** * * @return */ NODE_TYPE getNodeType() override { return Client::nodeType; } Client() { this->m_running = false; } ~Client() override { this->shutDown(); } }; }; GUID IOCP2::WSAIoctlTool::guidAcceptEx = WSAID_ACCEPTEX; GUID IOCP2::WSAIoctlTool::guidGetAcceptExSockaddrs = WSAID_GETACCEPTEXSOCKADDRS; std::unordered_map<IOCP2::NODE_TYPE,const std::string> IOCP2::NodeInterface::ipPortStrMap = { {IOCP2::NODE_TYPE::SERVER,"server"}, {IOCP2::NODE_TYPE::CLIENT,"client"} }; std::mutex IOCP2::NodeInterface::handleErrorMx;#include <iostream> #include <string> #include <thread> #include "test/IOCP2.hpp" #pragma comment(lib, "ws2_32.lib") #pragma comment(lib, "mswsock.lib") int main() { IOCP2::Server server(1001); IOCP2::Client client; client.addServer("127.0.0.1",1001); std::thread serverThread([&]() { server.setOnDataReceived([&](SOCKET socket, const char* buffer, int len) { std::cout << "server received message: " << buffer << std::endl; const char* message = "hellow client! server received message"; client.send(socket,message); }); server.start(); }); std::this_thread::sleep_for(std::chrono::seconds(3)); std::thread clientThread([&]() { client.setOnConnected([&](SOCKET socket) { std::cout << "client: connect socket = " << socket << std::endl; }); client.setOnDataReceived([&](SOCKET socket, const char* buffer, int len) { std::cout << "client received message: " << buffer << std::endl; client.send(socket,"hellow client! server received message"); }); client.start(); }); std::this_thread::sleep_for(std::chrono::seconds(3)); std::thread clientSendThread([&]() { const char* buffer = "Hello World!"; client.send("127.0.0.1",1001,buffer); }); serverThread.join(); clientThread.join(); clientSendThread.join(); return 0; }运行之后会内存泄露,问题初步定位是handWrite
10-17
#define WIN32_LEAN_AND_MEAN #define _WINSOCK_DEPRECATED_NO_WARNINGS #include <winsock2.h> #include <windows.h> #include <iostream> #include <iomanip> #include <sstream> #include <string> #include <fstream> #include <unordered_map> #include <algorithm> #include <cstring> #include <atomic> #include <thread> #include <chrono> #include <vector> #include <queue> #include <mutex> #include <condition_variable> #pragma comment(lib, "ws2_32.lib") #pragma comment(lib, "mswsock.lib") // 用于AcceptEx等异步操作 using namespace std; // 常量定义 constexpr DWORD CLIENT_SUB_ADDRESS = 0xAED9F0; constexpr DWORD CRAG_CONNECTION_INSTANCE_R_ADDRESS = 0xAEDE00; constexpr DWORD RECV_PTR_ADDRESS = 0x1424E18; constexpr int RING_BUFFER_SIZE = 64 * 1024; // 64KB环形缓冲区 constexpr int PACKET_POOL_SIZE = 1024; // 预分配1024个封包对象 constexpr int MAX_PACKET_SIZE = 8192; // 最大封包大小8KB constexpr DWORD TIMEOUT = 600000; // 10分钟超时 constexpr DWORD RECONNECT_INTERVAL = 3000; // 3秒重连间隔 constexpr DWORD PING_INTERVAL = 5000; // 5秒Ping间隔 constexpr DWORD SLEEP_TIME = 5; // 5ms休眠 constexpr DWORD HOOK_DELAY = 3000; // 3秒延迟应用Hook constexpr int WORKER_THREAD_COUNT = 4; // 工作线程数量 constexpr int MAX_ASYNC_OPS = 100; // 最大异步操作数量 enum e_PacketType { RECEIVED = 0, SENDED = 1 }; // 原子类型定义 using atomic_socket = atomic<SOCKET>; using atomic_bool = atomic<bool>; using atomic_dword = atomic<DWORD>; // 前向声明 typedef int(__thiscall* SendToClientFunc)(void* CragConnection, size_t size, char* buffer); typedef void* (__stdcall* originalInstanceR)(void); // 异步操作上下文 struct AsyncOperationContext { OVERLAPPED overlapped; SOCKET socket; WSABUF wsaBuf; char buffer[MAX_PACKET_SIZE]; DWORD bytesTransferred; DWORD flags; atomic_bool inUse; AsyncOperationContext() : socket(INVALID_SOCKET), bytesTransferred(0), flags(0) { ZeroMemory(&overlapped, sizeof(OVERLAPPED)); ZeroMemory(buffer, MAX_PACKET_SIZE); inUse.store(false, memory_order_relaxed); } void reset() { ZeroMemory(&overlapped, sizeof(OVERLAPPED)); bytesTransferred = 0; flags = 0; inUse.store(false, memory_order_relaxed); } }; // 线程安全的队列 template<typename T> class ThreadSafeQueue { private: queue<T> queue_; mutable mutex mutex_; condition_variable cond_; public: void push(T value) { lock_guard<mutex> lock(mutex_); queue_.push(move(value)); cond_.notify_one(); } bool try_pop(T& value) { lock_guard<mutex> lock(mutex_); if (queue_.empty()) { return false; } value = move(queue_.front()); queue_.pop(); return true; } bool empty() const { lock_guard<mutex> lock(mutex_); return queue_.empty(); } size_t size() const { lock_guard<mutex> lock(mutex_); return queue_.size(); } }; // 极简环形缓冲区 class SimpleRingBuffer { private: char* buffer; atomic<uint32_t> read_pos; atomic<uint32_t> write_pos; uint32_t size_mask; public: SimpleRingBuffer(uint32_t size) { // 确保大小为2的幂 uint32_t actual_size = 1; while (actual_size < size) actual_size <<= 1; buffer = new char[actual_size]; size_mask = actual_size - 1; read_pos.store(0, memory_order_relaxed); write_pos.store(0, memory_order_relaxed); } ~SimpleRingBuffer() { delete[] buffer; } uint32_t available_read() const { return write_pos.load(memory_order_acquire) - read_pos.load(memory_order_acquire); } uint32_t available_write() const { return size_mask + 1 - (write_pos.load(memory_order_acquire) - read_pos.load(memory_order_acquire)); } bool push(const char* data, uint32_t len) { uint32_t wp = write_pos.load(memory_order_acquire); uint32_t rp = read_pos.load(memory_order_acquire); uint32_t available = size_mask + 1 - (wp - rp); if (available < len) return false; uint32_t index = wp & size_mask; uint32_t first_chunk = min(len, size_mask + 1 - index); memcpy(buffer + index, data, first_chunk); if (first_chunk < len) { memcpy(buffer, data + first_chunk, len - first_chunk); } write_pos.store(wp + len, memory_order_release); return true; } uint32_t pop(char* dest, uint32_t len) { uint32_t rp = read_pos.load(memory_order_acquire); uint32_t wp = write_pos.load(memory_order_acquire); uint32_t available = wp - rp; if (available == 0) return 0; uint32_t to_read = min(len, available); uint32_t index = rp & size_mask; uint32_t first_chunk = min(to_read, size_mask + 1 - index); memcpy(dest, buffer + index, first_chunk); if (first_chunk < to_read) { memcpy(dest + first_chunk, buffer, to_read - first_chunk); } read_pos.store(rp + to_read, memory_order_release); return to_read; } void clear() { read_pos.store(0, memory_order_relaxed); write_pos.store(0, memory_order_relaxed); } }; // 极简内存池 class SimplePacketPool { private: struct PacketNode { char data[MAX_PACKET_SIZE]; uint16_t size; atomic<PacketNode*> next; }; PacketNode* nodes; atomic<PacketNode*> free_head; public: SimplePacketPool(size_t count) { nodes = new PacketNode[count]; // 构建链表 for (size_t i = 0; i < count - 1; ++i) { nodes[i].next.store(&nodes[i + 1], memory_order_relaxed); } nodes[count - 1].next.store(nullptr, memory_order_relaxed); free_head.store(nodes, memory_order_relaxed); } ~SimplePacketPool() { delete[] nodes; } PacketNode* acquire() { PacketNode* current_head = free_head.load(memory_order_acquire); while (current_head) { if (free_head.compare_exchange_weak(current_head, current_head->next.load(memory_order_acquire), memory_order_acq_rel, memory_order_acquire)) { return current_head; } } return nullptr; } void release(PacketNode* node) { if (!node) return; PacketNode* current_head = free_head.load(memory_order_acquire); node->next.store(current_head, memory_order_relaxed); while (!free_head.compare_exchange_weak(current_head, node, memory_order_acq_rel, memory_order_acquire)) { node->next.store(current_head, memory_order_relaxed); } } }; // 全局变量 atomic_socket koreClient(INVALID_SOCKET); atomic_socket roServer(INVALID_SOCKET); atomic_bool koreClientIsAlive(false); atomic_bool keepMainThread(true); atomic_bool imalive(false); atomic_bool hook_applied(false); atomic_bool hook_delayed(false); SimpleRingBuffer sendBuffer(RING_BUFFER_SIZE); SimplePacketPool packetPool(PACKET_POOL_SIZE); string koreServerIP; DWORD koreServerPort; bool allowMultiClient = false; // Hook相关 typedef int (WINAPI* recv_func_t)(SOCKET s, char* buf, int len, int flags); recv_func_t original_recv = nullptr; // 异步I/O相关 HANDLE iocpHandle = NULL; vector<AsyncOperationContext*> asyncContexts; ThreadSafeQueue<AsyncOperationContext*> freeContexts; mutex contextMutex; // 工作线程池 vector<thread> workerThreads; atomic_bool workersRunning(false); // 函数声明 void AllocateConsole(); void debug(const char* msg); bool CreateDefaultConfig(const std::string& filename); bool LoadConfig(const std::string& filename); bool ApplyHook(); void RemoveHook(); bool isConnected(SOCKET s); SOCKET createSocket(const std::string& ip, int port); DWORD GetUserPort(); void init(); void finish(); // 异步I/O函数声明 bool InitializeAsyncIO(); void CleanupAsyncIO(); AsyncOperationContext* GetAsyncContext(); void ReturnAsyncContext(AsyncOperationContext* context); bool PostAsyncRecv(SOCKET socket); void WorkerThreadProc(); bool InitializeWorkerThreads(); void CleanupWorkerThreads(); // 优化函数声明 SOCKET createOptimizedSocket(const std::string& ip, int port); void optimizedSendToKore(const char* data, uint16_t len, e_PacketType type); DWORD WINAPI highPerformancePacketProcessor(LPVOID lpParam); DWORD WINAPI koreConnectionMainOptimized(LPVOID lpParam); bool ApplyHookOptimized(); void initOptimized(); void finishOptimized(); void DelayedHookApplication(); // IOCP优化器 class IOCPOptimizer { private: HANDLE iocp_handle; public: IOCPOptimizer() : iocp_handle(NULL) {} bool initialize() { iocp_handle = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0); return iocp_handle != NULL; } bool associateSocket(SOCKET socket) { return CreateIoCompletionPort((HANDLE)socket, iocp_handle, 0, 0) != NULL; } HANDLE getHandle() { return iocp_handle; } ~IOCPOptimizer() { if (iocp_handle) { CloseHandle(iocp_handle); } } }; IOCPOptimizer iocp_optimizer; // 异步I/O初始化 bool InitializeAsyncIO() { // 创建IOCP句柄 iocpHandle = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, WORKER_THREAD_COUNT); if (iocpHandle == NULL) { cout << "[错误] 创建IOCP句柄失败: " << GetLastError() << endl; return false; } // 预分配异步操作上下文 for (int i = 0; i < MAX_ASYNC_OPS; ++i) { AsyncOperationContext* context = new AsyncOperationContext(); asyncContexts.push_back(context); freeContexts.push(context); } cout << "[成功] 异步I/O初始化完成,预分配 " << MAX_ASYNC_OPS << " 个上下文" << endl; return true; } // 清理异步I/O资源 void CleanupAsyncIO() { if (iocpHandle) { CloseHandle(iocpHandle); iocpHandle = NULL; } // 清理异步上下文 for (auto context : asyncContexts) { delete context; } asyncContexts.clear(); // 清空空闲队列 while (!freeContexts.empty()) { AsyncOperationContext* context = nullptr; freeContexts.try_pop(context); } } // 获取异步操作上下文 AsyncOperationContext* GetAsyncContext() { AsyncOperationContext* context = nullptr; if (freeContexts.try_pop(context)) { context->inUse.store(true, memory_order_relaxed); return context; } // 如果没有空闲上下文,动态创建一个(应该很少发生) lock_guard<mutex> lock(contextMutex); context = new AsyncOperationContext(); context->inUse.store(true, memory_order_relaxed); asyncContexts.push_back(context); cout << "[警告] 动态创建异步上下文,当前总数: " << asyncContexts.size() << endl; return context; } // 归还异步操作上下文 void ReturnAsyncContext(AsyncOperationContext* context) { if (context) { context->reset(); freeContexts.push(context); } } // 提交异步接收操作 bool PostAsyncRecv(SOCKET socket) { AsyncOperationContext* context = GetAsyncContext(); if (!context) { cout << "[错误] 无法获取异步上下文" << endl; return false; } context->socket = socket; context->wsaBuf.buf = context->buffer; context->wsaBuf.len = MAX_PACKET_SIZE; context->bytesTransferred = 0; context->flags = 0; DWORD bytesReceived = 0; // 使用WSARecv进行异步接收 int result = WSARecv(socket, &context->wsaBuf, 1, &bytesReceived, &context->flags, &context->overlapped, NULL); if (result == SOCKET_ERROR) { int error = WSAGetLastError(); if (error != WSA_IO_PENDING) { cout << "[错误] WSARecv失败: " << error << endl; ReturnAsyncContext(context); return false; } } return true; } // 工作线程处理函数 void WorkerThreadProc() { while (workersRunning.load(memory_order_acquire)) { DWORD bytesTransferred = 0; ULONG_PTR completionKey = 0; LPOVERLAPPED overlapped = nullptr; // 等待IOCP完成事件 BOOL success = GetQueuedCompletionStatus(iocpHandle, &bytesTransferred, &completionKey, &overlapped, INFINITE); if (!workersRunning.load(memory_order_acquire)) { break; } if (!overlapped) { // 收到退出信号 continue; } // 获取异步上下文 AsyncOperationContext* context = CONTAINING_RECORD(overlapped, AsyncOperationContext, overlapped); if (!success) { DWORD error = GetLastError(); if (error != WAIT_TIMEOUT) { cout << "[错误] IOCP操作失败: " << error << endl; // 处理连接断开 if (context->socket == koreClient.load(memory_order_acquire)) { koreClient.store(INVALID_SOCKET, memory_order_release); koreClientIsAlive.store(false, memory_order_release); } } ReturnAsyncContext(context); continue; } // 处理接收到的数据 if (bytesTransferred > 0) { // 处理数据包逻辑 char* data = context->buffer; int remaining = bytesTransferred; while (remaining >= 3) { char packet_type = data[0]; uint16_t packet_len = *reinterpret_cast<uint16_t*>(data + 1); if (remaining < 3 + packet_len) break; if (packet_type == 'S' && packet_len > 0) { // 发送到RO客户端 auto* sendFunc = reinterpret_cast<SendToClientFunc>(CLIENT_SUB_ADDRESS); auto* instanceR = reinterpret_cast<originalInstanceR>(CRAG_CONNECTION_INSTANCE_R_ADDRESS); if (sendFunc && instanceR) { void* instance = instanceR(); if (instance) { sendFunc(instance, packet_len, data + 3); } } } int packet_total_size = 3 + packet_len; data += packet_total_size; remaining -= packet_total_size; } // 继续提交异步接收 if (context->socket != INVALID_SOCKET) { PostAsyncRecv(context->socket); } } else { // 连接关闭 if (context->socket == koreClient.load(memory_order_acquire)) { koreClient.store(INVALID_SOCKET, memory_order_release); koreClientIsAlive.store(false, memory_order_release); } ReturnAsyncContext(context); } } } // 初始化工作线程池 bool InitializeWorkerThreads() { workersRunning.store(true, memory_order_release); for (int i = 0; i < WORKER_THREAD_COUNT; ++i) { workerThreads.emplace_back(WorkerThreadProc); } cout << "[成功] 启动 " << WORKER_THREAD_COUNT << " 个工作线程" << endl; return true; } // 清理工作线程池 void CleanupWorkerThreads() { workersRunning.store(false, memory_order_release); // 向所有线程发送退出信号 for (size_t i = 0; i < workerThreads.size(); ++i) { PostQueuedCompletionStatus(iocpHandle, 0, 0, NULL); } // 等待线程退出 for (auto& thread : workerThreads) { if (thread.joinable()) { thread.join(); } } workerThreads.clear(); cout << "[信息] 工作线程池已清理" << endl; } // 优化的recv钩子函数 int WINAPI hooked_recv(SOCKET s, char* buf, int len, int flags) { int result = original_recv(s, buf, len, flags); if (result > 0) { roServer.store(s, memory_order_release); // 使用内存池避免动态分配 auto packet_node = packetPool.acquire(); if (packet_node) { packet_node->size = static_cast<uint16_t>(result); memcpy(packet_node->data, buf, result); // 构建发送数据 char send_buf[3 + MAX_PACKET_SIZE]; send_buf[0] = 'R'; *reinterpret_cast<uint16_t*>(send_buf + 1) = packet_node->size; memcpy(send_buf + 3, packet_node->data, packet_node->size); // 非阻塞写入环形缓冲区 if (!sendBuffer.push(send_buf, 3 + packet_node->size)) { // 缓冲区满,直接发送到RO服务器(降级处理) SOCKET ro_sock = roServer.load(memory_order_acquire); if (ro_sock != INVALID_SOCKET) { send(ro_sock, buf, result, 0); } } packetPool.release(packet_node); } } return result; } // 控制台分配 void AllocateConsole() { AllocConsole(); freopen_s((FILE**)stdout, "CONOUT$", "w", stdout); freopen_s((FILE**)stderr, "CONOUT$", "w", stderr); freopen_s((FILE**)stdin, "CONIN$", "r", stdin); #ifdef UNICODE SetConsoleTitle(L"xKore优化版 - 调试控制台"); #else SetConsoleTitle("xKore优化版 - 调试控制台"); #endif } // 调试输出 void debug(const char* msg) { cout << "[调试] " << msg << endl; } // 创建默认配置 bool CreateDefaultConfig(const std::string& filename) { ofstream fout(filename); if (!fout.is_open()) { cout << "[错误] 无法创建配置文件: " << filename << endl; return false; } fout << "# xKore服务器配置\n"; fout << "koreServerIP=127.0.0.1\n"; fout << "koreServerPort=2350\n"; fout << "\n"; fout << "# 多客户端配置\n"; fout << "# 如果为true, 每次执行时在终端询问端口\n"; fout << "# 如果为false, 总是使用koreServerPort的默认端口\n"; fout << "allowMultiClient=true"; fout.close(); cout << "[成功] 默认配置文件已创建: " << filename << endl; return true; } // 加载配置 bool LoadConfig(const std::string& filename) { ifstream fin(filename); if (!fin.is_open()) { if (!CreateDefaultConfig(filename)) { return false; } cout << "\n*** 注意: 使用前请配置 '" << filename << "' 文件! ***" << endl; cout << "========================\n" << endl; fin.open(filename); if (!fin.is_open()) { cout << "[错误] 无法打开创建的配置文件: " << filename << endl; return false; } } string line; unordered_map<string, string> mapa; while (getline(fin, line)) { if (line.empty()) continue; if (line[0] == '#' || line[0] == ';') continue; size_t pos = line.find('='); if (pos == string::npos) continue; string chave = line.substr(0, pos); string valor = line.substr(pos + 1); while (!chave.empty() && isspace(chave.back())) chave.pop_back(); while (!valor.empty() && isspace(valor.front())) valor.erase(0, 1); while (!valor.empty() && isspace(valor.back())) valor.pop_back(); mapa[chave] = valor; } fin.close(); if (mapa.count("koreServerIP") == 0 || mapa.count("koreServerPort") == 0) { cout << "[错误] config_recv.txt中缺少必要的键。需要:\n" << " koreServerIP\n" << " koreServerPort\n"; return false; } try { koreServerIP = mapa.at("koreServerIP"); koreServerPort = static_cast<DWORD>(stoul(mapa.at("koreServerPort"), nullptr, 10)); if (mapa.count("allowMultiClient") > 0) { string allowMultiStr = mapa.at("allowMultiClient"); transform(allowMultiStr.begin(), allowMultiStr.end(), allowMultiStr.begin(), ::tolower); allowMultiClient = (allowMultiStr == "true" || allowMultiStr == "1" || allowMultiStr == "yes"); } } catch (exception& e) { cout << "[错误] 转换值时出现异常: " << e.what() << endl; return false; } cout << "[信息] 配置加载成功:\n\n" << " koreServerIP = " << koreServerIP << "\n" << " koreServerPort = " << koreServerPort << "\n" << " allowMultiClient = " << (allowMultiClient ? "true" : "false") << endl; return true; } // 应用Hook(优化版) bool ApplyHookOptimized() { if (original_recv != nullptr) { return true; // 已经hook } recv_func_t* recv_ptr = reinterpret_cast<recv_func_t*>(RECV_PTR_ADDRESS); original_recv = *recv_ptr; if (original_recv == nullptr) { cout << "错误: 原始recv指针为空!" << endl; return false; } *recv_ptr = hooked_recv; // 验证hook是否成功 if (*recv_ptr == hooked_recv) { hook_applied.store(true, memory_order_release); cout << "Hook应用成功!" << endl; return true; } return false; } // 延迟应用Hook函数 void DelayedHookApplication() { cout << "[信息] 等待3秒后应用Hook(避免强壳和NP检测)..." << endl; // 等待3秒 this_thread::sleep_for(chrono::milliseconds(HOOK_DELAY)); cout << "[信息] 开始应用Hook..." << endl; if (ApplyHookOptimized()) { cout << "[成功] 延迟Hook应用成功" << endl; hook_delayed.store(true, memory_order_release); } else { cout << "[错误] 延迟Hook应用失败" << endl; } } // 移除Hook void RemoveHook() { if (original_recv) { recv_func_t* recv_ptr = reinterpret_cast<recv_func_t*>(RECV_PTR_ADDRESS); *recv_ptr = original_recv; cout << "Hook已移除!" << endl; } } // 检查socket连接状态 bool isConnected(SOCKET s) { if (s == INVALID_SOCKET) return false; fd_set readfds; FD_ZERO(&readfds); FD_SET(s, &readfds); timeval timeout = { 0, 0 }; int result = select(0, &readfds, NULL, NULL, &timeout); if (result == SOCKET_ERROR) return false; return true; } // 创建优化socket SOCKET createOptimizedSocket(const std::string& ip, int port) { sockaddr_in addr; SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (sock == INVALID_SOCKET) { cout << "[错误] 创建socket失败: " << WSAGetLastError() << endl; return INVALID_SOCKET; } // 关键TCP优化参数 int nodelay = 1; if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char*)&nodelay, sizeof(nodelay)) == SOCKET_ERROR) { cout << "[警告] 设置TCP_NODELAY失败: " << WSAGetLastError() << endl; } // 设置发送缓冲区大小 int send_buf_size = 64 * 1024; setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char*)&send_buf_size, sizeof(send_buf_size)); // 设置接收缓冲区大小 int recv_buf_size = 64 * 1024; setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char*)&recv_buf_size, sizeof(recv_buf_size)); addr.sin_family = AF_INET; addr.sin_port = htons(static_cast<u_short>(port)); addr.sin_addr.s_addr = inet_addr(ip.c_str()); // 非阻塞连接 unsigned long mode = 1; ioctlsocket(sock, FIONBIO, &mode); int connect_result = connect(sock, (struct sockaddr*)&addr, sizeof(addr)); // 等待连接完成 fd_set writefds; FD_ZERO(&writefds); FD_SET(sock, &writefds); timeval timeout = { 3, 0 }; // 3秒超时 int select_result = select(0, NULL, &writefds, NULL, &timeout); if (select_result <= 0) { cout << "[错误] 连接超时或失败: " << WSAGetLastError() << endl; closesocket(sock); return INVALID_SOCKET; } // 检查socket错误 int error = 0; int error_len = sizeof(error); getsockopt(sock, SOL_SOCKET, SO_ERROR, (char*)&error, &error_len); if (error != 0) { cout << "[错误] 连接失败: " << error << endl; closesocket(sock); return INVALID_SOCKET; } // 恢复阻塞模式 mode = 0; ioctlsocket(sock, FIONBIO, &mode); // 关联到IOCP if (iocpHandle) { CreateIoCompletionPort((HANDLE)sock, iocpHandle, 0, 0); } return sock; } // 优化数据发送 void optimizedSendToKore(const char* data, uint16_t len, e_PacketType type) { if (!koreClientIsAlive.load(memory_order_acquire)) return; char header[3]; header[0] = (type == RECEIVED) ? 'R' : 'S'; *reinterpret_cast<uint16_t*>(header + 1) = len; // 先尝试写入header if (!sendBuffer.push(header, 3)) { return; // 缓冲区满,丢弃数据 } // 再写入数据 if (!sendBuffer.push(data, len)) { // 回滚header写入 char temp[3]; sendBuffer.pop(temp, 3); } } // 高性能封包处理线程 DWORD WINAPI highPerformancePacketProcessor(LPVOID lpParam) { char local_buf[4096]; atomic_dword last_send_time(GetTickCount()); atomic_dword last_ping_time(GetTickCount()); while (keepMainThread.load(memory_order_acquire)) { DWORD current_time = GetTickCount(); // 处理发送缓冲区 uint32_t available = sendBuffer.available_read(); if (available > 0) { SOCKET kore_sock = koreClient.load(memory_order_acquire); if (kore_sock != INVALID_SOCKET) { uint32_t bytes_read = sendBuffer.pop(local_buf, min(available, sizeof(local_buf))); if (bytes_read > 0) { int sent = send(kore_sock, local_buf, bytes_read, 0); if (sent == SOCKET_ERROR) { // 发送失败,可能连接已断开 koreClient.store(INVALID_SOCKET, memory_order_release); koreClientIsAlive.store(false, memory_order_release); } else { last_send_time.store(current_time, memory_order_relaxed); } } } } // 定期Ping(保持连接活跃) if (current_time - last_ping_time.load(memory_order_relaxed) > PING_INTERVAL) { SOCKET kore_sock = koreClient.load(memory_order_acquire); if (kore_sock != INVALID_SOCKET) { char ping_packet[3] = { 'K', 0, 0 }; send(kore_sock, ping_packet, 3, 0); } last_ping_time.store(current_time, memory_order_relaxed); } // 智能休眠:有数据时忙等待,无数据时短暂休眠 if (available == 0) { Sleep(1); // 1ms休眠减少CPU占用 } } return 0; } // 主连接线程(优化版) DWORD WINAPI koreConnectionMainOptimized(LPVOID lpParam) { // 等待Hook应用完成 while (!hook_delayed.load(memory_order_acquire) && keepMainThread.load(memory_order_acquire)) { cout << "[信息] 等待Hook应用完成..." << endl; Sleep(500); } if (!hook_applied.load(memory_order_acquire)) { cout << "[错误] Hook未应用,连接线程退出" << endl; return 1; } // 创建专用的封包处理线程 HANDLE packet_thread = CreateThread(NULL, 0, highPerformancePacketProcessor, NULL, CREATE_SUSPENDED, NULL); if (!packet_thread) { cout << "[错误] 创建封包处理线程失败: " << GetLastError() << endl; return 1; } // 设置线程优先级 SetThreadPriority(packet_thread, THREAD_PRIORITY_ABOVE_NORMAL); SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL); // 禁用线程库通知减少开销 DisableThreadLibraryCalls(GetModuleHandle(NULL)); // 启动封包处理线程 ResumeThread(packet_thread); char recv_buf[8192]; atomic_dword last_connect_attempt(0); atomic_dword last_activity_time(GetTickCount()); cout << "[信息] xKore连接线程已启动" << endl; while (keepMainThread.load(memory_order_acquire)) { DWORD current_time = GetTickCount(); SOCKET current_kore_client = koreClient.load(memory_order_acquire); // 连接管理 if (current_kore_client == INVALID_SOCKET || !isConnected(current_kore_client)) { if (current_time - last_connect_attempt.load(memory_order_relaxed) > RECONNECT_INTERVAL) { if (current_kore_client != INVALID_SOCKET) { shutdown(current_kore_client, SD_BOTH); closesocket(current_kore_client); } SOCKET new_socket = createOptimizedSocket(koreServerIP, koreServerPort); if (new_socket != INVALID_SOCKET) { koreClient.store(new_socket, memory_order_release); koreClientIsAlive.store(true, memory_order_release); imalive.store(true, memory_order_release); last_activity_time.store(current_time, memory_order_relaxed); // 提交异步接收操作 if (iocpHandle) { PostAsyncRecv(new_socket); } cout << "[成功] 已连接到xKore服务器 " << koreServerIP << ":" << koreServerPort << endl; } else { koreClientIsAlive.store(false, memory_order_release); imalive.store(false, memory_order_release); cout << "[错误] 连接xKore服务器失败" << endl; } last_connect_attempt.store(current_time, memory_order_relaxed); } Sleep(100); // 连接失败时短暂休眠 continue; } // 检查超时 if (current_time - last_activity_time.load(memory_order_relaxed) > TIMEOUT) { cout << "[警告] 连接超时,重新连接..." << endl; koreClient.store(INVALID_SOCKET, memory_order_release); continue; } // 如果没有使用异步I/O,则使用传统的recv if (!iocpHandle) { int bytes_received = recv(current_kore_client, recv_buf, sizeof(recv_buf), 0); if (bytes_received > 0) { last_activity_time.store(current_time, memory_order_relaxed); // 处理接收到的封包 const char* data_ptr = recv_buf; int remaining = bytes_received; while (remaining >= 3) { char packet_type = data_ptr[0]; uint16_t packet_len = *reinterpret_cast<const uint16_t*>(data_ptr + 1); if (remaining < 3 + packet_len) break; // 数据不完整 if (packet_type == 'S' && packet_len > 0) { // 发送到RO客户端 auto* sendFunc = reinterpret_cast<SendToClientFunc>(CLIENT_SUB_ADDRESS); auto* instanceR = reinterpret_cast<originalInstanceR>(CRAG_CONNECTION_INSTANCE_R_ADDRESS); if (sendFunc && instanceR) { void* instance = instanceR(); if (instance) { sendFunc(instance, packet_len, const_cast<char*>(data_ptr + 3)); } } } int packet_total_size = 3 + packet_len; data_ptr += packet_total_size; remaining -= packet_total_size; } } else if (bytes_received == 0) { // 连接关闭 cout << "[信息] xKore服务器断开连接" << endl; shutdown(current_kore_client, SD_BOTH); closesocket(current_kore_client); koreClient.store(INVALID_SOCKET, memory_order_release); koreClientIsAlive.store(false, memory_order_release); imalive.store(false, memory_order_release); } else if (bytes_received == SOCKET_ERROR) { int error = WSAGetLastError(); if (error != WSAEWOULDBLOCK) { cout << "[错误] 接收数据失败: " << error << endl; koreClient.store(INVALID_SOCKET, memory_order_release); } } } // 轻微休眠避免过高CPU占用 Sleep(SLEEP_TIME); } // 清理线程 keepMainThread.store(false, memory_order_release); WaitForSingleObject(packet_thread, 5000); CloseHandle(packet_thread); cout << "[信息] xKore连接线程已退出" << endl; return 0; } // 获取用户端口(多客户端模式) DWORD GetUserPort() { char input[256]; cout << "\n[多客户端模式]" << endl; cout << "请输入xKore服务器端口(默认: " << koreServerPort << "): "; if (fgets(input, sizeof(input), stdin)) { input[strcspn(input, "\r\n")] = 0; if (strlen(input) == 0) { cout << "使用默认端口: " << koreServerPort << endl; return koreServerPort; } int inputPort = atoi(input); if (inputPort > 0 && inputPort <= 65535) { cout << "使用自定义端口: " << inputPort << endl; return static_cast<DWORD>(inputPort); } else { cout << "无效端口! 使用默认端口: " << koreServerPort << endl; return koreServerPort; } } cout << "读取错误! 使用默认端口: " << koreServerPort << endl; return koreServerPort; } // 初始化函数 void initOptimized() { AllocateConsole(); cout << "=== xKore优化版 ===" << endl; cout << "架构: x86 (32位)" << endl; cout << "优化: 原子操作 + 内存池 + 环形缓冲区 + 异步I/O" << endl; cout << "特性: 3秒延迟Hook(避免强壳检测)" << endl; // 初始化Winsock WSADATA wsaData; if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { cout << "[错误] Winsock初始化失败" << endl; return; } // 加载配置 if (!LoadConfig("config_recv.txt")) { cout << "[致命] 加载配置文件失败" << endl; keepMainThread.store(false, memory_order_release); return; } // 多客户端模式 if (allowMultiClient) { koreServerPort = GetUserPort(); } // 初始化异步I/O系统 if (!InitializeAsyncIO()) { cout << "[警告] 异步I/O初始化失败使用传统模式" << endl; } else { // 初始化工作线程池 if (!InitializeWorkerThreads()) { cout << "[警告] 工作线程池初始化失败使用传统模式" << endl; CleanupAsyncIO(); } } // 创建延迟Hook应用线程 HANDLE hook_thread = CreateThread(NULL, 0, [](LPVOID) -> DWORD { DelayedHookApplication(); return 0; }, NULL, 0, NULL); if (hook_thread) { cout << "[信息] 延迟Hook线程已启动" << endl; CloseHandle(hook_thread); // 不需要保持句柄 } else { cout << "[错误] 创建延迟Hook线程失败: " << GetLastError() << endl; // 直接应用Hook作为备选方案 cout << "[信息] 尝试直接应用Hook..." << endl; ApplyHookOptimized(); } // 创建优化版主线程 HANDLE hThread = CreateThread(NULL, 0, koreConnectionMainOptimized, NULL, 0, NULL); if (hThread) { cout << "[成功] xKore主线程已启动" << endl; CloseHandle(hThread); // 不需要保持句柄 } else { cout << "[错误] 创建主线程失败: " << GetLastError() << endl; keepMainThread.store(false, memory_order_release); } cout << "====================\n" << endl; } // 清理函数 void finishOptimized() { cout << "[信息] 开始清理资源..." << endl; keepMainThread.store(false, memory_order_release); // 等待线程退出 Sleep(100); // 清理工作线程池和异步I/O CleanupWorkerThreads(); CleanupAsyncIO(); // 关闭socket连接 SOCKET sock = koreClient.exchange(INVALID_SOCKET, memory_order_acq_rel); if (sock != INVALID_SOCKET) { shutdown(sock, SD_BOTH); closesocket(sock); } sock = roServer.exchange(INVALID_SOCKET, memory_order_acq_rel); if (sock != INVALID_SOCKET) { closesocket(sock); } // 移除hook if (original_recv) { RemoveHook(); } // 清理Winsock WSACleanup(); cout << "[信息] 资源清理完成" << endl; } // DLL主入口 BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: // 禁用线程通知以减少开销 DisableThreadLibraryCalls(hModule); initOptimized(); break; case DLL_PROCESS_DETACH: finishOptimized(); break; case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: break; } return TRUE; }针对 RO 的1 对 1 单 IP 连接、高频小封包场景,IOCP 的 “恰到好处” 核心是:聚焦 “单连接下的高频 IO 效率”,砍掉多连接场景的冗余设计,用最小的资源开销解决 “卡顿、丢包” 问题,避免为 “用而用” 的过度优化。具体需在 6 个关键环节做到精准控制,既保留 IOCP 的核心优势,又不引入不必要的复杂度: 一、完成端口(IOCP)初始化:极简配置,不浪费内核资源 单连接场景下,IOCP 无需配置多连接的 “高并发参数”,核心是 “轻量化创建 + 绑定单 Socket”,避免内核资源闲置: 并发线程数设为 1,而非 CPU 核心数CreateIoCompletionPort 的第 4 个参数(NumberOfConcurrentThreads)控制允许同时处理 IO 事件的线程数。多连接场景会设为 CPU 核心数(如 4 核设 4),但单连接下 IO 事件是 “串行触发”(同一时间仅 1 个小封包待处理),设为1即可 —— 多线程反而会导致 “线程切换开销”(比如 2 个线程抢 1 个 IO 事件,浪费 CPU)。文档中IOCPOptimizer::initialize()用了默认的0(等于 CPU 核心数),可优化为1,更贴合单连接: cpp 运行 iocp_handle = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1); // 最后一个参数设为1 仅关联 1 个目标 Socket,不做批量绑定单连接场景下,仅需将 RO 客户端与服务器Socket(或 xKore 代理的 Socket)关联到 IOCP,无需设计 “批量 Socket 绑定逻辑”(如循环绑定多个连接)。文档中associateSocket()单次绑定 1 个 Socket 的逻辑已适配,无需额外扩展。 二、线程池设计:1 个工作线程足够,拒绝 “多线程冗余” IOCP 的线程池是 “事件消费者”,单连接下高频小封包的 IO 事件是 “连续且串行” 的,1 个工作线程即可高效处理,多线程反而会引入 “锁竞争”(如抢读环形缓冲区),属于过度优化: 固定 1 个 IO 工作线程,不动态增减无需设计 “根据 IO 压力动态创建 / 销毁线程” 的逻辑(多连接场景才需要),直接创建 1 个常驻线程处理 IO 事件即可。比如文档中的highPerformancePacketProcessor线程,可固定为 1 个,无需用线程池库(如CreateThreadPool)—— 代码中SetThreadPriority设为THREAD_PRIORITY_ABOVE_NORMAL是合理的(保证 IO 处理优先级高于普通逻辑,避免小封包延迟),但无需多线程。 线程与 IO 事件 “一对一绑定”,避免线程切换单线程处理所有 IO 事件(读 / 写 / 错误),无需拆分 “读线程”“写线程”—— 拆分后会增加 “线程间通信开销”(如写线程通知读线程处理数据),反而降低效率。文档中 “1 个线程处理发送缓冲区 + Ping + 超时检测” 的逻辑已适配,无需修改。 三、IO 请求投递:预投递 + 小缓冲区,适配高频小封包 RO 的小封包(10~512 字节)若 “每次投递 1 个 IO 请求”,会导致系统调用(WSARecv/WSASend)频繁,反而增加开销。需用 “预投递 + 固定小缓冲区” 优化,平衡效率与资源: 预投递 1 个读请求,而非多次投递单连接下,Socket 接收缓冲区的小封包是 “连续到达” 的,可预先投递 1 个WSARecv请求(挂起等待数据),数据到达后处理完再投递下 1 个 —— 避免 “每收到 1 个小封包就投递 1 次请求” 的高频系统调用。示例逻辑: cpp 运行 // 预投递读请求(初始化时执行1次) OVERLAPPED ov; memset(&ov, 0, sizeof(ov)); char recv_buf[512]; // 适配RO小封包,不用8192字节大缓冲区 WSARecv(sock, &wsabuf, 1, NULL, &flags, &ov, NULL); // 处理完成事件后,再次投递下1个请求 while (keepRunning) { GetQueuedCompletionStatus(iocp_handle, &bytesTransferred, &key, &ov, INFINITE); processSmallPacket(recv_buf, bytesTransferred); // 处理小封包 WSARecv(sock, &wsabuf, 1, NULL, &flags, &ov, NULL); // 再次预投递 } 这里缓冲区设为512 字节(RO 小封包最大通常不超过 512),比文档中recv_buf[8192]更节省内存,且避免 “大缓冲区空闲浪费”。 写请求 “批量合并”,减少 WSASend 调用高频小封包发送时,若每次调用WSASend发送 1 个小封包(如 10 字节),系统调用开销占比极高。可结合文档中的环形缓冲区(sendBuffer) ,积累多个小封包(如累计到 1KB 或等待 1ms)后,一次性调用WSASend发送 —— 但需注意 “延迟平衡”(累计时间不超过 1ms,避免 RO 实时交互卡顿)。文档中 “有数据就发送” 的逻辑可微调:增加 “最小累计字节数”(如 128 字节),减少系统调用次数,又不影响延迟。 四、缓冲区与内存管理:贴合小封包,避免 “大缓冲冗余” RO 的小封包不需要大缓冲区,过度分配会导致内存浪费;同时需避免动态内存分配(高频小封包易引发内存碎片),文档中的内存池已适配,需进一步贴合场景: Socket 缓冲区设为 64KB,不盲目调大SO_SNDBUF/SO_RCVBUF 的大小需适配小封包:设为 64KB 足够(RO 每秒数百个小封包,总流量仅几十 KB),设为 128KB 或更大反而会增加 “缓冲区数据拷贝开销”(内核到用户态)。文档中send_buf_size = 64 * 1024的配置已恰到好处,无需修改。 内存池单包大小设为 512 字节,而非 8KB文档中MAX_PACKET_SIZE = 8192(8KB)过大,RO 小封包最大仅 512 字节,可改为512,减少内存池的内存占用(1024 个包仅 512KB,原 8KB 需 8MB)。同时避免 “大缓冲区拆分小封包” 的逻辑,简化内存池管理。 五、错误处理与降级:简单可靠,不做复杂容错 单连接场景下,IO 错误类型少(如连接断开、超时),无需设计 “复杂的错误重试逻辑”(如多连接的 “故障转移”),做到 “快速检测 + 优雅降级” 即可: 仅处理关键错误,避免冗余判断重点处理 3 类错误:WSAECONNRESET(连接被重置)、WSAETIMEDOUT(超时)、ERROR_NETNAME_DELETED(连接关闭),其他错误直接触发 “重连逻辑”(如文档中的koreClient.store(INVALID_SOCKET))。无需遍历所有 WSA 错误码,减少判断开销。 IOCP 初始化失败时,降级为 “简化异步 IO”若 IOCP 创建失败(如老旧系统不支持),无需崩溃,可降级为 “WSAEventSelect”(比 select 高效,比 IOCP 简单),而非直接用 select。文档中 “IOCP 关联失败仅警告” 的逻辑可优化为降级逻辑,保证兼容性,又不引入过度容错。 六、避免 “为 IOCP 而加的冗余特性” 单连接场景下,多连接 IOCP 的常见特性(如 “连接池”“负载均衡”“多完成端口拆分”)均无需实现,属于典型的过度优化: 不做 “连接池”:单连接无需缓存多个 Socket,直接创建 / 关闭即可; 不做 “多完成端口”:1 个完成端口足够处理单连接,多完成端口会增加内核调度开销; 不做 “IO 事件优先级”:单连接下所有小封包优先级相同(如移动、技能封包无先后),无需设计事件优先级队列。 总结:IOCP “恰到好处” 的核心原则 针对 RO 1 对 1 单连接、高频小封包场景,IOCP 的优化需围绕 “最小资源开销解决核心问题”: 资源上:1 个完成端口 + 1 个工作线程 + 64KB Socket 缓冲区 + 512 字节内存池,不浪费内存与 CPU; 逻辑上:预投递 1 个读请求 + 批量合并写请求 + 简单错误处理,不引入多线程、多完成端口等冗余设计; 目标上:仅解决 “select 轮询开销”“小封包延迟”“缓冲区溢出丢包” 三大问题,不追求 “多连接扩展性”“极致并发” 等无关特性。 这种设计既保留了 IOCP “异步无轮询” 的核心优势(从根源解决卡顿、丢包),又避免了过度优化带来的复杂度与资源浪费,完全适配 RO 的单连接高频小封包场景。
09-24
<think>好的,我现在需要帮助用户了解AcceptEx函数在Windows Socket中的作用和用法。首先,我要回顾用户提供的引用内容,找出关键信息。引用3提到AcceptEx是用于接受客户端连接的重叠I/O函数,它需要预先创建套接字作为参数,与传统的accept函数不同。引用5说明AcceptEx可以同时接收数据和连接,并且可以通过SO_CONNECT_TIME检查连接状态。 接下来,我应该整理AcceptEx的主要功能:异步处理连接、数据预读、多连接高效管理。然后,使用步骤方面,用户可能需要知道如何获取函数指针、准备套接字、调用函数以及处理完成通知。代码示例在引用1和2中有展示,我需要简化这些步骤,用中文解释清楚。 另外,要注意对比AcceptEx和accept的区别,强调异步的优势。用户可能关心性能优化,比如如何避免阻塞,所以需要提到重叠I/O和完成端口机制。同时,注意事项部分要包括错误处理和连接状态检查,引用5中的getsockopt用法很重要。 最后,生成相关问题,帮助用户深入理解,比如异步模型、数据预读机制、与完成端口的配合等。确保回答结构清晰,分点说明,并正确引用提供的资料。</think>### AcceptEx函数解析 #### 一、核心作用 AcceptEx是Windows Socket中支持**重叠I/O**的异步连接接受函数,主要实现: 1. **异步连接接受**:支持非阻塞方式接受新连接[^3] 2. **数据预读机制**:可在接受连接时预先接收客户端数据[^5] 3. **批量处理优化**:通过重叠I/O机制提升高并发下的连接处理效率[^3] #### 二、函数原型 ```cpp BOOL AcceptEx( SOCKET sListenSocket, SOCKET sAcceptSocket, PVOID lpOutputBuffer, DWORD dwReceiveDataLength, DWORD dwLocalAddressLength, DWORD dwRemoteAddressLength, LPDWORD lpdwBytesReceived, LPOVERLAPPED lpOverlapped ); ``` 参数说明: - `sListenSocket`:监听套接字 - `sAcceptSocket`:**预先创建**的接受套接字(需未绑定) - `lpOutputBuffer`:接收缓冲区(同时存储地址信息+数据) - `dwReceiveDataLength`:预读数据长度(0表示不预读) #### 三、使用步骤 1. **获取函数指针** ```cpp // 需要加载Mswsock.h[^2][^4] GUID GuidAcceptEx = WSAID_ACCEPTEX; WSAIoctl( listenSocket, SIO_GET_EXTENSION_FUNCTION_POINTER, &GuidAcceptEx, sizeof(GuidAcceptEx), &lpfnAcceptEx, sizeof(lpfnAcceptEx), &dwBytes, NULL, NULL );[^1] ``` 2. **创建接受套接字** ```cpp SOCKET acceptSocket = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED); ``` 3. **发起异步操作** ```cpp char buffer[1024]; // 包含地址信息+数据 DWORD bytesReceived; AcceptEx( listenSocket, acceptSocket, buffer, sizeof(buffer) - ((sizeof(sockaddr_in) + 16) * 2), // 地址信息保留空间 sizeof(sockaddr_in) + 16, sizeof(sockaddr_in) + 16, &bytesReceived, &overlapped ); ``` #### 四、关键特性对比 | 特性 | accept() | AcceptEx() | |-------------|-------------------|--------------------------| | 操作模式 | 同步 | 异步重叠I/O[^3] | | 套接字创建 | 自动生成新套接字 | 需预先创建套接字 | | 数据接收 | 仅建立连接 | 可同时接收首包数据[^5] | | 性能优化 | 基础处理 | 支持批量连接处理[^3] | #### 五、注意事项 1. 必须通过`SO_UPDATE_ACCEPT_CONTEXT`更新套接字属性: ```cpp setsockopt(acceptSocket, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, (char*)&listenSocket, sizeof(listenSocket)); ``` 2. 连接状态检测: ```cpp int seconds; getsockopt(acceptSocket, SOL_SOCKET, SO_CONNECT_TIME, (char*)&seconds, &bytes); if(seconds == 0xFFFFFFFF) // 连接未完成[^5] ``` 3. 错误处理应通过`WSAGetLastError()`获取详细错误码
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值