服务器(Windows镜像)自建git服务器超详细教程

45 阅读9分钟

IOCP模型C++服务端-接收客户端数据并响应客户端,同时管理所有客户端句柄

效果展示

效果图

源码展示

WSASend

  在连接上的socket上发送数据。

int WSAAPI WSASend(
    _In_ SOCKET s, 客户端句柄
    _In_reads_(dwBufferCount) LPWSABUF lpBuffers, 发送缓冲区
    _In_ DWORD dwBufferCount, 发送缓冲区的数量
    _Out_opt_ LPDWORD lpNumberOfBytesSent, (如果发送操作立即完成)指向发送字节数
    _In_ DWORD dwFlags, 标记位
    _Inout_opt_ LPWSAOVERLAPPED lpOverlapped, 重叠I/O结构
    _In_opt_ LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine 指向例程的指针
);

参数:

  • s,指向已连接的套接字(即客户端句柄)。
  • lpBuffers,一个指向WSABUF结构数组的指针(也可以是WASBUF结构指针)。每一个WSABUF结构包含一个缓冲区的指针和缓冲区的长度。
  • dwBufferCount,WSABUF结构数组中WSABUF结构的数量(如果lpBuffers为WSABUF结构指针,则该参数可以填1)。
  • lpNumberOfBytesSent,如果接受数据的操作立即结束,那么接收的数据字节长度会返回给lpNumberOfBytesSent指针所指向的对象。(如果lpOverlapped结构不是NULL,那么应该使用NULL来填充此参数,以避免潜在的错误结果。即只要lpOverlapped不为NULL,那么这个参数必须为NULL或0)。
  • dwFlags,用于更改WSASend函数的行为的标记。(即用来控制套接字的行为。例如,指出当前套接字是面向流(连接)的还是面向消息(无连接)的。通常设置为0。)
  • lpOverlapped,一个指向重叠I/O结构的指针。
  • lpCompletionRoutine,一个指向完成例程的指针。在发送操作完成后,会调用指针所指向的例程函数。在重叠I/O结构中该参数可设置为NULL。

shutdown

  shutdown函数禁止一个socket发送数据或者接收数据。

int WSAAPI shutdown(
    _In_ SOCKET s, 所要操作的句柄
    _In_ int how 描述socket不允许哪种操作类型
);

参数:

  • s,所要操作的句柄(文件描述符)。

  • how,描述socket不允许哪种操作类型,如下:

    含义
    SD_RECEIVE 0关闭接收操作
    SD_SEND 1关闭发送操作
    SD_BOTH 2关闭发送和接收操作

返回值:

  如果执行成功,则返回0。否则,返回套接字错误的值,并通过调用WSAGetLastError()函数来检测错误代码。

参考链接:https://blog.csdn.net/weixin_40179091/article/details/113669146

  因为socket是双向的,client和发server都可以进行input和output,但是有时候我们需要数据在socekt上进行单向传输,即数据往一个方向传输。单向的socket为半开放的socket。而要实现半开放式,需要用到shutdown()函数。

shutdown()和close()/closesocket()的区别

  在多进程的环境中,close()/closesocket()破坏当前的进程所引用的socket标识符,但是socket还是完好存在的,其它的进程还是可以照样使用(就像shared_ptr智能指针一样),当引用数降为0的时候,socket被释放销毁。

  shutdown()用来关闭连接,而不是套接字。不管调用多少次shutdown(),套接字依然存在,直到调用close()/closesocket()将套接字从内存中消除为止。而shutdown()的杀伤面积比较广,假设有一对父子进程共用一个socket,如果父进程对此socket的标识符进行shutdown(fd,SHUT_RD)操作,则此socket的所有引用操作符均无法接收数据,只能发送数据。

  调用close()/closesocket()关闭套接字时,或者调用shutdown()关闭输出流时,都会向对方发送FIN包(三握四挥中有提到)。FIN包表示数据传输完毕,对方收到FIN包就知道对方不会再有数据传输过来。

  默认情况下,close()/closesocket()会立即向网络中发送FIN包,不管输出缓冲区和接收缓冲区是否还有数据,而shutdown()会等输出缓冲区的数据传输完毕再发送FIN包。也就意味着,调用close()/closesocket()将丢失输出缓冲区和接收缓冲区的数据,而调用shutdown()则不会丢失。

