trinitycore 魔兽服务器源码分析(一) 网络
trinitycore是游戏服务器的开源代码 许多玩家使用魔兽的数据来进行测试 ,使用它来假设魔兽私服。
官方网址 https://www.trinitycore.org/
类似的还有mangos 和 kbengine 不过mangos使用庞大的ACE网络框架
kbengine使用自写网络库 两者均使用了多语言进行开发
作为trinitycore 主要使用c++。代码比较好读,就开启本篇这个代码阅读的坑
代码要求具备c++11的function shared_ptr 指针的相关知识
以及了解阅读过boost asio网络库的文档和示例代码的相关知识
先从网络看起
大致看了下 trinitycore使用boost asio作为网络库
大致就是这么几个代码
class AsyncAcceptor 顾名思义 是异步accept
构造函数 简单的初始化类中变量 无他
AsyncAcceptor(boost::asio::io_service& ioService, std::string const& bindIp, uint16 port) :
_acceptor(ioService), _endpoint(boost::asio::ip::address::from_string(bindIp), port),
_socket(ioService), _closed(false), _socketFactory(std::bind(&AsyncAcceptor::DefeaultSocketFactory, this))
{
}
void AsyncAcceptWithCallback() 函数
1 使用_socketFactory产生socket指针复制给类变量
tcp::socket* socket;
std::tie(socket, threadIndex) = _socketFactory();
2 将初始化时传入的函数指针AcceptCallback在ACCEPT时候调用
typedef void(*AcceptCallback)(tcp::socket&& newSocket, uint32 threadIndex);
acceptCallback(std::move(*socket), threadIndex);
并再次进入 AsyncAcceptWithCallback函数等待下次accept;
if (!_closed)
this->AsyncAcceptWithCallback<acceptCallback>();
bool Bind()函数将类中accpter与指定的协议绑定bind 并进行监听listen
template<class T>
void AsyncAcceptor::AsyncAccept()函数
不设置回调函数 而是将accept的socket转化为 类型T的指针 并调用T->start();
并且再次进入AsyncAccept()等待下次accept
/*
* Copyright (C) 2008-2017 TrinityCore <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/ #ifndef __ASYNCACCEPT_H_
#define __ASYNCACCEPT_H_ #include "Log.h"
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/ip/address.hpp>
#include <functional>
#include <atomic> using boost::asio::ip::tcp; class AsyncAcceptor
{
public:
typedef void(*AcceptCallback)(tcp::socket&& newSocket, uint32 threadIndex); AsyncAcceptor(boost::asio::io_service& ioService, std::string const& bindIp, uint16 port) :
_acceptor(ioService), _endpoint(boost::asio::ip::address::from_string(bindIp), port),
_socket(ioService), _closed(false), _socketFactory(std::bind(&AsyncAcceptor::DefeaultSocketFactory, this))
{
} template<class T>
void AsyncAccept(); template<AcceptCallback acceptCallback>
void AsyncAcceptWithCallback()
{
tcp::socket* socket;
uint32 threadIndex;
std::tie(socket, threadIndex) = _socketFactory();
_acceptor.async_accept(*socket, [this, socket, threadIndex](boost::system::error_code error)
{
if (!error)
{
try
{
socket->non_blocking(true); acceptCallback(std::move(*socket), threadIndex);
}
catch (boost::system::system_error const& err)
{
TC_LOG_INFO("network", "Failed to initialize client's socket %s", err.what());
}
} if (!_closed)
this->AsyncAcceptWithCallback<acceptCallback>();
});
} bool Bind()
{
boost::system::error_code errorCode;
_acceptor.open(_endpoint.protocol(), errorCode);
if (errorCode)
{
TC_LOG_INFO("network", "Failed to open acceptor %s", errorCode.message().c_str());
return false;
} _acceptor.bind(_endpoint, errorCode);
if (errorCode)
{
TC_LOG_INFO("network", "Could not bind to %s:%u %s", _endpoint.address().to_string().c_str(), _endpoint.port(), errorCode.message().c_str());
return false;
} _acceptor.listen(boost::asio::socket_base::max_connections, errorCode);
if (errorCode)
{
TC_LOG_INFO("network", "Failed to start listening on %s:%u %s", _endpoint.address().to_string().c_str(), _endpoint.port(), errorCode.message().c_str());
return false;
} return true;
} void Close()
{
if (_closed.exchange(true))
return; boost::system::error_code err;
_acceptor.close(err);
} void SetSocketFactory(std::function<std::pair<tcp::socket*, uint32>()> func) { _socketFactory = func; } private:
std::pair<tcp::socket*, uint32> DefeaultSocketFactory() { return std::make_pair(&_socket, ); } tcp::acceptor _acceptor;
tcp::endpoint _endpoint;
tcp::socket _socket;
std::atomic<bool> _closed;
std::function<std::pair<tcp::socket*, uint32>()> _socketFactory;
}; template<class T>
void AsyncAcceptor::AsyncAccept()
{
_acceptor.async_accept(_socket, [this](boost::system::error_code error)
{
if (!error)
{
try
{
// this-> is required here to fix an segmentation fault in gcc 4.7.2 - reason is lambdas in a templated class
std::make_shared<T>(std::move(this->_socket))->Start();
}
catch (boost::system::system_error const& err)
{
TC_LOG_INFO("network", "Failed to retrieve client's remote address %s", err.what());
}
} // lets slap some more this-> on this so we can fix this bug with gcc 4.7.2 throwing internals in yo face
if (!_closed)
this->AsyncAccept<T>();
});
} #endif /* __ASYNCACCEPT_H_ */
//============================================================================
template<class SocketType>
class NetworkThread
类使用多线程执行socket的管理
那么类的成员变量及作用如后
typedef std::vector<std::shared_ptr<SocketType>> SocketContainer; //socket容器进行socket指针的存储管理
std::atomic<int32> _connections; //原子计数 多线程下记录连接数目
std::atomic<bool> _stopped; //原子bool型flag 标记此线程是否停止
std::thread* _thread; //线程指针
SocketContainer _sockets; //socket容器进行socket指针的存储管理
std::mutex _newSocketsLock; //多线程互斥变量
SocketContainer _newSockets; //另一个socket容器
//boost 设置常规变量
boost::asio::io_service _io_service;
tcp::socket _acceptSocket;
boost::asio::deadline_timer _updateTimer;
从 void Run()函数入手
void Run()的功能如下
定时异步执行 Update函数 ,运行_io_service
_updateTimer.expires_from_now(boost::posix_time::milliseconds(10));
_updateTimer.async_wait(std::bind(&NetworkThread<SocketType>::Update, this));
_io_service.run();
void Update()函数
在加锁情况下 将_newSockets容器socket指针添加到_sockets ==》 AddNewSockets();
并移除那些update失败的socket==》_sockets.erase(。。。。。。
再次定时异步调用update
函数作用应该是定时清除无效socket 具体效果还需要在后继代码中看看 template<typename SocketType> 中SocketType的update函数的具体作用
整个类代码如下
/*
* Copyright (C) 2008-2017 TrinityCore <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/ #ifndef NetworkThread_h__
#define NetworkThread_h__ #include "Define.h"
#include "Errors.h"
#include "Log.h"
#include "Timer.h"
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/deadline_timer.hpp>
#include <atomic>
#include <chrono>
#include <memory>
#include <mutex>
#include <set>
#include <thread> using boost::asio::ip::tcp; template<class SocketType>
class NetworkThread
{
public:
NetworkThread() : _connections(), _stopped(false), _thread(nullptr),
_acceptSocket(_io_service), _updateTimer(_io_service)
{
} virtual ~NetworkThread()
{
Stop();
if (_thread)
{
Wait();
delete _thread;
}
} void Stop()
{
_stopped = true;
_io_service.stop();
} bool Start()
{
if (_thread)
return false; _thread = new std::thread(&NetworkThread::Run, this);
return true;
} void Wait()
{
ASSERT(_thread); _thread->join();
delete _thread;
_thread = nullptr;
} int32 GetConnectionCount() const
{
return _connections;
} virtual void AddSocket(std::shared_ptr<SocketType> sock)
{
std::lock_guard<std::mutex> lock(_newSocketsLock); ++_connections;
_newSockets.push_back(sock);
SocketAdded(sock);
} tcp::socket* GetSocketForAccept() { return &_acceptSocket; } protected:
virtual void SocketAdded(std::shared_ptr<SocketType> /*sock*/) { }
virtual void SocketRemoved(std::shared_ptr<SocketType> /*sock*/) { } void AddNewSockets()
{
std::lock_guard<std::mutex> lock(_newSocketsLock); if (_newSockets.empty())
return; for (std::shared_ptr<SocketType> sock : _newSockets)
{
if (!sock->IsOpen())
{
SocketRemoved(sock);
--_connections;
}
else
_sockets.push_back(sock);
} _newSockets.clear();
} void Run()
{
TC_LOG_DEBUG("misc", "Network Thread Starting"); _updateTimer.expires_from_now(boost::posix_time::milliseconds());
_updateTimer.async_wait(std::bind(&NetworkThread<SocketType>::Update, this));
_io_service.run(); TC_LOG_DEBUG("misc", "Network Thread exits");
_newSockets.clear();
_sockets.clear();
} void Update()
{
if (_stopped)
return; _updateTimer.expires_from_now(boost::posix_time::milliseconds());
_updateTimer.async_wait(std::bind(&NetworkThread<SocketType>::Update, this)); AddNewSockets(); _sockets.erase(std::remove_if(_sockets.begin(), _sockets.end(), [this](std::shared_ptr<SocketType> sock)
{
if (!sock->Update())
{
if (sock->IsOpen())
sock->CloseSocket(); this->SocketRemoved(sock); --this->_connections;
return true;
} return false;
}), _sockets.end());
} private:
typedef std::vector<std::shared_ptr<SocketType>> SocketContainer; std::atomic<int32> _connections;
std::atomic<bool> _stopped; std::thread* _thread; SocketContainer _sockets; std::mutex _newSocketsLock;
SocketContainer _newSockets; boost::asio::io_service _io_service;
tcp::socket _acceptSocket;
boost::asio::deadline_timer _updateTimer;
}; #endif // NetworkThread_h__
trinitycore 魔兽服务器源码分析(一) 网络的更多相关文章
- trinitycore 魔兽服务器源码分析(二) 网络
书接上文 继续分析Socket.h SocketMgr.h template<class T>class Socket : public std::enable_shared_from_t ...
- trinitycore 魔兽服务器源码分析(三) 多线程相关
先看LockedQueue.h template <class T, typename StorageType = std::deque<T> >class LockedQue ...
- tiny web服务器源码分析
tiny web服务器源码分析 正如csapp书中所记,在短短250行代码中,它结合了许多我们已经学习到的思想,如进程控制,unix I/O,套接字接口和HTTP.虽然它缺乏一个实际服务器所具备的功能 ...
- nginx源码分析之网络初始化
nginx作为一个高性能的HTTP服务器,网络的处理是其核心,了解网络的初始化有助于加深对nginx网络处理的了解,本文主要通过nginx的源代码来分析其网络初始化. 从配置文件中读取初始化信息 与网 ...
- Android8.1 MTK平台 SystemUI源码分析之 网络信号栏显示刷新
SystemUI系列文章 Android8.1 MTK平台 SystemUI源码分析之 Notification流程 Android8.1 MTK平台 SystemUI源码分析之 电池时钟刷新 And ...
- [1]传奇3服务器源码分析一 LoginGate
服务端下载地址: 点击这里 网上基本上都有分析该源码的分析详解,如:请点击该链接,但容易晕,而且也不全!所以才有了本文! 一.首先来看服务端的LoginGate源码 先来张图比较让人容易理解
- python之epoll服务器源码分析
#!/usr/bin/env python # -*- coding: utf8 -*- import socket, select EOL1 = b'/r/n' EOL2 = b'/r/n/r/n' ...
- [6]传奇3服务器源码分析一GameGate
1. 2. 留存 服务端下载地址: 点击这里
- [5]传奇3服务器源码分析一GameServer
1. 2. 留存 服务端下载地址: 点击这里
随机推荐
- 为嵌入式全志V3s荔枝派板卡添加USB MT7601U(小米随身WIFI)驱动
折腾了了一天终于scan出环境热点了,感觉本来挺简单的事情,网上教程一大把还费了一天的劲,很丧.不过网上教程虽多,但是还还是有些不同之处的,现在特意总结一下 全志V3s荔枝派板卡 添加该驱动的过程. ...
- kafuka资料学习
http://blog.csdn.net/hmsiwtv/article/details/46960053
- Consul之:服务注册与发现
一.服务的管理(注册与发现)有三种方式: 1:通过配置文件的方式静态注册2:通过HTTP API接口来动态注册(spring cloud使用方式,spring cloud中使用的是consul api ...
- time&datetime
关于time模块的代码部分 1 #_*_coding:utf-8_*_ 2 __author__ = 'Alex Li' 3 4 import time 5 6 7 # print(time.cloc ...
- OS&SYS&Shuti模块
#sys.argv 主要针对脚本可以读取参数 Shuti模块 import shutil f1=open('笔记',encoding='utf-8') f2=open('笔记2','w',enco ...
- windows异常事件对应的ID
转载地址: Windows 2008 R2查看异常关机或开机事件ID https://blog.csdn.net/hejun1218/article/details/81059327
- LSTM/RNN中的Attention机制
一.解决的问题 采用传统编码器-解码器结构的LSTM/RNN模型存在一个问题,不论输入长短都将其编码成一个固定长度的向量表示,这使模型对于长输入序列的学习效果很差(解码效果很差). 注意下图中,ax ...
- leetCode27.移除元素
给定一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,返回移除后数组的新长度. 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成 ...
- Mysql数据表去重
查询不重复元素个数 select count(distinct domain) from black_botnet_domian; 查询表中元素个数大于等于2的元素 SELECT goods_id,g ...
- CentOS开机自动运行自己的脚本详解
一.root权限编辑/etc/rc.d/rc.local su cd /etc/rc.d/ vi rc.local 二.在这个文件加上你要执行的脚本,全部内容如下: #!/bin/sh # # Thi ...