码迷,mamicode.com
首页 > 编程语言 > 详细

多线程游戏服务器开发(2)-编写网络库

时间:2016-07-22 19:31:39      阅读:218      评论:0      收藏:0      [点我收藏+]

标签:

网络库功能介绍

网络库具有的功能

1.具备多线程

2.监听某个端口

3.连接远程服务器

4.保存并管理所有链接,外部与网络库操作通过链接ID

5.向某个连接发送数据

6.强制关闭某个链接

7.网络事件回掉:connect, receive, close

8.错误处理


网络库主要接口(文件:tcp_frame.h)

	class tcp_frame
	{
	public:
		/**
		* tcp_frame 构造函数
		* @handler 网络事件回掉(connect, recevie, close)
		* @net_thread_num 网络线程数量
		* 注意:如果开启了多个网络线程,那么handler 回掉函数是非线程安全的。参见
		*	broker::on_net_message ,里面使用了加锁队列
		*/
		tcp_frame(const net_message_hander& handler, uint8_t net_thread_num = 1);
		~tcp_frame();

		/**
		* 监听某个端口
		* @listenAddress ip地址或者域名
		* @listenPort 端口
		*/
		void							listen(const std::string& ip, const std::string& port, module_id moduleid);

		/**
		* 连接某个端口
		* @ip ip地址或者域名
		* @port 端口
		* @moduleid 模块标识符,一般情况下网络库是作为某个模块的一部分 参考 broker的实现。
		*	网络事件会以消息(message)的形式,插入到模块的消息队列中.
		*/
		void							connect(const std::string& ip, const std::string& port, module_id moduleid);

		/**
		* 向某个链接发送数据
		* @sockid 连接标识
		* @data 数据
		*/
		void							send(socket_id sockid, const buffer_ptr& data);

		/**
		* 关闭一个链接
		* @sockid 连接标识
		* @state 给链接设置一个状态,表明为什么关闭(例如 超时,发送非法数据)
		*/
		void							close_socket(socket_id sockid, ESocketState state);

		/**
		* 启动网络库
		*/
		void							run();

		/**
		* 停止网络库
		*/
		void							stop();

		/**
		* 获取错误码
		*/
		int							getErrorCode();

		/**
		* 获取错误信息
		*/
		std::string					getErrorMessage();

		/**
		* 设置管理链接的超时检测
		* @timeout 超时时间 ,单位 ms
		* @checkInterval 超时检测间隔,单位 ms
		*/
		void							setTimeout(uint32_t timeout, uint32_t checkInterval);
	protected:
		/**
		* 投递异步accept,接受网络连接
		*/
		void							postAccept();

		/**
		* 超时检测线程函数
		*/
		void							checkTimeOut(uint32_t interval);
	protected:
		struct Imp;
		std::shared_ptr<Imp> _Imp;
		net_message_hander  _hander;
	};

网络库使用示例

1.EchoServer

服务器代码:
#pragma once
#include <common/noncopyable.hpp>
#include <tcp_frame.h>
#include <message.h>
#include <buffer_reader.h>
#include <string>
#include <iostream>
#include <functional>

using namespace moon;

class EchoServer :noncopyable
{
public:
	EchoServer()
	{

	}

	~EchoServer()
	{
		if (m_Net != nullptr)
		{
			//关闭网络线程
			m_Net->stop();
		}
	}

