trinitycore魔兽服务器源码分析(二)网络

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

trinitycore魔兽服务器源码分析(⼆)⽹络
书接上⽂继续分析Socket.h SocketMgr.h
template<class T>
class Socket : public std::enable_shared_from_this<T>
根据智能指针的使⽤规则类中有使⽤本类⾃⼰的指针必须继承⾃enable_shared_from_this<> 防⽌⾃引⽤不能释放的BUG
class Socket封装了asio中的socket类获取远端ip 端⼝等功能,并且额外提供异步读写的功能
类中的两个原⼦变量 _closed _closing标记该socket的关闭开启状态
bool Update()函数根据socket是否是同步异步标记进⾏写⼊队列的处理。

同步则进⾏处理异步则暂缓
void AsyncRead() void AsyncReadWithCallback(void (T::*callback)(boost::system::error_code, std::size_t))
则采取异步读取socket 调⽤默认函数ReadHandlerInternal() 或者输⼊函数T::*callback()
由于AsyncReadWithCallback 函数中bind 需要 T类的指针所以才有开头的继承std::enable_shared_from_this<T>
但是使⽤⽐较怪异 std::enable_shared_from_this<>⽤法⼀般是继承⾃⼰本⾝
class self :: public std::enable_shared_from_this<self>{
public:
void test(){
// only for test
std::bind(&self ::test, shared_from_this());
}
}
异步写write类似 ,由bool AsyncProcessQueue()函数发起
使⽤asio的async_write_some函数异步读取连接内容并调⽤回调函数WriteHandler()或者WriteHandlerWrapper()
不过需要结合MessageBuffer ⼀起跟进流程
类代码如下
1/*
2 * Copyright (C) 2008-2017 TrinityCore </>
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see </licenses/>.
16*/
17
18 #ifndef __SOCKET_H__
19#define __SOCKET_H__
20
21 #include "MessageBuffer.h"
22 #include "Log.h"
23 #include <atomic>
24 #include <queue>
25 #include <memory>
26 #include <functional>
27 #include <type_traits>
28 #include <boost/asio/ip/tcp.hpp>
29
30using boost::asio::ip::tcp;
31
32#define READ_BLOCK_SIZE 4096
33 #ifdef BOOST_ASIO_HAS_IOCP
34#define TC_SOCKET_USE_IOCP
35#endif
36
37 template<class T>
38class Socket : public std::enable_shared_from_this<T>
39 {
40public:
41explicit Socket(tcp::socket&& socket) : _socket(std::move(socket)), _remoteAddress(_socket.remote_endpoint().address()),
42 _remotePort(_socket.remote_endpoint().port()), _readBuffer(), _closed(false), _closing(false), _isWritingAsync(false)
43 {
44 _readBuffer.Resize(READ_BLOCK_SIZE);
45 }
46
47virtual ~Socket()
48 {
49 _closed = true;
50 boost::system::error_code error;
51 _socket.close(error);
52 }
53
54virtual void Start() = 0;
55
56virtual bool Update()
57 {
58if (_closed)
59return false;
60
61 #ifndef TC_SOCKET_USE_IOCP
62if (_isWritingAsync || (_writeQueue.empty() && !_closing))
63return true;
64
65for (; HandleQueue();)
66 ;
67#endif
68
69return true;
70 }
71
72 boost::asio::ip::address GetRemoteIpAddress() const
73 {
74return _remoteAddress;
75 }
76
77 uint16 GetRemotePort() const
78 {
79return _remotePort;
80 }
81
82void AsyncRead()
83 {
84if (!IsOpen())
85return;
86
87 _readBuffer.Normalize();
88 _readBuffer.EnsureFreeSpace();
89 _socket.async_read_some(boost::asio::buffer(_readBuffer.GetWritePointer(), _readBuffer.GetRemainingSpace()),
90 std::bind(&Socket<T>::ReadHandlerInternal, this->shared_from_this(), std::placeholders::_1, std::placeholders::_2));
91 }
92
93void AsyncReadWithCallback(void (T::*callback)(boost::system::error_code, std::size_t))
94 {
95if (!IsOpen())
96return;
97
98 _readBuffer.Normalize();
99 _readBuffer.EnsureFreeSpace();
100 _socket.async_read_some(boost::asio::buffer(_readBuffer.GetWritePointer(), _readBuffer.GetRemainingSpace()),
101 std::bind(callback, this->shared_from_this(), std::placeholders::_1, std::placeholders::_2));
102 }
103
104void QueuePacket(MessageBuffer&& buffer)
105 {
106 _writeQueue.push(std::move(buffer));
107
108 #ifdef TC_SOCKET_USE_IOCP
109 AsyncProcessQueue();
110#endif
111 }
112
113bool IsOpen() const { return !_closed && !_closing; }
114
115void CloseSocket()
116 {
117if (_closed.exchange(true))
118return;
119
120 boost::system::error_code shutdownError;
121 _socket.shutdown(boost::asio::socket_base::shutdown_send, shutdownError);
122if (shutdownError)
123 TC_LOG_DEBUG("network", "Socket::CloseSocket: %s errored when shutting down socket: %i (%s)", GetRemoteIpAddress().to_string().c_str(), 124 shutdownError.value(), shutdownError.message().c_str());
125
126 OnClose();
127 }
128
129/// Marks the socket for closing after write buffer becomes empty
130void DelayedCloseSocket() { _closing = true; }
131
132 MessageBuffer& GetReadBuffer() { return _readBuffer; }
133
134protected:
135virtual void OnClose() { }
136
137virtual void ReadHandler() = 0;
138
139bool AsyncProcessQueue()
140 {
141if (_isWritingAsync)
142return false;
143
144 _isWritingAsync = true;
145
146 #ifdef TC_SOCKET_USE_IOCP
147 MessageBuffer& buffer = _writeQueue.front();
148 _socket.async_write_some(boost::asio::buffer(buffer.GetReadPointer(), buffer.GetActiveSize()), std::bind(&Socket<T>::WriteHandler,
149this->shared_from_this(), std::placeholders::_1, std::placeholders::_2));
150#else
151 _socket.async_write_some(boost::asio::null_buffers(), std::bind(&Socket<T>::WriteHandlerWrapper,
152this->shared_from_this(), std::placeholders::_1, std::placeholders::_2));
153#endif
154
155return false;
156 }
157
158void SetNoDelay(bool enable)
159 {
160 boost::system::error_code err;
161 _socket.set_option(tcp::no_delay(enable), err);
162if (err)
163 TC_LOG_DEBUG("network", "Socket::SetNoDelay: failed to set_option(boost::asio::ip::tcp::no_delay) for %s - %d (%s)",
164 GetRemoteIpAddress().to_string().c_str(), err.value(), err.message().c_str());
165 }
166
167private:
168void ReadHandlerInternal(boost::system::error_code error, size_t transferredBytes)
169 {
170if (error)
171 {
172 CloseSocket();
173return;
174 }
175
176 _readBuffer.WriteCompleted(transferredBytes);
177 ReadHandler();
178 }
179
180 #ifdef TC_SOCKET_USE_IOCP
181
182void WriteHandler(boost::system::error_code error, std::size_t transferedBytes)
183 {
184if (!error)
185 {
186 _isWritingAsync = false;
187 _writeQueue.front().ReadCompleted(transferedBytes);
188if (!_writeQueue.front().GetActiveSize())
189 _writeQueue.pop();
190
191if (!_writeQueue.empty())
192 AsyncProcessQueue();
193else if (_closing)
194 CloseSocket();
195 }
196else
197 CloseSocket();
198 }
199
200#else
201
202void WriteHandlerWrapper(boost::system::error_code /*error*/, std::size_t /*transferedBytes*/)
203 {
204 _isWritingAsync = false;
205 HandleQueue();
206 }
207
208bool HandleQueue()
209 {
210if (_writeQueue.empty())
211return false;
212
213 MessageBuffer& queuedMessage = _writeQueue.front();
214
215 std::size_t bytesToSend = queuedMessage.GetActiveSize();
216
217 boost::system::error_code error;
218 std::size_t bytesSent = _socket.write_some(boost::asio::buffer(queuedMessage.GetReadPointer(), bytesToSend), error);
219
220if (error)
221 {
222if (error == boost::asio::error::would_block || error == boost::asio::error::try_again)
223return AsyncProcessQueue();
224
225 _writeQueue.pop();
226if (_closing && _writeQueue.empty())
227 CloseSocket();
228return false;
229 }
230else if (bytesSent == 0)
231 {
232 _writeQueue.pop();
233if (_closing && _writeQueue.empty())
234 CloseSocket();
235return false;
236 }
237else if (bytesSent < bytesToSend) // now n > 0
238 {
239 queuedMessage.ReadCompleted(bytesSent);
240return AsyncProcessQueue();
241 }
242
243 _writeQueue.pop();
244if (_closing && _writeQueue.empty())
245 CloseSocket();
246return !_writeQueue.empty();
247 }
248
249#endif
250
251 tcp::socket _socket;
252
253 boost::asio::ip::address _remoteAddress;
254 uint16 _remotePort;
255
256 MessageBuffer _readBuffer;
257 std::queue<MessageBuffer> _writeQueue;
258
259 std::atomic<bool> _closed;
260 std::atomic<bool> _closing;
261
262bool _isWritingAsync;
263 };
264
265#endif// __SOCKET_H__
View Code
//======================================================
template<class SocketType>
class SocketMgr
将之前的Socket NetworkThread AsyncAcceptor
整合了起来
virtual bool StartNetwork(boost::asio::io_service& service, std::string const& bindIp, uint16 port, int threadCount)函数
开启threadCount个NetworkThread
创建⼀个AsyncAcceptor 异步ACCEPT连接
uint32 SelectThreadWithMinConnections() 函数会返回连接数⽬最少的NetworkThread 的线程索引
std::pair<tcp::socket*, uint32> GetSocketForAccept()则返回连接数⽬最少的线程索引和该线程⽤于异步连接Socket指针
其余的start stop 就没什么了
值得关注的是virtual void OnSocketOpen(tcp::socket&& sock, uint32 threadIndex)
当继承SocketMgr的服务器在accept的时候会调⽤该函数
函数功能是运⾏accept的Socket的run函数
并且讲Socket加⼊到NetworkThread 的Socket容器中(AddSocket函数)
整个类的代码如下
1/*
2 * Copyright (C) 2008-2017 TrinityCore </>
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see </licenses/>.
16*/
17
18 #ifndef SocketMgr_h__
19#define SocketMgr_h__
20
21 #include "AsyncAcceptor.h"
22 #include "Errors.h"
23 #include "NetworkThread.h"
24 #include <boost/asio/ip/tcp.hpp>
25 #include <memory>
26
27using boost::asio::ip::tcp;
28
29 template<class SocketType>
30class SocketMgr
31 {
32public:
33virtual ~SocketMgr()
34 {
35 ASSERT(!_threads && !_acceptor && !_threadCount, "StopNetwork must be called prior to SocketMgr destruction");
36 }
37
38virtual bool StartNetwork(boost::asio::io_service& service, std::string const& bindIp, uint16 port, int threadCount)
39 {
40 ASSERT(threadCount > 0);
41
42 AsyncAcceptor* acceptor = nullptr;
43try
44 {
45 acceptor = new AsyncAcceptor(service, bindIp, port);
46 }
47catch (boost::system::system_error const& err)
48 {
49 TC_LOG_ERROR("network", "Exception caught in SocketMgr.StartNetwork (%s:%u): %s", bindIp.c_str(), port, err.what());
50return false;
51 }
52
53if (!acceptor->Bind())
54 {
55 TC_LOG_ERROR("network", "StartNetwork failed to bind socket acceptor");
56return false;
57 }
58
59 _acceptor = acceptor;
60 _threadCount = threadCount;
61 _threads = CreateThreads();
62
63 ASSERT(_threads);
64
65for (int32 i = 0; i < _threadCount; ++i)
66 _threads[i].Start();
67
68return true;
69 }
70
71virtual void StopNetwork()
72 {
73 _acceptor->Close();
74
75if (_threadCount != 0)
76for (int32 i = 0; i < _threadCount; ++i)
77 _threads[i].Stop();
78
79 Wait();
80
81 delete _acceptor;
82 _acceptor = nullptr;
83 delete[] _threads;
84 _threads = nullptr;
85 _threadCount = 0;
86 }
87
88void Wait()
89 {
90if (_threadCount != 0)
91for (int32 i = 0; i < _threadCount; ++i)
92 _threads[i].Wait();
93 }
94
95virtual void OnSocketOpen(tcp::socket&& sock, uint32 threadIndex)
96 {
97try
98 {
99 std::shared_ptr<SocketType> newSocket = std::make_shared<SocketType>(std::move(sock)); 100 newSocket->Start();
101
102 _threads[threadIndex].AddSocket(newSocket);
103 }
104catch (boost::system::system_error const& err)
105 {
106 TC_LOG_WARN("network", "Failed to retrieve client's remote address %s", err.what());
107 }
108 }
109
110 int32 GetNetworkThreadCount() const { return _threadCount; }
111
112 uint32 SelectThreadWithMinConnections() const
113 {
114 uint32 min = 0;
115
116for (int32 i = 1; i < _threadCount; ++i)
117if (_threads[i].GetConnectionCount() < _threads[min].GetConnectionCount())
118 min = i;
119
120return min;
121 }
122
123 std::pair<tcp::socket*, uint32> GetSocketForAccept()
124 {
125 uint32 threadIndex = SelectThreadWithMinConnections();
126return std::make_pair(_threads[threadIndex].GetSocketForAccept(), threadIndex);
127 }
128
129protected:
130 SocketMgr() : _acceptor(nullptr), _threads(nullptr), _threadCount(0)
131 {
132 }
133
134virtual NetworkThread<SocketType>* CreateThreads() const = 0;
135
136 AsyncAcceptor* _acceptor;
137 NetworkThread<SocketType>* _threads;
138 int32 _threadCount;
139 };
140
141#endif// SocketMgr_h__ View Code。

相关文档
最新文档