shutdown函数应用场景

  因为shutdown()函数可以让socket实现单向传输,而半开放socket适用于以下场景:

  • 当你想要确保所有写好的数据已经发送成功时。如果在发送数据的过程中,网络出现断开或者异常,系统不一定会返回异常,这时候要怎么确定对端已经收到数据了呢?可以使用shutdown()函数来确定数据是否发送成功,因为调用shutdown()函数时只有在缓存中的数据全部发送成功后才返回。
  • 当不能往有些socket上写数据时,或者不能从有些socket上读数据时,可以使用shutdown()让其断开,后续对其进行读写的操作会返回异常。
  • 当多线程时,想防止其它线程或者进程访问该资源时,或者你想彻底关闭这个socket,让别的线程或者进程没法使用该socke可以调用shutdown()。

PostQueuedCompletionStatus

  发送一个I/O完成数据包到I/O完成端口中。

BOOL WINAPI PostQueuedCompletionStatus(
    _In_ HANDLE CompletionPort, I/O完成端口
    _In_ DWORD dwNumberOfBytesTransferred, 传输的字节数
    _In_ ULONG_PTR dwCompletionKey, I/O完成密钥
    _In_opt_ LPOVERLAPPED lpOverlapped 重叠I/O结构体
);

参数:

  • CompletionPort,I/O完成端口。
  • dwNumberOfBytesTransferred,通过lpNumberOfBytesTransferred字段返回的字节大小,即GetQueuedCompletionStatus函数返回中的lpNumberOfBytesTransferred字段。
  • dwCompletionKey,通过 lpCompletionKey 字段返回的I/O完成密钥,即GetQueuedCompletionStatus函数返回中的lpCompletionKey字段。
  • lpOverlapped,通过lpOverlapped 字段返回的I/O完成端口,即GetQueuedCompletionStatus函数返回中的lpOverlapped字段。

返回值:

  如果函数成功,则返回值为非0。

  如果函数失败,则返回值为0,如果想要获取额外的错误信息,可以使用GetLastError函数。

注意点:

  PostQueuedCompletionStatus函数可以向I/O完成端口发送一个特殊的数据包,用于通知在I/O完成端口中运行的文件描述符(句柄)。其中第一个参数务必是I/O完成端口对象,至于另外三个参数:dwNumberOfBytesTransferred,dwCompletionKey和lpOverlapped,我们可以自己指定其中的值。这样一来,正在工作的文件描述符(句柄)可以在收到对应的参数之后处理相应的事件。比如我们给dwNumberOfBytesTransferred参数设置为0,表示终止指令。一旦所有的正在工作的文件描述符(句柄)收到这条指令,那么我们就可以关闭相应的文件描述符(句柄)。

  即PostQueuedCompletionStatus函数提供了一种方式,用于跟I/O完成端口中的文件描述符(句柄)进行通信。

XNetCore.h

#ifndef _X_NET_CORE_H_
#define _X_NET_CORE_H_

//#define X_SELECT_NETCORE
#define X_IOCP_NETCORE

#include <functional>
namespace X {

	class ILoopEvent
	{
	public:

		virtual void Init() = 0;

		virtual void LoopOnce() = 0;

		virtual void UnInit() = 0;

		virtual ~ILoopEvent() {}

	};

	class ITcpSocketCB
	{
	public:
		virtual bool OnRecv(int len) = 0;

		virtual bool OnSend(int len) = 0;

		//客户端断开后的回调
		virtual void OnClose() = 0;

