以下使用VS2022进行演示。
在使用vs2022书写服务端的时候,最好将编码格式改为utf-8,下面介绍如果在vs2022中进行快速设置文件的编码格式。
首先使用vs2022打开某个项目,点击工具=》自定义模块。


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


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

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

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


TIPS:这里暂时不过多的叙述EventLoop框架的概念,下面主要是实操代码。
TIPS:客户端使用sokit工具进行演示。有两个服务端加入到事件循环机制中进行监听消息,端口号分别为7890和7891。功能仅仅只是客户端成功连接后响应相应的事件。



#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_
#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
#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
#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
#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
#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;
}