	void Start()
	{
		auto handler = std::bind(&EchoServer::OnNetMessage, this, std::placeholders::_1);
		m_Net = std::make_shared<tcp_frame>(handler,2);//2条网络线程

		//监听本机的 11111 端口,由于此处只是用网络库,不关心模块,模块ID为0 即可
		m_Net->listen("127.0.0.1", "11111", module_id::create(0));

		//启动网络线程
		m_Net->run();

		//正常情况下 应该阻塞主线程,防止主线程退出。由于稍后客户端会运行在主线程内,不再阻塞主线程
	}

private:
	void OnNetMessage(const message& msg)
	{
		switch (msg.get_type())
		{
		case EMessageType::SocketConnect:
		{
			//连接,消息内容默认为远程主机地址
			buffer_reader br(msg.data(), msg.size());
			std::string addr;
			br >> addr;
			std::cout <<"SERVER:client connect "<<addr<< std::endl;
			break;
		}
		case EMessageType::SocketData:
		{
			//收到数据,message 保存有发送者和接收者的ID.
			//如果是网络消息,那么发送者为网络连接ID

			//获取网络连接ID
			auto sockID = msg.get_socket_id();


			buffer_reader br(msg.data(), msg.size());
			//获取发来的信息
			std::string  clientMsg;
			br >> clientMsg;

			//把信息发送回去 (echoMsg是智能指针,方便多线程之间内存管理)
			auto echoMsg = buffer::create(clientMsg.size() + 1);
			(*echoMsg) << clientMsg;
			m_Net->send(sockID, echoMsg);


			std::cout << "SERVER:echo msg " << clientMsg << std::endl;
			break;
		}
		case EMessageType::SocketClose:
		{
			//断开
			buffer_reader br(msg.data(), msg.size());
			std::string addr;
			br >> addr;
			std::cout << "SERVER:client close " << addr << std::endl;
			break;
		}
		default:
			break;
		}
	}

private:
	std::shared_ptr<tcp_frame>   m_Net;
};


客户端代码:

#pragma once
#include <common/noncopyable.hpp>
#include <tcp_frame.h>
#include <message.h>
#include <buffer_reader.h>
#include <string>
#include <iostream>
#include <functional>

using namespace moon;

class EchoClient
{
public:

	void Start()
	{
		auto handler = std::bind(&EchoClient::OnNetMessage, this, std::placeholders::_1);
		m_Net = std::make_shared<tcp_frame>(handler, 1);//1条网络线程

		//连接本机的 11111 端口,由于此处只是用网络库,不关心模块,模块ID为0 即可
		auto id = m_Net->sync_connect("127.0.0.1", "11111", module_id::create(0));

		if (id.value == 0)
		{
			std::cout << "CLIENT : connect server failed" << std::endl;
			return;
		}

		//启动网络线程
		m_Net->run();

		std::string str;

		std::cin >> str;

		while (str != "exit")
		{
			std::cout << "CLIENT:send msg " <<str<< std::endl;
			auto msg = buffer::create(str.size() + 1);
			(*msg) << str;
			m_Net->send(id, msg);
			std::cin >> str;
		}

		m_Net->stop();
	}

private:
	void OnNetMessage(const message& msg)
	{
		switch (msg.get_type())
		{
		case EMessageType::SocketConnect:
		{
			buffer_reader br(msg.data(), msg.size());
			std::string addr;
			br >> addr;
			std::cout << "CLIENT:connect server:" << addr << std::endl;
			break;
		}
		case EMessageType::SocketData:
		{
			//获取网络连接ID
			auto sockID = msg.get_socket_id();
			buffer_reader br(msg.data(), msg.size());
			//获取发来的信息
			std::string  clientMsg;
			br >> clientMsg;
			std::cout << "CLIENT:recv msg " << clientMsg << std::endl;
			break;
			break;
		}
		case EMessageType::SocketClose:
		{
			//断开,消息内容默认为客户端地址
			buffer_reader br(msg.data(), msg.size());
			std::string addr;
			br >> addr;
			std::cout << "CLIENT:server close " << addr << std::endl;
			break;
		}
		default:
			break;
		}
	}

private:
	std::shared_ptr<tcp_frame>   m_Net;
};




使用示例

#include "EchoClient.hpp"
#include "EchoServer.hpp"

int main()
{
	EchoServer svr;
	svr.Start();

	EchoClient cl;
	cl.Start();

    return 0;
}


技术分享


示例地址:点击打开链接



多线程游戏服务器开发(2)-编写网络库

标签:

原文地址:http://blog.csdn.net/greatchina01/article/details/51982860

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!