		virtual ~ITcpSocketCB() {}
	};


	class ITcpSocket
	{
	public:
		virtual void Init(ILoopEvent* loop, ITcpSocketCB* cb) = 0;

		virtual bool DoSend(const char* buff, int len) = 0;

		virtual bool DoRecv(char const* buff, int len) = 0;

		//主动关闭客户端
		virtual bool Close() = 0;

		virtual ~ITcpSocket() {}

	};


	typedef std::function<void(ITcpSocket*)> FTcpServerCB;

	class ITcpServer
	{
	public:
		//  和 循环事件关联
		/// <summary>
		/// 初始化TCP服务
		/// </summary>
		/// <param name="loop">循环事件</param>
		/// <param name="cb">当用户连接成功后 回调的函数</param>
		/// <returns></returns>
		virtual bool Init(ILoopEvent* loop, FTcpServerCB cb) = 0;

		virtual bool Listen(const char* ip, unsigned short port) = 0;

		virtual ~ITcpServer() {}


	};


	void InitNetCore();

	ILoopEvent* CreateLoopEvent();

	ITcpServer* CreateTcpServer();

}

#endif // !_X_NET_CORE_H_

IOCPLoopEvent.h

#include "XNetCore.h"

#ifdef X_IOCP_NETCORE
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <WinSock2.h>
#include <unordered_map>

#pragma comment(lib,"ws2_32")
#pragma comment(lib, "Mswsock")
#pragma comment(lib, "shlwapi")
#pragma comment(lib, "psapi")

#include <iostream>

#ifndef X_LOPEVENT_H_
#define X_LOPEVENT_H_

namespace X {
	struct sEvent
	{
		enum class Type
		{
			E_TCPSERVER,
			E_TCPSOCKET,
			PCK_ACCEPT_CLOSE,
			PCK_SOCKET_CLOSE,
			PCK_USER_DATA,	//用户投递的数据,调用DoPost让用户自己消耗
		};
		Type type;
		SOCKET sock;
		union
		{
			class TcpServer* tcpServer;
			class TcpSocket* tcpSocket;
			void* ptr;
		};
	};

	struct sReqHandle
	{
		OVERLAPPED	 overlapped;
		enum class sReqHandleE
		{
			HANDLE_ACCEPT = 0,
			HANDLE_RECV,
			HANDLE_SEND,
			HANDLE_CONNECT,
			HANDLE_RECVFROM,
			HANDLE_SENDTO,
		};
		sReqHandleE eType;//投递的类型
		void* ptr;
	};

	class LoopEvent :public ILoopEvent
	{
	private:
		std::unordered_map<SOCKET, sEvent*> _events;
		HANDLE _iocp;
	public:
		void Init() override;

		void LoopOnce() override;

		void UnInit() override;
	public:
		void AddEvent(sEvent* event);

		// 关联完成端口
		bool AssioIOCP(SOCKET sock, void* ptr);

		//消息处理
		void PostMsg(sEvent::Type eKey, void* pData);
	};

}

#endif // !_ILOOPEVENT_H_
#endif // !X_SELECT_NETCORE

IOCPLoopEvent.cpp

#include "IOCPLoopEvent.h"
#ifdef X_IOCP_NETCORE
#include "IOCPTcpServer.h"
#include "IOCPTcpSocket.h"

namespace X {
	void InitNetCore()
	{
		WSADATA wsaData;
		WSAStartup(MAKEWORD(2, 2), &wsaData);

		// TODO 添加异常导出库 程序崩溃生成崩溃信息

	}

	ILoopEvent* CreateLoopEvent()
	{

		return new LoopEvent();
	}
}


void X::LoopEvent::Init()
{
	_iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
	if (_iocp == INVALID_HANDLE_VALUE)
	{
		std::cout << "创建完成端口失败" << std::endl;
		return;
	}
	std::cout << "创建完成端口成功" << std::endl;


}

