我是靠谱客的博主 英勇白猫,最近开发中收集的这篇文章主要介绍基于EventLoop的tcp服务端 C++实现(二) ——服务端TcpServer的模块设计描述,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

学习github上的项目 flamingo 自己的笔记。
flamingo原作者的csdn是: analogous_love
flamingo是多线程的,但是本人能力有限,只是单线程的还算能理解一点。

自己参照flamingo实现的基于epoll的单线程服务端,git地址:https://gitee.com/storm_zy/StServerFrame
实现了简单的echo功能,很多代码直接拷贝自flamingo。

一、如何设计TcpServer——功能上来说

  1. 一个TcpServer需要至少一个监听的端口(Listener)。
  2. 需要提供新连接到来时的处理方法,即将连接加入到自己的列表中进行维护等等。
  3. 需要维护自己的连接列表 TcpConnections。
  4. 需要处理过时失效的连接 。
  5. 提供对业务层的回调接口connectCallBack,以便将建立的TcpConnection告知上层的业务层。
  6. 业务层通过TcpConnetion来建立业务层的Session,然后实现业务的接入。

二、如何设计TcpServer——流程上来说

  1. 首先需要确定监听的端口和地址。
  2. 将新连接建立OnNewConnection(int fd)函数,用来设置到Listener对象的回调函数,在接收到新连接的时候可以接入到本TcpServer中。需要在 连接建立后调用 connectCallBack 接入到业务层。
  3. 新建立的连接添加到 connections列表中,进行维护。
  4. 需要有 start和stop函数,就是开始和结束函数,命名随意。
  5. 在start函数中,将Listener开启监听。
  6. 在stop函数中,将connections列表清理,并关闭Listener。

三、伪码实现

1 类设计

// 至于函数命名,因为是参考的 flamingo的代码,有的是直接拷贝的,有的是自己写的,所以有点乱。。。
class CListener;
class CTcpServer
{
public:
	typedef std::function<void(CTcpConnection *)> ConnectionCallBack;
	typedef std::function<void()> DailyResCleanCallBack;
	CTcpServer(CEventLoop *loop, const std::string& ip, st_port_t port);
	~CTcpServer();

public:
	void					start();
	void					stop();
	void					closeConnection(CTcpConnection *c);
	void					OnNewConnection(int fd); 
	void					OnConnectionClose(CTcpConnection *c);
	void					BindSession(CTcpSession *session, CTcpConnection *c);
	void					HandleDailyResCleanUp(CEventLoop *loop); // 处理需要关闭的连接等
private:
	bool					AddConnection(CTcpConnection *c);
	void					RemoveConnetion(CTcpConnection *c);
	void					CleanConnetions();
public:
	void					setConnectionCallBack(const ConnectionCallBack& cb) { connectionCallBack_ = cb; }
	void					setDailyCleanUpCallBack(const DailyResCleanCallBack& cb) { dailyResCleanUpCallBack_ = cb; }
private:
	ConnectionCallBack		connectionCallBack_;
	DailyResCleanCallBack	dailyResCleanUpCallBack_;
private:
	typedef std::map<int, CTcpConnection*> ConnectionMap;
	typedef std::vector<CTcpConnection *> ConnectionList;
	ConnectionMap			m_connections;
	ConnectionList			m_needDelConnections;
	CEventLoop				*m_loop;
	bool					m_stoped;
	CListener				*m_listener;
};

2 构造函数和析构函数

CTcpServer::CTcpServer(CEventLoop *loop, const std::string& ip, st_port_t port) : 
	m_loop(loop), m_listener(new CListener(loop, ip, port))
{
	m_listener->setNewConnectionCallBack(std::bind(&CTcpServer::OnNewConnection, this, std::placeholders::_1));
	m_loop->setRuntimeCallBack(std::bind(&CTcpServer::HandleDailyResCleanUp, this, std::placeholders::_1));
}

CTcpServer::~CTcpServer()
{
	this->CleanConnetions();
}

3 开始和停止

void CTcpServer::start()
{
	m_stoped = false;
	m_listener->StartListening();
}

void CTcpServer::stop()
{
	m_listener->Close();
	m_stoped = true;
	if (m_loop)
		m_loop->stop();
	this->CleanConnetions();
}

4 新连接建立回调函数,在Listener中调用

void CTcpServer::OnNewConnection(int fd)
{
	CTcpConnection *conn = new CTcpConnection(m_loop, fd);
	if (!AddConnection(conn)) {
		return;
	}
	在TcpConnection中处理关闭时会调用该回调。CTcpServer::OnConnectionClose就是要将关闭的连接添加到待删除连接列表。
	conn->setCloseCallBack(std::bind(&CTcpServer::OnConnectionClose, this, std::placeholders::_1));

	CSocket s(fd);
	s.SetNonBlock(true);

	conn->connectEstablished();
	if (connectionCallBack_)
		connectionCallBack_(conn);
}

5 业务层绑定回调函数,业务层的类需要集成 CTcpSession然后重写其读写函数。

将方法绑定到TcpConnection上之后,就会在 EventLoop中调用相应的方法,以此来实现回调。
void CTcpServer::BindSession(CTcpSession *session, CTcpConnection *c)
{
	c->setMessageCallBack(std::bind(&CTcpSession::OnRead, session, std::placeholders::_1, std::placeholders::_2));
	c->setWriteCompleteCallBack(std::bind(&CTcpSession::OnWriteComplete, session, std::placeholders::_1));
	c->addSession(session);
}

6 日常检查过时连接并清理

void CTcpServer::HandleDailyResCleanUp(CEventLoop *loop)
{
	if (dailyResCleanUpCallBack_)
		dailyResCleanUpCallBack_();

	size_t len = m_needDelConnections.size();
	if (len) {
		for (size_t i = 0; i < len; ++i)
		{
			CTcpConnection *c = m_needDelConnections.back();
			m_needDelConnections.pop_back();
			SAFE_DEL(c);
		}
	}
}

*以上只是伪码,示例大概怎样使用。


欢迎关注 [懒人漫说] 公众号,分享Java、Android、C/C++ 技术,包括基础、自己遇到的问题解决过程。
在这里插入图片描述
当然如果关注并留言问题的话,我们力所能及的话会帮你解决并回复哟。我们和你一样,是正在成长的程序员,我们也会分享自己的成长路上的感想,希望可以和你一起努力成长。

最后

以上就是英勇白猫为你收集整理的基于EventLoop的tcp服务端 C++实现(二) ——服务端TcpServer的模块设计描述的全部内容,希望文章能够帮你解决基于EventLoop的tcp服务端 C++实现(二) ——服务端TcpServer的模块设计描述所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(34)

评论列表共有 0 条评论

立即
投稿
返回
顶部