TCP网络事件模型的封装1.0

TCP网络模型的封装

最近学习了TCP网络模型的封装,其中运用的封装技术个人感觉有点绕

在反复读代码、做思维导图下初步理解了这套封装模型,不禁感叹原来代码还能这样写?神奇!

为此将源码分享出来并将流程图画出,方便理解和复习

PS:下列思维导图仅代表个人理解,如有误恳请指出纠正

模型继承关系图

要理解该模型,我认为首先要画图理解类的继承关系,下面是我画的一个简单关系图
在这里插入图片描述

模型流程图

下面是我画的该模型的大致流程图,仅供参考,有误恳请指出
在这里插入图片描述

具体代码实现

EventLoop.hpp

#ifndef _EVENTLOOP_H_
#define _EVENTLOOP_H_

#include <list>
#include <WinSock2.h>

enum class E_Event_Type
{
	Recv,
	Send,
};

class IEventCallback
{
public:
	virtual void OnNetEvent(E_Event_Type e) = 0;
	virtual void OnClose() = 0;
};

struct sSelectEvent
{
	SOCKET sock;
	IEventCallback* event;
};

class EventLoop
{
private:
	std::list<sSelectEvent*> _events;
	std::list<sSelectEvent*> _delEventCaches;

public:
	void LoopOnce();

	void AddEvent(sSelectEvent* e)
	{
		_events.push_back(e);
	}

	void DelEvent(sSelectEvent* e);
};
#endif

EventLoop.cpp

#include "EventLoop.hpp"

void EventLoop::LoopOnce()
{

	fd_set reads;
	FD_ZERO(&reads);

	do
	{

		auto begin = _events.begin();
		auto end = _events.end();
		for (; begin != end; ++begin)
			FD_SET((*begin)->sock, &reads);
		//(*begin)->event->NeedWrite()
	} while (false);

	int nSeclect = select(0, &reads, nullptr, nullptr, nullptr);

	if (0 == nSeclect)return;

	if (nSeclect < 0)
		return;

	do
	{
		auto begin = _events.begin();
		auto end = _events.end();
		for (; begin != end; ++begin)
		{
			if (FD_ISSET((*begin)->sock, &reads))
			{
				(*begin)->event->OnNetEvent(E_Event_Type::Recv);
			}
		}
	} while (false);
	do
	{
		auto begin = _delEventCaches.begin();
		auto end = _delEventCaches.end();
		for (; begin != end; ++begin)
		{
			sSelectEvent* p = *begin;
			_events.remove_if([p](sSelectEvent* a)
				{
					return a == p;
				});
			p->event->OnClose();
		}
		_delEventCaches.clear();
	} while (false);

}

void EventLoop::DelEvent(sSelectEvent* e)
{
	_delEventCaches.push_back(e);
}

TcpListen.hpp

#ifndef _TCPLISTEN_H_
#define _TCPLISTEN_H_
#define _WINSOCK_DEPRECATED_NO_WARNINGS 

#include "EventLoop.hpp"
#include <WinSock2.h>
#include <iostream>
#include <functional>
class TcpSocket;
class TcpListen :public IEventCallback
{
protected:
	SOCKET _sock;
	sSelectEvent _event;
	EventLoop* _loop;
	std::function<TcpSocket* ()> _sockCB;
public:
	TcpListen();

	void Init(EventLoop* loop, std::function<TcpSocket* ()> sockCB)
	{
		_loop = loop; _sockCB = sockCB;
	}

	bool Listen(unsigned short port, const char* const ip = "0.0.0.0");

	// 通过 IEventCallback 继承
	virtual void OnNetEvent(E_Event_Type e) override;

	virtual void OnClose() override;
public:
	virtual void OnAccpet(TcpSocket* sock) = 0;

};
#endif

TcpListen.cpp

#include "TcpListen.h"
#include "TcpSocket.h"
TcpListen::TcpListen()
{
	_event.event = this;
	_sock = _event.sock = INVALID_SOCKET;
	_loop = nullptr;
}

bool TcpListen::Listen(unsigned short port, const char* const ip)
{

	_sock = socket(AF_INET, SOCK_STREAM, 0);

	if (INVALID_SOCKET == _sock)
	{
		std::cout << "create SOCKET fail!\n" << std::endl;
		return false;
	}
	std::cout << "1.create SOCKET OK!\n" << std::endl;

	// 2.绑定IP和端口
//  bind(SOCKET,绑定的IP端口结构体,结构体大小)
	SOCKADDR_IN serverAddr;
	serverAddr.sin_family = AF_INET;
	//SOCKADDR_IN6*

	serverAddr.sin_port = htons(port);
	// 127.0.0.1 本机回环地址
	// 0.0.0.0  绑定所有IP
	serverAddr.sin_addr.s_addr = inet_addr(ip);

	//SOCKADDR_IN6 serverAddr6;
	if (SOCKET_ERROR
		== bind(_sock, (SOCKADDR*)&serverAddr, sizeof(serverAddr)))
	{
		std::cout << "bind SOCKET fail!\n" << std::endl;
		return false;
	}
	std::cout << "2.bind SOCKET OK!\n" << std::endl;

	listen(_sock, 5);
	std::cout << "3.listen SOCKET OK!\n" << std::endl;

	_event.sock = _sock;
	_loop->AddEvent(&_event);

	return true;
}

