• EventLoop框架C++服务端(Tcp/Ip)搭建


    EventLoop框架C++服务端(Tcp/Ip)搭建

    以下使用VS2022进行演示。

    更改编码格式

    在使用vs2022书写服务端的时候,最好将编码格式改为utf-8,下面介绍如果在vs2022中进行快速设置文件的编码格式。

      首先使用vs2022打开某个项目,点击工具=》自定义模块。

    效果图
    效果图

      紧接着选择:命令=》添加命令。

    效果图

    效果图

      滑动滚动条找到:文件=》高级保存选项=》确定。即可。

    效果图

      之后我们会发现我们vs2022编译器左上方会出现该窗口。

    效果图

      最后,我们点击该按钮,更改编码格式即可。

    效果图

    效果图

    EventLoop框架

    TIPS:这里暂时不过多的叙述EventLoop框架的概念,下面主要是实操代码。

    效果展示

    TIPS:客户端使用sokit工具进行演示。有两个服务端加入到事件循环机制中进行监听消息,端口号分别为7890和7891。功能仅仅只是客户端成功连接后响应相应的事件。

    效果图

    目录结构

    效果图
    效果图

    源码部分

    UNetCore.h

    #ifndef UNETCORE_H_
    #define UNETCORE_H_
    
    //表示当前IO内核使用的是select模型
    #define U_SELECT_NETCORE
    #define _WINSOCK_DEPRECATED_NO_WARNINGS
    #include <functional>
    
    namespace U
    {
    	//EventLoop抽象类,事件循环机制
    	class IEventLoop
    	{
    	public:
    		virtual void Init() = 0;
    
    		virtual void LoopOnce() = 0;
    
    		virtual void UnInit() = 0;
    	};
    
    	//用于管理连接上来的客户端
    	//TODO
    	class ITcpSocket
    	{
    		virtual void Init(IEventLoop* loop) = 0;
    	};
    
    	//响应客户端连接回调函数
    	typedef std::function<void(ITcpSocket*)> FTcpServerCB;
    
    
    	//ITcpServer抽象类,服务端
    	class ITcpServer
    	{
    	public:
    		/// <summary>
    		/// 初始化TCP服务,与循环事件进行关联
    		/// </summary>
    		/// <param name="loop">事件循环机制</param>
    		/// <param name="cb">当用户连接成功后的回调函数</param>
    		/// <returns></returns>
    		virtual bool Init(IEventLoop* loop, FTcpServerCB cb) = 0;
    
    		/// <summary>
    		/// 初始化socket
    		/// </summary>
    		/// <param name="ip">服务端IP</param>
    		/// <param name="port">监听端口号</param>
    		/// <returns>错误返回false</returns>
    		virtual bool Listen(const char* ip, int port) = 0;
    	};
    
    	//加载Windows网络库
    	void InitNetCore();
    
    	//卸载Windows网络库
    	void UnNetCore();
    
    	//实例化事件循环机制
    	IEventLoop* CreateEventLoop();
    
    	//实例化服务端类
    	ITcpServer* CreateTcpServer();
    }
    
    #endif // !UNETCORE_H_
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68

    EventLoop.h

    #include "UNetCore.h"
    
    #ifdef U_SELECT_NETCORE
    #include <WinSock2.h>
    #include <iostream>
    #include <unordered_map>
    #pragma comment(lib,"ws2_32")
    
    #ifndef EVENTLOOP_H_
    #define EVENTLOOP_H_
    
    
    namespace U
    {
    	//保存服务端单元的信息。即与服务端句柄关联,保存至事件循环机制中
    	class sEvent
    	{
    	public:
    		//该服务端是属于什么类型的(TCP、UDP、PIPE)
    		enum class Type
    		{
    			E_TCPSERVER,
    			//UDP,PIPE
    		};
    		Type type;
    		SOCKET sock;//保存服务端句柄
    		//由于sEvent类必须要附带服务端类,那么如果不使用联合体,会造成过度的内存资源浪费,即这里使用联合体保存各种类型服务端类的指针。
    		union
    		{
    			class TcpServer* tcpServer;
    			//class UcpServer* ucpServer;
    			//...
    		};
    	};
    
    
    	class EventLoop :public IEventLoop
    	{
    	private:
    		std::unordered_map<SOCKET, sEvent*> _events;
    	public:
    		void Init() override;
    
    		void LoopOnce() override;
    
    		void UnInit() override;
    
    		//添加监听的循环事件,压入sEvent单元
    		void AddEvent(sEvent* event);
    	};
    }
    
    #endif // !EVENTLOOP_H_
    #endif // U_SELECT_NETCORE
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    EventLoop.cpp

    #include "EventLoop.h"
    #include "TcpServer.h"
    
    #ifdef U_SELECT_NETCORE
    
    namespace U
    {
    	void InitNetCore()
    	{
    		WSADATA wsa;
    		WSAStartup(MAKEWORD(2, 2), &wsa);
    
    		//TODO 可以添加异常导出库,在程序崩溃生成崩溃信息
    	}
    
    	void UnNetCore()
    	{
    		WSACleanup();
    	}
    
    	IEventLoop* CreateEventLoop()
    	{
    		return new EventLoop;
    	}
    }
    
    void U::EventLoop::Init()
    {
    
    }
    
    //采用select IO模型
    void U::EventLoop::LoopOnce()
    {
    	FD_SET reads;
    	FD_ZERO(&reads);
    
    	for (auto& event : _events)
    		FD_SET(event.first, &reads);
    
    	int nRet = select(0, &reads, nullptr, nullptr, nullptr);
    	if (nRet <= 0)
    		return;
    
    	for (auto& event : _events)
    	{
    		SOCKET sock = event.first;
    		sEvent* pEvent = event.second;
    		if (FD_ISSET(sock, &reads))
    		{
    			switch (pEvent->type)
    			{
    			case U::sEvent::Type::E_TCPSERVER://处理TCP类的服务端
    			{
    				pEvent->tcpServer->OnAccept();
    				break;
    			}
    			default:
    				break;
    			}
    		}
    	}
    }
    
    void U::EventLoop::UnInit()
    {
    
    }
    
    void U::EventLoop::AddEvent(sEvent* event)
    {
    	std::cout << "添加 事件" << event->sock
    		<< " type:" << (int)event->type
    		<< " serverPtr:" << event->tcpServer
    		<< std::endl;
    	_events.insert(std::make_pair(event->sock, event));
    }
    
    #endif // U_SELECT_NETCORE
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79

    TcpServer.h

    #include "UNetCore.h"
    
    #ifdef U_SELECT_NETCORE
    #include "EventLoop.h"
    #ifndef TCPSERVER_H_
    #define TCPSERVER_H_
    
    namespace U
    {
    	class TcpServer :public ITcpServer
    	{
    	private:
    		EventLoop* _loop;//事件循环机制
    		FTcpServerCB _cb;//客户端连接回调事件
    		SOCKET _sock;//服务端socket
    		sEvent _event;//往事件循环机制注册消息的最小单元,即用于注册循环事件
    	public:
    		TcpServer();
    
    		~TcpServer();
    
    		bool Init(IEventLoop* loop, FTcpServerCB cb) override;
    
    		bool Listen(const char* ip, int port) override;
    
    	public:
    		//处理客户端连接
    		void OnAccept();
    	};
    }
    
    #endif // !TCPSERVER_H_
    #endif // U_SELECT_NETCORE
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    TcpServer.cpp

    #include "TcpServer.h"
    #ifdef U_SELECT_NETCORE
    
    namespace U
    {
    	ITcpServer* CreateTcpServer()
    	{
    		return new TcpServer;
    	}
    }
    
    U::TcpServer::TcpServer()
    {
    	std::cout << "初始化 TCPServer " << std::endl;
    
    	_loop = nullptr;
    	_cb = nullptr;
    	_sock = INVALID_SOCKET;
    
    	_event.tcpServer = this;
    	_event.type = U::sEvent::Type::E_TCPSERVER;
    	_event.sock = INVALID_SOCKET;
    }
    
    U::TcpServer::~TcpServer()
    {
    	_loop = nullptr;
    	_cb = nullptr;
    	if (INVALID_SOCKET != _sock)
    		closesocket(_sock);
    	_sock = INVALID_SOCKET;
    }
    
    bool U::TcpServer::Init(IEventLoop* loop, FTcpServerCB cb)
    {
    	_loop = dynamic_cast<EventLoop*>(loop);
    	_cb = cb;
    
    	return true;
    }
    
    bool U::TcpServer::Listen(const char* ip, int port)
    {
    	std::cout << "Listen IP:" << ip << " port:" << port << std::endl;
    
    	//TODO 待完善
    	if (_sock != INVALID_SOCKET)
    	{
    		closesocket(_sock);
    		return false;
    	}
    
    	_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;
    	_loop->AddEvent(&_event);
    	return true;
    }
    
    void U::TcpServer::OnAccept()
    {
    	//TODO 未处理客户端socket(句柄)
    	SOCKADDR_IN addr;
    	int addrLen = sizeof(SOCKADDR_IN);
    	SOCKET sock = accept(_sock, (sockaddr*)&addr, &addrLen);
    
    	//连接成功后调用回调函数
    	_cb(nullptr);
    }
    
    #endif // U_SELECT_NETCORE
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80

    UServer.cpp

    #include "UNetCore.h"
    #include <iostream>
    
    int main()
    {
    	//加载Windows网络库
    	U::InitNetCore();
    
    	//调用EventLoop循环机制
    	U::IEventLoop* loop = U::CreateEventLoop();
    	//开启两个服务端
    	U::ITcpServer* server = U::CreateTcpServer();
    	U::ITcpServer* server1 = U::CreateTcpServer();
    
    	//将服务端与事件循环机制loop关联
    	server->Init(loop, [](U::ITcpSocket* sock) {
    		std::cout << "客户端1连接" << std::endl;
    		});
    	server1->Init(loop, [](U::ITcpSocket* sock) {
    		std::cout << "客户端2连接" << std::endl;
    		});
    
    	server->Listen("0.0.0.0", 7890);
    	server1->Listen("0.0.0.0", 7891);
    
    	//启动循环机制监听消息
    	while (true)
    		loop->LoopOnce();
    
    	//卸载Windows网络库
    	U::UnNetCore();
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
  • 相关阅读:
    retrofit网络框架源码解析
    【EMQX】 Spring Cloud 集成MQTT并异步入库(mongodb)
    web前端期末大作业 html+css+javascript汽车介绍网页设计实例 企业网站制作(带报告3490字)
    洛谷P1090 [NOIP2004 提高组] 合并果子 / [USACO06NOV] Fence Repair G
    哈尔滨等保测评试题分享
    算法与数据结构【30天】集训营——图的遍历之深度优先搜索、广度优先搜索(28)
    《C程序设计》笔记(ch1-2)
    2023.10.18 信息学日志
    MFF论文笔记
    PDF转化为图片
  • 原文地址:https://blog.csdn.net/qq135595696/article/details/125475334