栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

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

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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 

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 FTcpServerCB;


	//ITcpServer抽象类,服务端
	class ITcpServer
	{
	public:
		/// 
		/// 初始化TCP服务,与循环事件进行关联
		/// 
		/// 事件循环机制
		/// 当用户连接成功后的回调函数
		/// 
		virtual bool Init(IEventLoop* loop, FTcpServerCB cb) = 0;

		/// 
		/// 初始化socket
		/// 
		/// 服务端IP
		/// 监听端口号
		/// 错误返回false
		virtual bool Listen(const char* ip, int port) = 0;
	};

	//加载Windows网络库
	void InitNetCore();

	//卸载Windows网络库
	void UnNetCore();

	//实例化事件循环机制
	IEventLoop* CreateEventLoop();

	//实例化服务端类
	ITcpServer* CreateTcpServer();
}

#endif // !UNETCORE_H_

EventLoop.h
#include "UNetCore.h"

#ifdef U_SELECT_NETCORE
#include 
#include 
#include 
#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 _events;
	public:
		void Init() override;

		void LoopOnce() override;

		void UnInit() override;

		//添加监听的循环事件,压入sEvent单元
		void AddEvent(sEvent* event);
	};
}

#endif // !EVENTLOOP_H_
#endif // U_SELECT_NETCORE

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
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
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(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
UServer.cpp
#include "UNetCore.h"
#include 

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;
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/993768.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号