void X::LoopEvent::LoopOnce()
{

	DWORD lpNumberOfBytesTransferred;
	void* lpCompletionKey = nullptr;
	OVERLAPPED* lpOverlapped;
	DWORD dwMilliseconds;
	BOOL bRet = GetQueuedCompletionStatus(_iocp, &lpNumberOfBytesTransferred
		, (PULONG_PTR)&lpCompletionKey, &lpOverlapped, 0);

	if (!bRet && lpOverlapped)
	{
		return;
	}
	if (lpCompletionKey == nullptr) return;

	sEvent* event = (sEvent*)lpCompletionKey;

	switch (event->type)
	{
	case sEvent::Type::E_TCPSERVER:
		event->tcpServer->OnAccept();
		break;
	case sEvent::Type::E_TCPSOCKET:
		event->tcpSocket->OnNetMsg((sReqHandle*)lpOverlapped, bRet, lpNumberOfBytesTransferred);
		break;
	case sEvent::Type::PCK_SOCKET_CLOSE:
		event->tcpSocket->OnClose();
		break;
	default:
		break;

	}
}

void X::LoopEvent::UnInit()
{
}

void X::LoopEvent::AddEvent(sEvent* event)
{
	std::cout << "添加 事件" << event->sock
		<< " type:" << (int)event->type
		<< " ptr:" << event->tcpServer
		<< std::endl;
	_events.insert(std::pair<SOCKET, sEvent*>(event->sock, event));
}


bool X::LoopEvent::AssioIOCP(SOCKET sock, void* ptr)
{

	return _iocp == CreateIoCompletionPort((HANDLE)sock, _iocp, (ULONG_PTR)ptr, 0);
}


void X::LoopEvent::PostMsg(sEvent::Type eKey, void* pData)
{
	sEvent* event = new sEvent();
	event->type = eKey;
	event->ptr = pData;

	if (PostQueuedCompletionStatus(_iocp, 0, (ULONG_PTR)event, (LPOVERLAPPED)pData) != 0)
		std::cout << "消息发布成功" << std::endl;
}

#endif // !X_SELECT_NETCORE

IOCPTcpServer.h

#include "XNetCore.h"
#include "IOCPLoopEvent.h"

#ifdef X_IOCP_NETCORE

#ifndef X_TCP_SERVER_H_
#define X_TCP_SERVER_H_

namespace X {
	class TcpServer :public ITcpServer
	{
	private:
		LoopEvent* _loop;
		FTcpServerCB _cb;
		SOCKET _sock;
		sEvent _event;
		sReqHandle _handle;

		SOCKET	_socket;
		char _recvBuf[1024];
		DWORD _recvLen;
	public:
		bool Init(ILoopEvent* loop, FTcpServerCB cb) override;


		bool Listen(const char* ip, unsigned short port) override;

	public:
		TcpServer();
		void OnAccept();
	private:
		void PostAccept();

	};


}

#endif // !_ILOOPEVENT_H_
#endif // !X_SELECT_NETCORE

IOCPTcpServer.cpp

#include "IOCPTcpServer.h"
#ifdef X_IOCP_NETCORE
#include <ws2tcpip.h>
#include <mswsock.h>
#include "IOCPTcpSocket.h"

namespace X
{
	ITcpServer* CreateTcpServer()
	{
		return new TcpServer();
	}

}

bool X::TcpServer::Init(ILoopEvent* loop, FTcpServerCB cb)
{
	_loop = (LoopEvent*)loop;
	_cb = cb;

	std::cout << "初始化 TCPServer " << std::endl;

	return true;
}

