socket_base
- 格式:ppt
- 大小:406.50 KB
- 文档页数:70


trinitycore魔兽服务器源码分析(⼆)⽹络书接上⽂继续分析Socket.h SocketMgr.htemplate<class T>class Socket : public std::enable_shared_from_this<T>根据智能指针的使⽤规则类中有使⽤本类⾃⼰的指针必须继承⾃enable_shared_from_this<> 防⽌⾃引⽤不能释放的BUGclass 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 it5 * under the terms of the GNU General Public License as published by the6 * Free Software Foundation; either version 2 of the License, or (at your7 * option) any later version.8 *9 * This program is distributed in the hope that it will be useful, but WITHOUT10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for12 * more details.13 *14 * You should have received a copy of the GNU General Public License along15 * with this program. If not, see </licenses/>.16*/1718 #ifndef __SOCKET_H__19#define __SOCKET_H__2021 #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>2930using boost::asio::ip::tcp;3132#define READ_BLOCK_SIZE 409633 #ifdef BOOST_ASIO_HAS_IOCP34#define TC_SOCKET_USE_IOCP35#endif3637 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 }4647virtual ~Socket()48 {49 _closed = true;50 boost::system::error_code error;51 _socket.close(error);52 }5354virtual void Start() = 0;5556virtual bool Update()57 {58if (_closed)59return false;6061 #ifndef TC_SOCKET_USE_IOCP62if (_isWritingAsync || (_writeQueue.empty() && !_closing))63return true;6465for (; HandleQueue();)66 ;67#endif6869return true;70 }7172 boost::asio::ip::address GetRemoteIpAddress() const73 {74return _remoteAddress;75 }7677 uint16 GetRemotePort() const78 {79return _remotePort;80 }8182void AsyncRead()83 {84if (!IsOpen())85return;8687 _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 }9293void AsyncReadWithCallback(void (T::*callback)(boost::system::error_code, std::size_t))94 {95if (!IsOpen())96return;9798 _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 }103104void QueuePacket(MessageBuffer&& buffer)105 {106 _writeQueue.push(std::move(buffer));107108 #ifdef TC_SOCKET_USE_IOCP109 AsyncProcessQueue();110#endif111 }112113bool IsOpen() const { return !_closed && !_closing; }114115void CloseSocket()116 {117if (_closed.exchange(true))118return;119120 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());125126 OnClose();127 }128129/// Marks the socket for closing after write buffer becomes empty130void DelayedCloseSocket() { _closing = true; }131132 MessageBuffer& GetReadBuffer() { return _readBuffer; }133134protected:135virtual void OnClose() { }136137virtual void ReadHandler() = 0;138139bool AsyncProcessQueue()140 {141if (_isWritingAsync)142return false;143144 _isWritingAsync = true;145146 #ifdef TC_SOCKET_USE_IOCP147 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#else151 _socket.async_write_some(boost::asio::null_buffers(), std::bind(&Socket<T>::WriteHandlerWrapper,152this->shared_from_this(), std::placeholders::_1, std::placeholders::_2));153#endif154155return false;156 }157158void 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 }166167private:168void ReadHandlerInternal(boost::system::error_code error, size_t transferredBytes)169 {170if (error)171 {172 CloseSocket();173return;174 }175176 _readBuffer.WriteCompleted(transferredBytes);177 ReadHandler();178 }179180 #ifdef TC_SOCKET_USE_IOCP181182void 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();190191if (!_writeQueue.empty())192 AsyncProcessQueue();193else if (_closing)194 CloseSocket();195 }196else197 CloseSocket();198 }199200#else201202void WriteHandlerWrapper(boost::system::error_code /*error*/, std::size_t /*transferedBytes*/)203 {204 _isWritingAsync = false;205 HandleQueue();206 }207208bool HandleQueue()209 {210if (_writeQueue.empty())211return false;212213 MessageBuffer& queuedMessage = _writeQueue.front();214215 std::size_t bytesToSend = queuedMessage.GetActiveSize();216217 boost::system::error_code error;218 std::size_t bytesSent = _socket.write_some(boost::asio::buffer(queuedMessage.GetReadPointer(), bytesToSend), error);219220if (error)221 {222if (error == boost::asio::error::would_block || error == boost::asio::error::try_again)223return AsyncProcessQueue();224225 _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 > 0238 {239 queuedMessage.ReadCompleted(bytesSent);240return AsyncProcessQueue();241 }242243 _writeQueue.pop();244if (_closing && _writeQueue.empty())245 CloseSocket();246return !_writeQueue.empty();247 }248249#endif250251 tcp::socket _socket;252253 boost::asio::ip::address _remoteAddress;254 uint16 _remotePort;255256 MessageBuffer _readBuffer;257 std::queue<MessageBuffer> _writeQueue;258259 std::atomic<bool> _closed;260 std::atomic<bool> _closing;261262bool _isWritingAsync;263 };264265#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 it5 * under the terms of the GNU General Public License as published by the6 * Free Software Foundation; either version 2 of the License, or (at your7 * option) any later version.8 *9 * This program is distributed in the hope that it will be useful, but WITHOUT10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for12 * more details.13 *14 * You should have received a copy of the GNU General Public License along15 * with this program. If not, see </licenses/>.16*/1718 #ifndef SocketMgr_h__19#define SocketMgr_h__2021 #include "AsyncAcceptor.h"22 #include "Errors.h"23 #include "NetworkThread.h"24 #include <boost/asio/ip/tcp.hpp>25 #include <memory>2627using boost::asio::ip::tcp;2829 template<class SocketType>30class SocketMgr31 {32public:33virtual ~SocketMgr()34 {35 ASSERT(!_threads && !_acceptor && !_threadCount, "StopNetwork must be called prior to SocketMgr destruction");36 }3738virtual bool StartNetwork(boost::asio::io_service& service, std::string const& bindIp, uint16 port, int threadCount)39 {40 ASSERT(threadCount > 0);4142 AsyncAcceptor* acceptor = nullptr;43try44 {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 }5253if (!acceptor->Bind())54 {55 TC_LOG_ERROR("network", "StartNetwork failed to bind socket acceptor");56return false;57 }5859 _acceptor = acceptor;60 _threadCount = threadCount;61 _threads = CreateThreads();6263 ASSERT(_threads);6465for (int32 i = 0; i < _threadCount; ++i)66 _threads[i].Start();6768return true;69 }7071virtual void StopNetwork()72 {73 _acceptor->Close();7475if (_threadCount != 0)76for (int32 i = 0; i < _threadCount; ++i)77 _threads[i].Stop();7879 Wait();8081 delete _acceptor;82 _acceptor = nullptr;83 delete[] _threads;84 _threads = nullptr;85 _threadCount = 0;86 }8788void Wait()89 {90if (_threadCount != 0)91for (int32 i = 0; i < _threadCount; ++i)92 _threads[i].Wait();93 }9495virtual void OnSocketOpen(tcp::socket&& sock, uint32 threadIndex)96 {97try98 {99 std::shared_ptr<SocketType> newSocket = std::make_shared<SocketType>(std::move(sock)); 100 newSocket->Start();101102 _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 }109110 int32 GetNetworkThreadCount() const { return _threadCount; }111112 uint32 SelectThreadWithMinConnections() const113 {114 uint32 min = 0;115116for (int32 i = 1; i < _threadCount; ++i)117if (_threads[i].GetConnectionCount() < _threads[min].GetConnectionCount())118 min = i;119120return min;121 }122123 std::pair<tcp::socket*, uint32> GetSocketForAccept()124 {125 uint32 threadIndex = SelectThreadWithMinConnections();126return std::make_pair(_threads[threadIndex].GetSocketForAccept(), threadIndex);127 }128129protected:130 SocketMgr() : _acceptor(nullptr), _threads(nullptr), _threadCount(0)131 {132 }133134virtual NetworkThread<SocketType>* CreateThreads() const = 0;135136 AsyncAcceptor* _acceptor;137 NetworkThread<SocketType>* _threads;138 int32 _threadCount;139 };140141#endif// SocketMgr_h__ View Code。
socket异常解决方案
《Socket异常解决方案》
在开发网络应用程序时,我们经常会遇到socket异常的问题。
socket异常可能会导致网络连接失败,数据传输中断,甚至导
致程序崩溃。
在面对这些问题时,我们需要及时解决并找出根本原因。
首先,我们需要了解造成socket异常的可能原因。
常见的原
因包括网络连接问题,服务器故障,数据包丢失等。
在了解了可能的原因后,就需要针对性地解决这些问题。
解决socket异常的方案可能包括以下几点:
1. 检查网络连接:确认网络连接是否正常,尝试其他网络环境,比如切换到4G网络或者使用VPN连接。
如果网络连接出现
问题,可能是导致socket异常的原因之一。
2. 重启服务器:如果是服务器端出现了问题,可以尝试重启服务器或者联系服务器管理员进行排查。
3. 检查数据包:数据包丢失可能会导致socket异常,对于这
种情况,我们可以使用数据包监控工具来检查数据传输情况,找出问题所在。
4. 异常处理:在程序中加入异常处理机制是很重要的,比如捕获socket异常并进行相应的处理,比如重新连接,重传数据
等。
5. 更新软件版本:有时socket异常可能是由于软件版本过低或者存在bug所致,及时更新软件版本可能解决这些问题。
总之,解决socket异常需要综合考虑网络环境、服务器端和客户端的问题,及时采取合理的措施来解决和避免出现异常情况。
希望上述的解决方案能帮助大家更好地解决socket异常的问题。
socket 协议Socket协议是一种计算机网络通信协议,它定义了网络中两个设备之间进行通信所使用的规则和格式。
它是一种面向连接的传输层协议,可在不同的网络环境下进行通信。
该协议的设计初衷是为了简化网络编程,使开发人员能够方便地进行网络通信。
Socket协议采用Client-Server模型,其中Client是请求方,Server是接收并响应请求的方。
一般情况下,Client发起连接请求,Server接受请求并进行处理。
在Socket协议中,通信的每一个终端都有一个唯一的标识符,称为Socket地址。
Socket 地址由IP地址和端口号组成,用于唯一标识一个进程在网络中的位置。
在Socket协议中,数据是以数据包的形式进行传输的。
数据包的格式由协议定义,其中包括了数据的源地址、目标地址等信息。
Socket协议定义了如何建立连接、如何传输数据以及如何关闭连接等操作。
它采用流式数据传输方式,可以按照顺序将数据分割成小的块进行传输,接收方可以按照顺序接收这些小块并重新组合成完整的数据。
Socket协议的运行过程通常包括以下几个步骤:首先,Client 创建一个Socket对象,并建立与Server的连接。
然后,Client 向Server发送请求,并等待Server的响应。
Server接收到请求后,进行处理并返回响应给Client。
Client接收到响应后,继续发送新的请求或关闭连接。
Socket协议具有以下特点:首先,它是一种简单易用的协议,开发人员只需要通过几个简单的API就可以实现网络通信。
其次,它具有高效性,可以快速传输大量数据。
再次,它是可靠的,保证了数据的完整性和有序性。
此外,由于Socket协议是面向连接的,因此在通信过程中可以保持双方的状态信息,使得通信更加灵活。
Socket协议在实际应用中有着广泛的应用,例如,在Web开发中,浏览器和服务器之间的通信就是通过Socket协议实现的。
socket函数的三个参数标题:socket函数的使用方法导语:在计算机网络中,socket函数是一种用于实现网络通信的编程接口。
它是网络应用程序与网络之间的通信端点,通过socket函数可以实现进程间的通信和数据传输。
本文将详细介绍socket函数的三个参数的使用方法,帮助读者理解并能够灵活应用socket函数。
一、参数一:domain(套接字的协议域)在socket函数中,参数domain指定了套接字的协议域。
协议域是一组协议的集合,它定义了套接字可以用于通信的协议类型。
常用的协议域包括AF_INET(IPv4协议)、AF_INET6(IPv6协议)、AF_UNIX(本地通信协议)等。
1. AF_INET(IPv4协议)在使用IPv4协议进行通信时,可以使用AF_INET作为套接字的协议域。
IPv4协议是当前广泛应用的网络协议,它使用32位地址来标识网络中的主机。
2. AF_INET6(IPv6协议)当需要使用IPv6协议进行通信时,可以选择AF_INET6作为套接字的协议域。
IPv6协议是IPv4协议的升级版,它使用128位地址来标识网络中的主机,解决了IPv4地址不足的问题。
3. AF_UNIX(本地通信协议)如果需要在同一台主机上的进程之间进行通信,可以选择AF_UNIX 作为套接字的协议域。
AF_UNIX提供了一种本地通信的方式,不需要通过网络传输数据。
二、参数二:type(套接字的类型)在socket函数中,参数type指定了套接字的类型。
套接字的类型决定了套接字的工作方式和特性。
常用的套接字类型包括SOCK_STREAM(流式套接字)和SOCK_DGRAM(数据报套接字)。
1. SOCK_STREAM(流式套接字)当需要建立可靠的、面向连接的通信时,可以选择SOCK_STREAM作为套接字的类型。
流式套接字提供了一种面向连接的、可靠的通信方式,数据按照顺序传输,不会丢失和重复。
2. SOCK_DGRAM(数据报套接字)如果需要进行无连接的、不可靠的通信,可以选择SOCK_DGRAM作为套接字的类型。