void TcpListen::OnNetEvent(E_Event_Type e)
{
	SOCKADDR_IN clientAddr;
	int addrlen = sizeof(SOCKADDR_IN);
	SOCKET clientSock = accept(_sock, (SOCKADDR*)&clientAddr, &addrlen);

	if (INVALID_SOCKET == clientSock)
	{
		std::cout << "4.ACCEPT ERROR!!\n" << std::endl;
		return;
	}
	std::cout << "4.ACCEPT ip:" << inet_ntoa(clientAddr.sin_addr)
		<< "  Port:" << ntohs(clientAddr.sin_port) << "   " << clientSock
		<< std::endl;
	TcpSocket* sock = _sockCB();

	sock->OnAccept(clientSock, &clientAddr);

	OnAccpet(sock);

}

void TcpListen::OnClose()
{
}

TcpSocket.hpp

#ifndef _TCPSOCKET_H_
#define _TCPSOCKET_H_
#define _WINSOCK_DEPRECATED_NO_WARNINGS 

#include "EventLoop.hpp"

const unsigned int RECV_MAX_BUF = 4096 * 2;

class TcpSocket :public IEventCallback
{
private:
	SOCKET _sock;
	SOCKADDR_IN _addr;
	sSelectEvent _event;
	EventLoop* _loop;

	char _recvBuff[RECV_MAX_BUF];
	int _recvLen;

	bool _bClose;
public:
	TcpSocket();

	virtual ~TcpSocket();

	void Init(EventLoop* loop);

	void OnAccept(SOCKET sock, SOCKADDR_IN* addr);

	void Close();

public:
	// 通过 IEventCallback 继承
	virtual void OnNetEvent(E_Event_Type e) override;

	virtual void OnClose() override;

public:

	virtual int OnNetMsg(const char* const msg, int msgLen) = 0;

	void Send(const char* msg, int msgLen);

};

#endif

TcpSocket.cpp

#include "TcpSocket.h"

TcpSocket::TcpSocket()
{
	_sock = _event.sock = INVALID_SOCKET;
	_event.event = this;
	_recvLen = 0;
	_bClose = false;
}

TcpSocket::~TcpSocket()
{
}

void TcpSocket::Init(EventLoop* loop)
{
	_loop = loop;
	_loop->AddEvent(&_event);
}

void TcpSocket::OnAccept(SOCKET sock, SOCKADDR_IN* addr)
{
	_sock = sock;
	_event.sock = sock;
	memcpy(&_addr, addr, sizeof(addr));
}

void TcpSocket::Close()
{
	if (_bClose) return;

	_bClose = true;

	_loop->DelEvent(&_event);
}

void TcpSocket::OnNetEvent(E_Event_Type e)
{
	if (E_Event_Type::Recv == e)
	{
		int nRecv = recv(_sock, _recvBuff + _recvLen, RECV_MAX_BUF - _recvLen, 0);

		if (nRecv <= 0)
		{
			Close();
			return;
		}
		_recvLen += nRecv;


		while (_recvLen != 0)
		{
			int nRet = OnNetMsg(_recvBuff, _recvLen);
			if (nRet <= 0)break;
			_recvLen -= nRet;
			for (int i = 0; i < _recvLen; ++i)
			{
				_recvBuff[i] = _recvBuff[i + nRet];
			}
		}
		if (_recvLen == RECV_MAX_BUF) Close();

	}
}

void TcpSocket::OnClose()
{

	closesocket(_sock);
	delete this;
}

void TcpSocket::Send(const char* msg, int msgLen)
{
	send(_sock, msg, msgLen, 0);
}

EasyTcpServer.cpp

#define  _WINSOCK_DEPRECATED_NO_WARNINGS
#include <iostream>

#include <WinSock2.h>
#pragma comment(lib,"ws2_32")
#include <vector>


#include "TcpListen.h"
#include "TcpSocket.h"

class EasyTcpClient :public TcpSocket
{
public:
	// 通过 TcpSocket 继承
	virtual int OnNetMsg(const char* const msg, int msgLen) override
	{
		std::cout << msgLen << "接受客户端数据:" << msg << std::endl;

		return msgLen;
	}
};


class EasyTcpServer :public TcpListen
{
public:

	void OnAccpet(TcpSocket* sock) override
	{
		//sock->Init(_loop)
		sock->Init(_loop);
		std::cout << "客户端连接" << std::endl;
	}

};


int main()
{
	// 加载网络环境
	WSADATA wsaData;
	WSAStartup(MAKEWORD(2, 2), &wsaData);

	EventLoop loop;

	EasyTcpServer listen;

	listen.Init(&loop, []()->TcpSocket*
		{
			return new EasyTcpClient;
		});

	listen.Listen(7890);

	while (true)
	{
		loop.LoopOnce();
	}

	return 0;
}

最后

void OnAccpet(TcpSocket* sock) override
{
	//sock->Init(_loop)
	sock->Init(_loop);
	std::cout << "客户端连接" << std::endl;
}

};

int main()
{
// 加载网络环境
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);

EventLoop loop;

EasyTcpServer listen;

listen.Init(&loop, []()->TcpSocket*
	{
		return new EasyTcpClient;
	});

listen.Listen(7890);

while (true)
{
	loop.LoopOnce();
}

return 0;

}




# 最后

代码经供参考,如有疑问或者代码有问题欢迎提出
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值