bool X::TcpServer::Listen(const char* ip, unsigned short port)
{
	std::cout << "Listen IP:" << ip << " port:" << port << std::endl;

	// TODO 改行代码 以后完善 存在一些问题 
	if (_sock != INVALID_SOCKET)
		closesocket(_sock);

	//初始化socket
	_sock = INVALID_SOCKET;
	_sock = socket(AF_INET, SOCK_STREAM, 0);

	SOCKADDR_IN addr;
	addr.sin_family = AF_INET;
	addr.sin_port = htons(port);
	addr.sin_addr.s_addr = inet_addr(ip);
	if (SOCKET_ERROR == bind(_sock, (sockaddr*)&addr, sizeof(addr)))
		return false;

	if (SOCKET_ERROR == listen(_sock, 5))
		return false;

	_event.sock = _sock;
	if (_loop->AssioIOCP(_sock, &_event))
	{
		std::cout << "关联IOCP成功" << __FUNCTION__ << std::endl;
	}
	else
		std::cout << "关联IOCP失败" << __FUNCTION__ << std::endl;

	// 投递IOCP监听
	PostAccept();


	return true;

}

X::TcpServer::TcpServer()
{
	_loop = nullptr;
	_sock = INVALID_SOCKET;

	_event.tcpServer = this;
	_event.type = sEvent::Type::E_TCPSERVER;
	_event.sock = INVALID_SOCKET;

	_handle.eType = sReqHandle::sReqHandleE::HANDLE_ACCEPT;
	memset(&_handle.overlapped, 0, sizeof(_handle.overlapped));
}

void X::TcpServer::OnAccept()
{
	//SOCKADDR_IN addr;
	//int addrLen = sizeof(SOCKADDR_IN);
	//SOCKET sock = accept(_sock, (sockaddr*)&addr, &addrLen);

	//// 连接成功 调用回调函数
	//_cb(nullptr);
	sockaddr* paddr1 = NULL;
	sockaddr* paddr2 = NULL;
	int tmp1 = 0;
	int tmp2 = 0;
	GetAcceptExSockaddrs(_recvBuf, _recvLen, sizeof(SOCKADDR_IN) + 16
		, sizeof(SOCKADDR_IN) + 16, &paddr1, &tmp1, &paddr2, &tmp2);

	TcpSocket* tcp = new TcpSocket();
	tcp->OnAccept(_socket, paddr2);


	_cb(tcp);

	PostAccept();
}

void X::TcpServer::PostAccept()
{

	_socket = socket(AF_INET, SOCK_STREAM, 0);
	//WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
	if (_socket == INVALID_SOCKET)
	{

		return;
	}
	_recvLen = 0;
	if (FALSE == AcceptEx(_sock, _socket, _recvBuf, 0, sizeof(SOCKADDR_IN) + 16
		, sizeof(SOCKADDR_IN) + 16, &_recvLen, &_handle.overlapped))
	{
		if (WSAGetLastError() != ERROR_IO_PENDING)
		{
			std::cout << "ERROR " << __FUNCTION__ << std::endl;
			return;
		}
	}
	std::cout << "OK " << __FUNCTION__ << std::endl;

	return;
}

#endif // !X_SELECT_NETCORE

IOCPTcpSocket.h

#include "XNetCore.h"
#include "IOCPLoopEvent.h"

#ifdef X_IOCP_NETCORE

#ifndef X_TCP_SOCKET_H_
#define X_TCP_SOCKET_H_

namespace X {
	//记录客户端当前的状态
	enum class LINK_STATUS
	{
		LS_UNINITIALIZE = 0, // 无效状态
		LS_ESTABLISHED,  // 连接状态
		LS_WAITCLOSE,    // 等待关闭状态
		LS_WAITCLEAR,    // 等待清除状态
	};

	class TcpSocket :public ITcpSocket
	{
	private:
		LoopEvent* _loop;
		ITcpSocketCB* _cb;
		SOCKET _sock;

		sEvent _event;

		//发送缓冲区
		bool _bSend;
		WSABUF _sendWsaBuf;
		sReqHandle _sendHandle;

		//接收缓冲区
		bool _bRecv;
		WSABUF _recvWSABuf;
		sReqHandle _recvHandle;

		//当前状态
		LINK_STATUS _elinkStatus;
	public:
		TcpSocket();

		~TcpSocket();
	public:
		bool OnAccept(SOCKET sock, SOCKADDR* in);

		bool OnNetMsg(sReqHandle* handle, BOOL ret, int len);

		//关闭客户端
		bool OnClose();

		//准备关闭客户端
		bool DoClose();
	public:
		// 通过 ITcpSocket 继承
		virtual void Init(ILoopEvent* loop, ITcpSocketCB* cb) override;

		virtual bool DoSend(const char* buff, int len) override;

		virtual bool DoRecv(char const* buff, int len) override;

		//主动关闭客户端
		virtual bool Close() override;
	};
}

#endif // !_ILOOPEVENT_H_

#endif // !X_SELECT_NETCORE

IOCPTcpSocket.cpp

#include "IOCPTcpServer.h"
#ifdef X_IOCP_NETCORE
#include <ws2tcpip.h>
#include <mswsock.h>
#include "IOCPTcpSocket.h"

namespace X
{
	TcpSocket::TcpSocket()
	{

		_cb = nullptr;
		_loop = nullptr;
		_sock = INVALID_SOCKET;

		_bSend = false;
		_sendHandle.eType = sReqHandle::sReqHandleE::HANDLE_SEND;
		_sendHandle.ptr = this;
		memset(&_sendHandle.overlapped, 0, sizeof(_sendHandle.overlapped));

		_event.tcpSocket = this;
		_event.type = sEvent::Type::E_TCPSOCKET;

		_bRecv = false;
		_recvHandle.eType = sReqHandle::sReqHandleE::HANDLE_RECV;
		_recvHandle.ptr = this;
		memset(&_recvHandle.overlapped, 0, sizeof(_recvHandle.overlapped));

		_elinkStatus = LINK_STATUS::LS_UNINITIALIZE;
	}

	TcpSocket::~TcpSocket()
	{
		//std::cout << "释放客户端" << _sock << std::endl;
	}

	bool TcpSocket::Close()
	{
		return true;
	}

	bool TcpSocket::DoClose()
	{
		switch (_elinkStatus)
		{
		case X::LINK_STATUS::LS_UNINITIALIZE:
			break;
		case X::LINK_STATUS::LS_ESTABLISHED:
		{
			_elinkStatus = LINK_STATUS::LS_WAITCLOSE;
			shutdown(_sock, SD_BOTH);
			goto postClear;
			break;
		}
		case X::LINK_STATUS::LS_WAITCLOSE:
			goto postClear;
			break;
		case X::LINK_STATUS::LS_WAITCLEAR:
			break;
		}
	postClear:
		_elinkStatus = LINK_STATUS::LS_WAITCLEAR;
		if (_loop) //如果有IO服务则投递到IO服务中关闭
		{
			_loop->PostMsg(sEvent::Type::PCK_SOCKET_CLOSE, this);
		}
		else //没有服务则直接关闭
		{
			OnClose();
		}
		return true;
	}

	bool TcpSocket::OnClose()
	{
		closesocket(_sock);
		_sock = INVALID_SOCKET;
		if (_cb)
			_cb->OnClose();
		_elinkStatus = LINK_STATUS::LS_UNINITIALIZE;
		delete this;
		return true;
	}

	void TcpSocket::Init(ILoopEvent* loop, ITcpSocketCB* cb)
	{
		_loop = (LoopEvent*)loop;
		_cb = cb;

		_event.sock = _sock;
		_loop->AssioIOCP(_sock, &_event);
	}

	bool TcpSocket::OnAccept(SOCKET sock, SOCKADDR* in)
	{
		_sock = sock;
		_elinkStatus = LINK_STATUS::LS_ESTABLISHED;
		return true;
	}

	bool TcpSocket::OnNetMsg(sReqHandle* handle, BOOL ret, int len)
	{
		if (ret)
		{
			// TODO关闭
		}
		//if (len <= 0)
		//{
		//	// 断开连接
		//	return 0;
		//}

		switch (handle->eType)
		{
		case sReqHandle::sReqHandleE::HANDLE_RECV:
		{
			_bRecv = false;

			if (len <= 0)
			{
				// 断开连接
				DoClose();
				return 0;
			}

			_cb->OnRecv(len);
			break;
		}
		case sReqHandle::sReqHandleE::HANDLE_SEND:
		{
			_bSend = false;

			_cb->OnSend(len);
			break;
		}
		case sReqHandle::sReqHandleE::HANDLE_CONNECT:
			break;
		case sReqHandle::sReqHandleE::HANDLE_RECVFROM:
			break;
		case sReqHandle::sReqHandleE::HANDLE_SENDTO:
			break;
		default:
			break;
		}

		return true;
	}

	bool TcpSocket::DoSend(const char* buff, int len)
	{
		//TODO 判断一些错误

		if (_bSend) return false;

		_sendWsaBuf.buf = (CHAR*)buff;
		_sendWsaBuf.len = len;

		DWORD dwSend = 0;
		if (WSASend(_sock, &_sendWsaBuf, 1, &dwSend, 0, &_sendHandle.overlapped, NULL) != 0)
		{
			if (WSAGetLastError() != WSA_IO_PENDING)
			{

				return false;
			}
		}

		_bSend = true;
		return false;
	}

	bool TcpSocket::DoRecv(char const* buf, int len)
	{
		if (_bRecv) return false;

		// TODO判断一些失败条件

		_bRecv = true;

		_recvWSABuf.buf = (CHAR*)buf;
		_recvWSABuf.len = len;

		DWORD dwRecv = 0;
		DWORD dwFlag = 0;
		if (WSARecv(_sock, &_recvWSABuf, 1, &dwRecv, &dwFlag, &_recvHandle.overlapped, NULL) != 0)
		{
			if (WSAGetLastError() != WSA_IO_PENDING)
			{
				return false;
			}
		}

		return true;
	}
}

#endif // !X_SELECT_NETCORE

XServer.cpp

#include <iostream>
#include "XNetCore.h"


namespace {

	class TcpSocket : public X::ITcpSocketCB
	{
	public:
		char buff[1024]{ 0 };

		char sendBuf[1024];
		X::ITcpSocket* iTcpSocket;
	public:


		// 通过 ITcpSocketCB 继承
		virtual bool OnRecv(int len) override
		{
			std::cout << buff << std::endl;

			OnRecv();//重新投递


			return true;
		}

		void OnRecv()
		{
			iTcpSocket->DoRecv(buff, 1024);
		}


		void OnSend()
		{
			for (int i = 0; i < 1024; i++)
				sendBuf[i] = 'a';
			iTcpSocket->DoSend(sendBuf, 1024);
		}


		virtual bool OnSend(int len) override
		{

			return true;
		}

		virtual void OnClose() override
		{

			std::cout << "客户端断开(断开回调)" << std::endl;
		}

	};

}


int main()
{
	X::InitNetCore();

	X::ILoopEvent* loop = X::CreateLoopEvent();

	loop->Init();

	X::ITcpServer* server = X::CreateTcpServer();

	server->Init(loop, [loop](X::ITcpSocket* sock) {
		std::cout << "客户端连接成功1" << std::endl;
		TcpSocket* tcp = new TcpSocket();
		sock->Init(loop, tcp);

		tcp->iTcpSocket = sock;

		tcp->OnRecv();
		tcp->OnSend();
		});


	server->Listen("0.0.0.0", 7890);

	while (true)
	{
		loop->LoopOnce();
	}

	return 0;
}

服务端事件处理顺序示意图

效果图

IOCP模型C++服务端-接收客户端数据并响应客户端,同时管理所有客户端句柄_iocp shutdown 返回_ufgnix0802的博客-CSDN博客

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 19 天,  点击查看活动详情