├── IOCP - NewThreadPool ├── license.txt ├── TSingleton.h ├── Server │ ├── Packet.cpp │ ├── IOEvent.cpp │ ├── Packet.h │ ├── IOEvent.h │ ├── Client.h │ ├── Server.sln │ ├── Client.cpp │ ├── main.cpp │ ├── Server.h │ ├── Server.vcproj │ └── Server.cpp ├── Log.h ├── Network.h ├── Client │ ├── Client.sln │ ├── ClientMan.h │ ├── Client.h │ ├── main.cpp │ ├── ClientMan.cpp │ ├── Client.vcproj │ └── Client.cpp ├── IOCP.sln ├── Log.cpp └── Network.cpp ├── IOCP - OldThreadPool ├── license.txt ├── TSingleton.h ├── Server │ ├── Packet.cpp │ ├── IOEvent.cpp │ ├── Packet.h │ ├── Client.h │ ├── IOEvent.h │ ├── Client.cpp │ ├── Server.sln │ ├── main.cpp │ ├── Server.h │ ├── Server.vcproj │ └── Server.cpp ├── Log.h ├── Network.h ├── Client │ ├── ClientMan.h │ ├── Client.sln │ ├── Client.h │ ├── main.cpp │ ├── ClientMan.cpp │ ├── Client.vcproj │ └── Client.cpp ├── IOCP.sln ├── Log.cpp └── Network.cpp ├── README.txt └── .gitignore /IOCP - NewThreadPool/license.txt: -------------------------------------------------------------------------------- 1 | 2 | This work is licensed under the Creative Commons Attribution 2.0 Korea License. To view a copy of this license, visit http://creativecommons.org/licenses/by-nc/2.0/kr/ or send a letter to Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. 3 | -------------------------------------------------------------------------------- /IOCP - OldThreadPool/license.txt: -------------------------------------------------------------------------------- 1 | 2 | This work is licensed under the Creative Commons Attribution 2.0 Korea License. To view a copy of this license, visit http://creativecommons.org/licenses/by-nc/2.0/kr/ or send a letter to Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. 3 | -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | You need Boost lib for compling. Please set a correct path for Boost lib in 2 | [Project Properties] / [C/C++] / [General] / [Additional Include Directories] 3 | 4 | More deatils on this project are in my post. 5 | http://young2code.wordpress.com/2009/08/16/network-programming-with-iocp-and-thread-pool-intro/ 6 | http://young2code.wordpress.com/2010/05/30/iocp-with-the-original-or-old-thread-pool-api/ -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | #ignore thumbnails created by windows 3 | Thumbs.db 4 | #Ignore files build by Visual Studio 5 | *.obj 6 | *.exe 7 | *.pdb 8 | *.user 9 | *.aps 10 | *.pch 11 | *.vspscc 12 | *_i.c 13 | *_p.c 14 | *.ncb 15 | *.suo 16 | *.tlb 17 | *.tlh 18 | *.bak 19 | *.cache 20 | *.ilk 21 | *.log 22 | [Bb]in 23 | [Dd]ebug*/ 24 | *.lib 25 | *.sbr 26 | obj/ 27 | [Rr]elease*/ 28 | _ReSharper*/ 29 | [Tt]est[Rr]esult* -------------------------------------------------------------------------------- /IOCP - NewThreadPool/TSingleton.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | template class TSingleton 4 | { 5 | private: 6 | static T* m_Instance; 7 | 8 | public: 9 | static void New() 10 | { 11 | if( m_Instance == 0 ) 12 | { 13 | m_Instance = new T; 14 | } 15 | } 16 | 17 | 18 | static void Delete() 19 | { 20 | delete m_Instance; 21 | m_Instance = 0; 22 | } 23 | 24 | 25 | static T* Instance() 26 | { 27 | return m_Instance; 28 | } 29 | }; 30 | 31 | template T* TSingleton::m_Instance = 0; 32 | -------------------------------------------------------------------------------- /IOCP - OldThreadPool/TSingleton.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | template class TSingleton 4 | { 5 | private: 6 | static T* m_Instance; 7 | 8 | public: 9 | static void New() 10 | { 11 | if( m_Instance == 0 ) 12 | { 13 | m_Instance = new T; 14 | } 15 | } 16 | 17 | 18 | static void Delete() 19 | { 20 | delete m_Instance; 21 | m_Instance = 0; 22 | } 23 | 24 | 25 | static T* Instance() 26 | { 27 | return m_Instance; 28 | } 29 | }; 30 | 31 | template T* TSingleton::m_Instance = 0; 32 | -------------------------------------------------------------------------------- /IOCP - NewThreadPool/Server/Packet.cpp: -------------------------------------------------------------------------------- 1 | #include "Packet.h" 2 | 3 | #include 4 | 5 | typedef boost::singleton_pool PacketPool; 6 | 7 | /* static */ Packet* Packet::Create(Client* sender, const BYTE* buff, DWORD size) 8 | { 9 | Packet* packet = static_cast(PacketPool::malloc()); 10 | packet->m_Sender = sender; 11 | packet->m_Size = size; 12 | CopyMemory(packet->m_Data, buff, size); 13 | 14 | return packet; 15 | } 16 | 17 | /* static */ void Packet::Destroy(Packet* packet) 18 | { 19 | PacketPool::free(packet); 20 | } 21 | 22 | -------------------------------------------------------------------------------- /IOCP - OldThreadPool/Server/Packet.cpp: -------------------------------------------------------------------------------- 1 | #include "Packet.h" 2 | 3 | #include 4 | 5 | typedef boost::singleton_pool PacketPool; 6 | 7 | /* static */ Packet* Packet::Create(Client* sender, const BYTE* buff, DWORD size) 8 | { 9 | Packet* packet = static_cast(PacketPool::malloc()); 10 | packet->m_Sender = sender; 11 | packet->m_Size = size; 12 | CopyMemory(packet->m_Data, buff, size); 13 | 14 | return packet; 15 | } 16 | 17 | /* static */ void Packet::Destroy(Packet* packet) 18 | { 19 | PacketPool::free(packet); 20 | } 21 | 22 | -------------------------------------------------------------------------------- /IOCP - NewThreadPool/Log.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace Log 4 | { 5 | void Trace(const char * msg, ...); 6 | 7 | void Error(const char* fileName, const char* funcName, int line, const char* msg, ...); 8 | void Error(const char* fileName, const char* funcName, int line, int code, const char* msg, ...); 9 | 10 | void Setup(); 11 | void Cleanup(); 12 | 13 | void EnableTrace(bool enable); 14 | } 15 | 16 | #define TRACE(msg, ...) Log::Trace(msg, __VA_ARGS__); 17 | #define ERROR_MSG(msg, ...) Log::Error(__FILE__, __FUNCTION__, __LINE__, msg, __VA_ARGS__); 18 | #define ERROR_CODE(code, msg, ...) Log::Error(__FILE__, __FUNCTION__, __LINE__, code, msg, __VA_ARGS__); 19 | -------------------------------------------------------------------------------- /IOCP - OldThreadPool/Log.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace Log 4 | { 5 | void Trace(const char * msg, ...); 6 | 7 | void Error(const char* fileName, const char* funcName, int line, const char* msg, ...); 8 | void Error(const char* fileName, const char* funcName, int line, int code, const char* msg, ...); 9 | 10 | void Setup(); 11 | void Cleanup(); 12 | 13 | void EnableTrace(bool enable); 14 | } 15 | 16 | #define TRACE(msg, ...) Log::Trace(msg, __VA_ARGS__); 17 | #define ERROR_MSG(msg, ...) Log::Error(__FILE__, __FUNCTION__, __LINE__, msg, __VA_ARGS__); 18 | #define ERROR_CODE(code, msg, ...) Log::Error(__FILE__, __FUNCTION__, __LINE__, code, msg, __VA_ARGS__); 19 | -------------------------------------------------------------------------------- /IOCP - NewThreadPool/Server/IOEvent.cpp: -------------------------------------------------------------------------------- 1 | #include "IOEvent.h" 2 | #include "Client.h" 3 | #include "Packet.h" 4 | 5 | #include 6 | 7 | typedef boost::singleton_pool IOEventPool; 8 | 9 | /* static */ IOEvent* IOEvent::Create(Type type, Client* client, Packet* packet) 10 | { 11 | IOEvent* event = static_cast(IOEventPool::malloc()); 12 | 13 | ZeroMemory(event, sizeof(IOEvent)); 14 | event->m_Client = client; 15 | event->m_Type = type; 16 | event->m_Packet = packet; 17 | 18 | return event; 19 | } 20 | 21 | /* static */ void IOEvent::Destroy(IOEvent* event) 22 | { 23 | IOEventPool::free(event); 24 | } 25 | 26 | -------------------------------------------------------------------------------- /IOCP - OldThreadPool/Server/IOEvent.cpp: -------------------------------------------------------------------------------- 1 | #include "IOEvent.h" 2 | #include "Client.h" 3 | #include "Packet.h" 4 | 5 | #include 6 | 7 | typedef boost::singleton_pool IOEventPool; 8 | 9 | /* static */ IOEvent* IOEvent::Create(Type type, Client* client, Packet* packet) 10 | { 11 | IOEvent* event = static_cast(IOEventPool::malloc()); 12 | 13 | ZeroMemory(event, sizeof(IOEvent)); 14 | event->m_Client = client; 15 | event->m_Type = type; 16 | event->m_Packet = packet; 17 | 18 | return event; 19 | } 20 | 21 | /* static */ void IOEvent::Destroy(IOEvent* event) 22 | { 23 | IOEventPool::free(event); 24 | } 25 | 26 | -------------------------------------------------------------------------------- /IOCP - NewThreadPool/Network.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | struct addrinfo; 9 | 10 | namespace Network 11 | { 12 | bool Initialize(); 13 | void Deinitialize(); 14 | 15 | SOCKET CreateSocket(bool bind, u_short port); 16 | void CloseSocket(SOCKET socket); 17 | 18 | BOOL AcceptEx(SOCKET listenSocket, SOCKET newSocket, LPOVERLAPPED overlapped); 19 | BOOL ConnectEx(SOCKET socket, sockaddr* addr, int addrlen, LPOVERLAPPED overlapped); 20 | 21 | bool GetLocalAddress(SOCKET socket, std::string& ip, u_short& port); 22 | bool GetRemoteAddress(SOCKET socket, std::string& ip, u_short& port); 23 | }; 24 | -------------------------------------------------------------------------------- /IOCP - OldThreadPool/Network.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | struct addrinfo; 9 | 10 | namespace Network 11 | { 12 | bool Initialize(); 13 | void Deinitialize(); 14 | 15 | SOCKET CreateSocket(bool bind, u_short port); 16 | void CloseSocket(SOCKET socket); 17 | 18 | BOOL AcceptEx(SOCKET listenSocket, SOCKET newSocket, LPOVERLAPPED overlapped); 19 | BOOL ConnectEx(SOCKET socket, sockaddr* addr, int addrlen, LPOVERLAPPED overlapped); 20 | 21 | bool GetLocalAddress(SOCKET socket, std::string& ip, u_short& port); 22 | bool GetRemoteAddress(SOCKET socket, std::string& ip, u_short& port); 23 | }; 24 | -------------------------------------------------------------------------------- /IOCP - NewThreadPool/Server/Packet.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | class Client; 5 | class Packet 6 | { 7 | private: 8 | enum 9 | { 10 | MAX_BUFF_SIZE = 1024, 11 | }; 12 | 13 | public: 14 | static Packet* Create(Client* sender, const BYTE* buff, DWORD size); 15 | static void Destroy(Packet* packet); 16 | 17 | public: 18 | Client* GetSender() { return m_Sender; } 19 | DWORD GetSize() { return m_Size; } 20 | BYTE* GetData() { return m_Data; } 21 | 22 | private: 23 | Packet(); 24 | ~Packet(); 25 | Packet(const Packet& rhw); 26 | Packet& operator=(const Packet& input); 27 | 28 | private: 29 | Client* m_Sender; 30 | DWORD m_Size; 31 | BYTE m_Data[MAX_BUFF_SIZE]; 32 | }; 33 | -------------------------------------------------------------------------------- /IOCP - OldThreadPool/Server/Packet.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | class Client; 5 | class Packet 6 | { 7 | private: 8 | enum 9 | { 10 | MAX_BUFF_SIZE = 1024, 11 | }; 12 | 13 | public: 14 | static Packet* Create(Client* sender, const BYTE* buff, DWORD size); 15 | static void Destroy(Packet* packet); 16 | 17 | public: 18 | Client* GetSender() { return m_Sender; } 19 | DWORD GetSize() { return m_Size; } 20 | BYTE* GetData() { return m_Data; } 21 | 22 | private: 23 | Packet(); 24 | ~Packet(); 25 | Packet(const Packet& rhw); 26 | Packet& operator=(const Packet& input); 27 | 28 | private: 29 | Client* m_Sender; 30 | DWORD m_Size; 31 | BYTE m_Data[MAX_BUFF_SIZE]; 32 | }; 33 | -------------------------------------------------------------------------------- /IOCP - OldThreadPool/Server/Client.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | class Client 6 | { 7 | public: 8 | enum 9 | { 10 | MAX_RECV_BUFFER = 1024, 11 | }; 12 | 13 | enum State 14 | { 15 | WAIT, 16 | ACCEPTED, 17 | DISCONNECTED, 18 | }; 19 | 20 | public: 21 | static Client* Create(); 22 | static void Destroy(Client* client); 23 | 24 | public: 25 | void SetState(State state) { m_State = state; } 26 | State GetState() { return m_State; } 27 | 28 | SOCKET GetSocket() { return m_Socket; } 29 | BYTE* GetRecvBuff() { return m_recvBuffer; } 30 | 31 | private: 32 | Client(void); 33 | ~Client(void); 34 | Client& operator=(Client& rhs); 35 | Client(const Client& rhs); 36 | 37 | private: 38 | State m_State; 39 | SOCKET m_Socket; 40 | BYTE m_recvBuffer[MAX_RECV_BUFFER]; 41 | }; 42 | -------------------------------------------------------------------------------- /IOCP - NewThreadPool/Server/IOEvent.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | class Client; 5 | class Packet; 6 | 7 | class IOEvent 8 | { 9 | public: 10 | enum Type 11 | { 12 | ACCEPT, 13 | RECV, 14 | SEND, 15 | }; 16 | 17 | public: 18 | static IOEvent* Create(Type type, Client* client, Packet* packet = NULL); 19 | static void Destroy(IOEvent* event); 20 | 21 | public: 22 | Type GetType() { return m_Type; } 23 | Client* GetClient() { return m_Client; } 24 | Packet* GetPacket() { return m_Packet; } 25 | OVERLAPPED& GetOverlapped() { return m_Overlapped; } 26 | 27 | private: 28 | IOEvent(); 29 | ~IOEvent(); 30 | IOEvent& operator=(IOEvent& rhs); 31 | IOEvent(const IOEvent& rhs); 32 | 33 | private: 34 | OVERLAPPED m_Overlapped; 35 | Client* m_Client; 36 | Packet* m_Packet; // only for sending. 37 | Type m_Type; 38 | }; -------------------------------------------------------------------------------- /IOCP - OldThreadPool/Server/IOEvent.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | class Client; 5 | class Packet; 6 | 7 | class IOEvent 8 | { 9 | public: 10 | enum Type 11 | { 12 | ACCEPT, 13 | RECV, 14 | SEND, 15 | }; 16 | 17 | public: 18 | static IOEvent* Create(Type type, Client* client, Packet* packet = NULL); 19 | static void Destroy(IOEvent* event); 20 | 21 | public: 22 | Type GetType() { return m_Type; } 23 | Client* GetClient() { return m_Client; } 24 | Packet* GetPacket() { return m_Packet; } 25 | OVERLAPPED& GetOverlapped() { return m_Overlapped; } 26 | 27 | private: 28 | IOEvent(); 29 | ~IOEvent(); 30 | IOEvent& operator=(IOEvent& rhs); 31 | IOEvent(const IOEvent& rhs); 32 | 33 | private: 34 | OVERLAPPED m_Overlapped; 35 | Client* m_Client; 36 | Packet* m_Packet; // only for sending. 37 | Type m_Type; 38 | }; -------------------------------------------------------------------------------- /IOCP - OldThreadPool/Server/Client.cpp: -------------------------------------------------------------------------------- 1 | #include "Client.h" 2 | #include "..\Log.h" 3 | #include "..\Network.h" 4 | 5 | #include 6 | 7 | // use thread-safe memory pool 8 | typedef boost::singleton_pool ClientPool; 9 | 10 | /* static */ Client* Client::Create() 11 | { 12 | Client* client = static_cast(ClientPool::malloc()); 13 | client->m_State = WAIT; 14 | 15 | client->m_Socket = Network::CreateSocket(false, 0); 16 | if(client->m_Socket == INVALID_SOCKET) 17 | { 18 | ERROR_MSG("Could not create socket."); 19 | ClientPool::free(client); 20 | return NULL; 21 | } 22 | return client; 23 | } 24 | 25 | 26 | /* static */ void Client::Destroy(Client* client) 27 | { 28 | if( client->m_Socket != INVALID_SOCKET ) 29 | { 30 | Network::CloseSocket(client->m_Socket); 31 | } 32 | ClientPool::free(client); 33 | } -------------------------------------------------------------------------------- /IOCP - NewThreadPool/Server/Client.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | class Client 6 | { 7 | public: 8 | enum 9 | { 10 | MAX_RECV_BUFFER = 1024, 11 | }; 12 | 13 | enum State 14 | { 15 | WAIT, 16 | ACCEPTED, 17 | DISCONNECTED, 18 | }; 19 | 20 | public: 21 | static Client* Create(); 22 | static void Destroy(Client* client); 23 | 24 | public: 25 | void SetTPIO(TP_IO* pTPIO) { m_pTPIO = pTPIO; } 26 | TP_IO* GetTPIO() { return m_pTPIO; } 27 | 28 | void SetState(State state) { m_State = state; } 29 | State GetState() { return m_State; } 30 | 31 | SOCKET GetSocket() { return m_Socket; } 32 | BYTE* GetRecvBuff() { return m_recvBuffer; } 33 | 34 | private: 35 | Client(void); 36 | ~Client(void); 37 | Client& operator=(Client& rhs); 38 | Client(const Client& rhs); 39 | 40 | private: 41 | TP_IO* m_pTPIO; 42 | State m_State; 43 | SOCKET m_Socket; 44 | BYTE m_recvBuffer[MAX_RECV_BUFFER]; 45 | }; 46 | -------------------------------------------------------------------------------- /IOCP - OldThreadPool/Client/ClientMan.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "..\TSingleton.h" 8 | 9 | class Client; 10 | 11 | using namespace std; 12 | 13 | class ClientMan : public TSingleton 14 | { 15 | public: 16 | ClientMan(void); 17 | virtual ~ClientMan(void); 18 | 19 | void AddClients(short& port, int numClients); 20 | void ConnectClients(const char* ip, u_short port); 21 | void ShutdownClients(); 22 | void RemoveClients(); 23 | void Send(const string& msg); 24 | void RemoveClient(const Client* client); 25 | 26 | bool IsAlive(const Client* client); 27 | size_t GetNumClients(); 28 | 29 | private: 30 | typedef vector ClientList; 31 | ClientList m_listClient; 32 | 33 | typedef boost::object_pool PoolTypeClient; 34 | PoolTypeClient m_PoolClient; 35 | 36 | CRITICAL_SECTION m_CSForClients; 37 | }; 38 | -------------------------------------------------------------------------------- /IOCP - NewThreadPool/Client/Client.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 10.00 3 | # Visual Studio 2008 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Client - OldThreadPool", "Client.vcproj", "{D89CFDF1-ACBD-414F-81C5-83C3AB5FB403}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Release|Win32 = Release|Win32 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {D89CFDF1-ACBD-414F-81C5-83C3AB5FB403}.Debug|Win32.ActiveCfg = Debug|Win32 13 | {D89CFDF1-ACBD-414F-81C5-83C3AB5FB403}.Debug|Win32.Build.0 = Debug|Win32 14 | {D89CFDF1-ACBD-414F-81C5-83C3AB5FB403}.Release|Win32.ActiveCfg = Release|Win32 15 | {D89CFDF1-ACBD-414F-81C5-83C3AB5FB403}.Release|Win32.Build.0 = Release|Win32 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /IOCP - NewThreadPool/Server/Server.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 10.00 3 | # Visual Studio 2008 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Server - OldThreadPool", "Server.vcproj", "{9F68071D-1DDB-46E5-AD9A-D6D19C698688}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Release|Win32 = Release|Win32 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {9F68071D-1DDB-46E5-AD9A-D6D19C698688}.Debug|Win32.ActiveCfg = Debug|Win32 13 | {9F68071D-1DDB-46E5-AD9A-D6D19C698688}.Debug|Win32.Build.0 = Debug|Win32 14 | {9F68071D-1DDB-46E5-AD9A-D6D19C698688}.Release|Win32.ActiveCfg = Release|Win32 15 | {9F68071D-1DDB-46E5-AD9A-D6D19C698688}.Release|Win32.Build.0 = Release|Win32 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /IOCP - OldThreadPool/Client/Client.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 10.00 3 | # Visual Studio 2008 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Client - OldThreadPool", "Client.vcproj", "{D89CFDF1-ACBD-414F-81C5-83C3AB5FB403}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Release|Win32 = Release|Win32 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {D89CFDF1-ACBD-414F-81C5-83C3AB5FB403}.Debug|Win32.ActiveCfg = Debug|Win32 13 | {D89CFDF1-ACBD-414F-81C5-83C3AB5FB403}.Debug|Win32.Build.0 = Debug|Win32 14 | {D89CFDF1-ACBD-414F-81C5-83C3AB5FB403}.Release|Win32.ActiveCfg = Release|Win32 15 | {D89CFDF1-ACBD-414F-81C5-83C3AB5FB403}.Release|Win32.Build.0 = Release|Win32 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /IOCP - OldThreadPool/Server/Server.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 10.00 3 | # Visual Studio 2008 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Server - OldThreadPool", "Server.vcproj", "{9F68071D-1DDB-46E5-AD9A-D6D19C698688}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Release|Win32 = Release|Win32 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {9F68071D-1DDB-46E5-AD9A-D6D19C698688}.Debug|Win32.ActiveCfg = Debug|Win32 13 | {9F68071D-1DDB-46E5-AD9A-D6D19C698688}.Debug|Win32.Build.0 = Debug|Win32 14 | {9F68071D-1DDB-46E5-AD9A-D6D19C698688}.Release|Win32.ActiveCfg = Release|Win32 15 | {9F68071D-1DDB-46E5-AD9A-D6D19C698688}.Release|Win32.Build.0 = Release|Win32 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /IOCP - NewThreadPool/Client/ClientMan.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "..\TSingleton.h" 8 | 9 | class Client; 10 | 11 | using namespace std; 12 | 13 | class ClientMan : public TSingleton 14 | { 15 | private: 16 | static void CALLBACK WorkerRemoveClient(PTP_CALLBACK_INSTANCE /* Instance */, PVOID Context); 17 | 18 | public: 19 | ClientMan(void); 20 | virtual ~ClientMan(void); 21 | 22 | void AddClients(int numClients); 23 | void ConnectClients(const char* ip, u_short port); 24 | void ShutdownClients(); 25 | void RemoveClients(); 26 | void PostRemoveClient(Client* client); 27 | void Send(const string& msg); 28 | 29 | bool IsAlive(const Client* client); 30 | size_t GetNumClients(); 31 | 32 | private: 33 | void RemoveClient(Client* client); 34 | 35 | 36 | private: 37 | typedef vector ClientList; 38 | ClientList m_listClient; 39 | 40 | typedef boost::object_pool PoolTypeClient; 41 | PoolTypeClient m_PoolClient; 42 | 43 | CRITICAL_SECTION m_CSForClients; 44 | }; 45 | -------------------------------------------------------------------------------- /IOCP - NewThreadPool/Server/Client.cpp: -------------------------------------------------------------------------------- 1 | #include "Client.h" 2 | #include "..\Log.h" 3 | #include "..\Network.h" 4 | 5 | #include 6 | 7 | // use thread-safe memory pool 8 | typedef boost::singleton_pool ClientPool; 9 | 10 | /* static */ Client* Client::Create() 11 | { 12 | Client* client = static_cast(ClientPool::malloc()); 13 | 14 | client->m_State = WAIT; 15 | 16 | client->m_Socket = Network::CreateSocket(false, 0); 17 | if(client->m_Socket == INVALID_SOCKET) 18 | { 19 | ERROR_MSG("Could not create socket."); 20 | ClientPool::free(client); 21 | return NULL; 22 | } 23 | return client; 24 | } 25 | 26 | 27 | /* static */ void Client::Destroy(Client* client) 28 | { 29 | if( client->m_Socket != INVALID_SOCKET ) 30 | { 31 | Network::CloseSocket(client->m_Socket); 32 | CancelIoEx(reinterpret_cast(client->m_Socket), NULL); 33 | client->m_Socket = INVALID_SOCKET; 34 | client->m_State = DISCONNECTED; 35 | } 36 | 37 | if( client->m_pTPIO != NULL ) 38 | { 39 | WaitForThreadpoolIoCallbacks( client->m_pTPIO, true ); 40 | CloseThreadpoolIo( client->m_pTPIO ); 41 | client->m_pTPIO = NULL; 42 | } 43 | 44 | ClientPool::free(client); 45 | } -------------------------------------------------------------------------------- /IOCP - OldThreadPool/Client/Client.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | class Client 7 | { 8 | private: 9 | enum 10 | { 11 | MAX_RECV_BUFFER = 1024, 12 | MAX_SEND_BUFFER = 1024, 13 | }; 14 | 15 | public: 16 | enum State 17 | { 18 | WAIT, 19 | CREATED, 20 | CONNECTED, 21 | CLOSED, 22 | }; 23 | 24 | private: 25 | static void WINAPI OnIOCompletion(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped); 26 | 27 | public: 28 | Client(); 29 | ~Client(); 30 | 31 | bool Create(short port); 32 | void Destroy(); 33 | 34 | bool PostConnect(const char* ip, short port); 35 | void PostReceive(); 36 | void PostSend(const char* buffer, unsigned int size); 37 | 38 | bool Shutdown(); 39 | 40 | void OnConnect(); 41 | void OnRecv(DWORD dwNumberOfBytesTransfered); 42 | void OnSend(DWORD dwNumberOfBytesTransfered); 43 | void OnClose(); 44 | 45 | State GetState() { return m_State; } 46 | SOCKET GetSocket() { return m_Socket; } 47 | 48 | private: 49 | Client(const Client& rhs); 50 | Client& operator=(const Client& rhs); 51 | 52 | private: 53 | State m_State; 54 | SOCKET m_Socket; 55 | BYTE m_recvBuffer[MAX_RECV_BUFFER]; 56 | BYTE m_sendBuffer[MAX_SEND_BUFFER]; 57 | }; 58 | -------------------------------------------------------------------------------- /IOCP - NewThreadPool/Client/Client.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | class Client 7 | { 8 | private: 9 | enum 10 | { 11 | MAX_RECV_BUFFER = 1024, 12 | MAX_SEND_BUFFER = 1024, 13 | }; 14 | 15 | public: 16 | enum State 17 | { 18 | WAIT, 19 | CREATED, 20 | CONNECTED, 21 | CLOSED, 22 | }; 23 | 24 | private: 25 | static void CALLBACK IoCompletionCallback(PTP_CALLBACK_INSTANCE Instance, PVOID Context, PVOID Overlapped, ULONG IoResult, ULONG_PTR NumberOfBytesTransferred, PTP_IO Io); 26 | 27 | public: 28 | Client(); 29 | ~Client(); 30 | 31 | bool Create(short port); 32 | void Destroy(); 33 | 34 | bool PostConnect(const char* ip, short port); 35 | void PostReceive(); 36 | void PostSend(const char* buffer, unsigned int size); 37 | 38 | bool Shutdown(); 39 | 40 | void OnConnect(); 41 | void OnRecv(DWORD dwNumberOfBytesTransfered); 42 | void OnSend(DWORD dwNumberOfBytesTransfered); 43 | void OnClose(); 44 | 45 | State GetState() { return m_State; } 46 | SOCKET GetSocket() { return m_Socket; } 47 | 48 | private: 49 | Client(const Client& rhs); 50 | Client& operator=(const Client& rhs); 51 | 52 | private: 53 | TP_IO* m_pTPIO; 54 | 55 | State m_State; 56 | SOCKET m_Socket; 57 | BYTE m_recvBuffer[MAX_RECV_BUFFER]; 58 | BYTE m_sendBuffer[MAX_SEND_BUFFER]; 59 | }; 60 | -------------------------------------------------------------------------------- /IOCP - OldThreadPool/Server/main.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | #include "..\\Log.h" 7 | #include "..\\Network.h" 8 | #include "Server.h" 9 | 10 | void main(int argc, char* argv[]) 11 | { 12 | Log::Setup(); 13 | 14 | if( argc != 3) 15 | { 16 | TRACE("Please add port and max number of accept posts."); 17 | TRACE("(ex) 17000 100"); 18 | return; 19 | } 20 | 21 | u_short port = static_cast( atoi(argv[1]) ); 22 | int maxPostAccept = atoi(argv[2]); 23 | 24 | TRACE("Input : port : %d, max accept : %d", port, maxPostAccept); 25 | 26 | if(Network::Initialize() == false) 27 | { 28 | ERROR_MSG("Network::Initialize() failed"); 29 | return; 30 | } 31 | 32 | Server::New(); 33 | 34 | if(Server::Instance()->Create(port, maxPostAccept) == false) 35 | { 36 | ERROR_MSG("Server::Create() failed"); 37 | Network::Deinitialize(); 38 | return; 39 | } 40 | 41 | Log::EnableTrace(false); 42 | 43 | string input; 44 | bool loop = true; 45 | while(loop) 46 | { 47 | std::getline(cin, input); 48 | 49 | if(input == "`client_size") 50 | { 51 | TRACE(" Number of Clients : %d", Server::Instance()->GetNumClients()); 52 | } 53 | if(input == "`accept_size") 54 | { 55 | TRACE(" Number of Accept posts : %d", Server::Instance()->GetNumPostAccepts()); 56 | } 57 | else if(input == "`enable_trace") 58 | { 59 | Log::EnableTrace(true); 60 | } 61 | else if(input == "`disable_trace") 62 | { 63 | Log::EnableTrace(false); 64 | } 65 | } 66 | 67 | Server::Delete(); 68 | 69 | Network::Deinitialize(); 70 | 71 | Log::Cleanup(); 72 | 73 | return; 74 | } 75 | -------------------------------------------------------------------------------- /IOCP - NewThreadPool/Server/main.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | #include "..\\Log.h" 7 | #include "..\\Network.h" 8 | #include "Server.h" 9 | 10 | void main(int argc, char* argv[]) 11 | { 12 | Log::Setup(); 13 | 14 | if( argc != 3) 15 | { 16 | TRACE("Please add port and max number of accept posts."); 17 | TRACE("(ex) 17000 100"); 18 | return; 19 | } 20 | 21 | u_short port = static_cast( atoi(argv[1]) ); 22 | int maxPostAccept = atoi(argv[2]); 23 | 24 | TRACE("Input : port : %d, max accept : %d", port, maxPostAccept); 25 | 26 | if(Network::Initialize() == false) 27 | { 28 | ERROR_MSG("Network::Initialize() failed"); 29 | return; 30 | } 31 | 32 | Server::New(); 33 | 34 | if(Server::Instance()->Create(port, maxPostAccept) == false) 35 | { 36 | ERROR_MSG("Server::Create() failed"); 37 | Network::Deinitialize(); 38 | return; 39 | } 40 | 41 | #ifndef _DEBUG 42 | Log::EnableTrace(false); 43 | #endif 44 | 45 | string input; 46 | bool loop = true; 47 | while(loop) 48 | { 49 | std::getline(cin, input); 50 | 51 | if(input == "`client_size") 52 | { 53 | TRACE(" Number of Clients : %d", Server::Instance()->GetNumClients()); 54 | } 55 | if(input == "`accept_size") 56 | { 57 | TRACE(" Number of Accept posts : %d", Server::Instance()->GetNumPostAccepts()); 58 | } 59 | else if(input == "`enable_trace") 60 | { 61 | Log::EnableTrace(true); 62 | } 63 | else if(input == "`disable_trace") 64 | { 65 | Log::EnableTrace(false); 66 | } 67 | } 68 | 69 | Server::Delete(); 70 | 71 | Network::Deinitialize(); 72 | 73 | Log::Cleanup(); 74 | 75 | return; 76 | } 77 | -------------------------------------------------------------------------------- /IOCP - OldThreadPool/Server/Server.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "..\TSingleton.h" 7 | 8 | class Client; 9 | class Packet; 10 | class IOEvent; 11 | 12 | class Server : public TSingleton 13 | { 14 | private: 15 | // Callback Routine 16 | static void WINAPI OnIOCompletion(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped); 17 | 18 | // Worker Thread Functions 19 | static DWORD WINAPI WorkerPostAccept(LPVOID lpParam); 20 | static DWORD WINAPI WorkerAddClient(LPVOID lpParam); 21 | static DWORD WINAPI WorkerRemoveClient(LPVOID lpParam); 22 | static DWORD WINAPI WorkerProcessRecvPacket(LPVOID lpParam); 23 | static DWORD WINAPI WorkerProcessSentPacket(LPVOID lpParam); 24 | 25 | public: 26 | Server(); 27 | virtual ~Server(); 28 | 29 | bool Create(short port, int maxPostAccept); 30 | void Destroy(); 31 | 32 | size_t GetNumClients(); 33 | long GetNumPostAccepts(); 34 | 35 | private: 36 | void PostAccept(); 37 | void PostRecv(Client* client); 38 | void PostSend(Client* client, Packet* packet); 39 | 40 | void OnAccept(IOEvent* event); 41 | void OnRecv(IOEvent* event, DWORD dwNumberOfBytesTransfered); 42 | void OnSend(IOEvent* event, DWORD dwNumberOfBytesTransfered); 43 | void OnClose(IOEvent* event); 44 | 45 | void AddClient(Client* client); 46 | void RemoveClient(Client* client); 47 | 48 | void Echo(Packet* packet); 49 | 50 | private: 51 | Server& operator=(Server& rhs); 52 | Server(const Server& rhs); 53 | 54 | private: 55 | SOCKET m_listenSocket; 56 | 57 | typedef std::vector ClientList; 58 | ClientList m_Clients; 59 | 60 | int m_MaxPostAccept; 61 | volatile long m_NumPostAccept; 62 | 63 | CRITICAL_SECTION m_CSForClients; 64 | }; 65 | -------------------------------------------------------------------------------- /IOCP - NewThreadPool/Client/main.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | #include "..\\Log.h" 8 | #include "..\\Network.h" 9 | #include "ClientMan.h" 10 | 11 | void main(int argc, char* argv[]) 12 | { 13 | Log::Setup(); 14 | 15 | if(argc != 4) 16 | { 17 | TRACE("Please add server IP, port and max number of clients in command line."); 18 | TRACE("(ex) 127.0.0.1 1234 1000"); 19 | return; 20 | } 21 | 22 | const char* serverIP = argv[1]; 23 | u_short serverPort = static_cast(atoi(argv[2])); 24 | int maxClients = atoi(argv[3]); 25 | 26 | TRACE("Input : Server IP: %s, Port : %d, Max Clients : %i", serverIP, serverPort, maxClients); 27 | 28 | if(Network::Initialize() == false) 29 | { 30 | return; 31 | } 32 | 33 | ClientMan::New(); 34 | 35 | string input; 36 | bool loop = true; 37 | while(loop) 38 | { 39 | std::getline(cin, input); 40 | 41 | if(input == "`size") 42 | { 43 | TRACE(" Number of Clients : %d", ClientMan::Instance()->GetNumClients()); 44 | } 45 | else if(input =="`create") 46 | { 47 | ClientMan::Instance()->AddClients(maxClients); 48 | } 49 | else if(input == "`connect") 50 | { 51 | ClientMan::Instance()->ConnectClients(serverIP, serverPort); 52 | } 53 | else if(input == "`shutdown") 54 | { 55 | ClientMan::Instance()->ShutdownClients(); 56 | } 57 | else if(input == "`remove") 58 | { 59 | ClientMan::Instance()->RemoveClients(); 60 | } 61 | else if(input == "`enable_trace") 62 | { 63 | Log::EnableTrace(true); 64 | } 65 | else if(input == "`disable_trace") 66 | { 67 | Log::EnableTrace(false); 68 | } 69 | else if(!input.empty() && input.at(0) == '`') 70 | { 71 | TRACE("wrong command."); 72 | } 73 | else if(input.length() != 0) 74 | { 75 | ClientMan::Instance()->Send(input); 76 | } 77 | } 78 | 79 | ClientMan::Delete(); 80 | 81 | Network::Deinitialize(); 82 | 83 | Log::Cleanup(); 84 | 85 | return; 86 | } 87 | -------------------------------------------------------------------------------- /IOCP - NewThreadPool/Server/Server.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "..\TSingleton.h" 7 | 8 | class Client; 9 | class Packet; 10 | class IOEvent; 11 | 12 | class Server : public TSingleton 13 | { 14 | private: 15 | // Callback Routine 16 | static void CALLBACK IoCompletionCallback(PTP_CALLBACK_INSTANCE Instance, PVOID Context, PVOID Overlapped, ULONG IoResult, ULONG_PTR NumberOfBytesTransferred, PTP_IO Io); 17 | 18 | // Worker Thread Functions 19 | static void CALLBACK WorkerPostAccept(PTP_CALLBACK_INSTANCE /* Instance */, PVOID Context, PTP_WORK /* Work */); 20 | 21 | static void CALLBACK WorkerAddClient(PTP_CALLBACK_INSTANCE /* Instance */, PVOID Context); 22 | static void CALLBACK WorkerRemoveClient(PTP_CALLBACK_INSTANCE /* Instance */, PVOID Context); 23 | static void CALLBACK WorkerProcessRecvPacket(PTP_CALLBACK_INSTANCE /* Instance */, PVOID Context); 24 | 25 | public: 26 | Server(); 27 | virtual ~Server(); 28 | 29 | bool Create(short port, int maxPostAccept); 30 | void Destroy(); 31 | 32 | size_t GetNumClients(); 33 | long GetNumPostAccepts(); 34 | 35 | private: 36 | void PostAccept(); 37 | void PostRecv(Client* client); 38 | void PostSend(Client* client, Packet* packet); 39 | 40 | void OnAccept(IOEvent* event); 41 | void OnRecv(IOEvent* event, DWORD dwNumberOfBytesTransfered); 42 | void OnSend(IOEvent* event, DWORD dwNumberOfBytesTransfered); 43 | void OnClose(IOEvent* event); 44 | 45 | void AddClient(Client* client); 46 | void RemoveClient(Client* client); 47 | 48 | void Echo(Packet* packet); 49 | 50 | private: 51 | Server& operator=(Server& rhs); 52 | Server(const Server& rhs); 53 | 54 | private: 55 | TP_IO* m_pTPIO; 56 | SOCKET m_listenSocket; 57 | 58 | TP_WORK* m_AcceptTPWORK; 59 | 60 | typedef std::vector ClientList; 61 | ClientList m_Clients; 62 | 63 | int m_MaxPostAccept; 64 | volatile long m_NumPostAccept; 65 | 66 | CRITICAL_SECTION m_CSForClients; 67 | 68 | TP_CALLBACK_ENVIRON m_ClientTPENV; 69 | TP_CLEANUP_GROUP* m_ClientTPCLEAN; 70 | 71 | volatile bool m_ShuttingDown; 72 | }; 73 | -------------------------------------------------------------------------------- /IOCP - NewThreadPool/IOCP.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 10.00 3 | # Visual Studio 2008 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Client - OldThreadPool", "Client\Client.vcproj", "{D89CFDF1-ACBD-414F-81C5-83C3AB5FB403}" 5 | EndProject 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Server - OldThreadPool", "Server\Server.vcproj", "{9F68071D-1DDB-46E5-AD9A-D6D19C698688}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Win32 = Debug|Win32 11 | Debug|x64 = Debug|x64 12 | Release|Win32 = Release|Win32 13 | Release|x64 = Release|x64 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {D89CFDF1-ACBD-414F-81C5-83C3AB5FB403}.Debug|Win32.ActiveCfg = Debug|Win32 17 | {D89CFDF1-ACBD-414F-81C5-83C3AB5FB403}.Debug|Win32.Build.0 = Debug|Win32 18 | {D89CFDF1-ACBD-414F-81C5-83C3AB5FB403}.Debug|x64.ActiveCfg = Debug|x64 19 | {D89CFDF1-ACBD-414F-81C5-83C3AB5FB403}.Debug|x64.Build.0 = Debug|x64 20 | {D89CFDF1-ACBD-414F-81C5-83C3AB5FB403}.Release|Win32.ActiveCfg = Release|Win32 21 | {D89CFDF1-ACBD-414F-81C5-83C3AB5FB403}.Release|Win32.Build.0 = Release|Win32 22 | {D89CFDF1-ACBD-414F-81C5-83C3AB5FB403}.Release|x64.ActiveCfg = Release|x64 23 | {D89CFDF1-ACBD-414F-81C5-83C3AB5FB403}.Release|x64.Build.0 = Release|x64 24 | {9F68071D-1DDB-46E5-AD9A-D6D19C698688}.Debug|Win32.ActiveCfg = Debug|Win32 25 | {9F68071D-1DDB-46E5-AD9A-D6D19C698688}.Debug|Win32.Build.0 = Debug|Win32 26 | {9F68071D-1DDB-46E5-AD9A-D6D19C698688}.Debug|x64.ActiveCfg = Debug|x64 27 | {9F68071D-1DDB-46E5-AD9A-D6D19C698688}.Debug|x64.Build.0 = Debug|x64 28 | {9F68071D-1DDB-46E5-AD9A-D6D19C698688}.Release|Win32.ActiveCfg = Release|Win32 29 | {9F68071D-1DDB-46E5-AD9A-D6D19C698688}.Release|Win32.Build.0 = Release|Win32 30 | {9F68071D-1DDB-46E5-AD9A-D6D19C698688}.Release|x64.ActiveCfg = Release|x64 31 | {9F68071D-1DDB-46E5-AD9A-D6D19C698688}.Release|x64.Build.0 = Release|x64 32 | EndGlobalSection 33 | GlobalSection(SolutionProperties) = preSolution 34 | HideSolutionNode = FALSE 35 | EndGlobalSection 36 | EndGlobal 37 | -------------------------------------------------------------------------------- /IOCP - OldThreadPool/IOCP.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 10.00 3 | # Visual Studio 2008 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Client - OldThreadPool", "Client\Client.vcproj", "{D89CFDF1-ACBD-414F-81C5-83C3AB5FB403}" 5 | EndProject 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Server - OldThreadPool", "Server\Server.vcproj", "{9F68071D-1DDB-46E5-AD9A-D6D19C698688}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Win32 = Debug|Win32 11 | Debug|x64 = Debug|x64 12 | Release|Win32 = Release|Win32 13 | Release|x64 = Release|x64 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {D89CFDF1-ACBD-414F-81C5-83C3AB5FB403}.Debug|Win32.ActiveCfg = Debug|Win32 17 | {D89CFDF1-ACBD-414F-81C5-83C3AB5FB403}.Debug|Win32.Build.0 = Debug|Win32 18 | {D89CFDF1-ACBD-414F-81C5-83C3AB5FB403}.Debug|x64.ActiveCfg = Debug|x64 19 | {D89CFDF1-ACBD-414F-81C5-83C3AB5FB403}.Debug|x64.Build.0 = Debug|x64 20 | {D89CFDF1-ACBD-414F-81C5-83C3AB5FB403}.Release|Win32.ActiveCfg = Release|Win32 21 | {D89CFDF1-ACBD-414F-81C5-83C3AB5FB403}.Release|Win32.Build.0 = Release|Win32 22 | {D89CFDF1-ACBD-414F-81C5-83C3AB5FB403}.Release|x64.ActiveCfg = Release|x64 23 | {D89CFDF1-ACBD-414F-81C5-83C3AB5FB403}.Release|x64.Build.0 = Release|x64 24 | {9F68071D-1DDB-46E5-AD9A-D6D19C698688}.Debug|Win32.ActiveCfg = Debug|Win32 25 | {9F68071D-1DDB-46E5-AD9A-D6D19C698688}.Debug|Win32.Build.0 = Debug|Win32 26 | {9F68071D-1DDB-46E5-AD9A-D6D19C698688}.Debug|x64.ActiveCfg = Debug|x64 27 | {9F68071D-1DDB-46E5-AD9A-D6D19C698688}.Debug|x64.Build.0 = Debug|x64 28 | {9F68071D-1DDB-46E5-AD9A-D6D19C698688}.Release|Win32.ActiveCfg = Release|Win32 29 | {9F68071D-1DDB-46E5-AD9A-D6D19C698688}.Release|Win32.Build.0 = Release|Win32 30 | {9F68071D-1DDB-46E5-AD9A-D6D19C698688}.Release|x64.ActiveCfg = Release|x64 31 | {9F68071D-1DDB-46E5-AD9A-D6D19C698688}.Release|x64.Build.0 = Release|x64 32 | EndGlobalSection 33 | GlobalSection(SolutionProperties) = preSolution 34 | HideSolutionNode = FALSE 35 | EndGlobalSection 36 | EndGlobal 37 | -------------------------------------------------------------------------------- /IOCP - OldThreadPool/Client/main.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | #include "..\\Log.h" 8 | #include "..\\Network.h" 9 | #include "ClientMan.h" 10 | 11 | //The IANA suggests 49152 to 65535 as "dynamic and/or private ports". 12 | const short PORT_START = 50000; 13 | 14 | void main(int argc, char* argv[]) 15 | { 16 | Log::Setup(); 17 | 18 | if(argc != 4) 19 | { 20 | TRACE("Please add server IP, port and max number of clients in command line."); 21 | TRACE("(ex) 127.0.0.1 1234 1000"); 22 | return; 23 | } 24 | 25 | const char* serverIP = argv[1]; 26 | u_short serverPort = static_cast(atoi(argv[2])); 27 | int maxClients = atoi(argv[3]); 28 | 29 | TRACE("Input : Server IP: %s, Port : %d, Max Clients : %i", serverIP, serverPort, maxClients); 30 | 31 | if(Network::Initialize() == false) 32 | { 33 | return; 34 | } 35 | 36 | ClientMan::New(); 37 | 38 | short port = PORT_START; 39 | 40 | string input; 41 | bool loop = true; 42 | while(loop) 43 | { 44 | std::getline(cin, input); 45 | 46 | if(input == "`size") 47 | { 48 | TRACE(" Number of Clients : %d", ClientMan::Instance()->GetNumClients()); 49 | } 50 | else if(input =="`create") 51 | { 52 | ClientMan::Instance()->AddClients(port, maxClients); 53 | } 54 | else if(input == "`connect") 55 | { 56 | ClientMan::Instance()->ConnectClients(serverIP, serverPort); 57 | } 58 | else if(input == "`shutdown") 59 | { 60 | ClientMan::Instance()->ShutdownClients(); 61 | } 62 | else if(input == "`remove") 63 | { 64 | ClientMan::Instance()->RemoveClients(); 65 | } 66 | else if(input == "`enable_trace") 67 | { 68 | Log::EnableTrace(true); 69 | } 70 | else if(input == "`disable_trace") 71 | { 72 | Log::EnableTrace(false); 73 | } 74 | else if(!input.empty() && input.at(0) == '`') 75 | { 76 | TRACE("wrong command."); 77 | } 78 | else if(input.length() != 0) 79 | { 80 | ClientMan::Instance()->Send(input); 81 | } 82 | } 83 | 84 | ClientMan::Delete(); 85 | 86 | Network::Deinitialize(); 87 | 88 | Log::Cleanup(); 89 | 90 | return; 91 | } 92 | -------------------------------------------------------------------------------- /IOCP - NewThreadPool/Log.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Log.h" 4 | #include 5 | #include 6 | #include 7 | using namespace std; 8 | 9 | namespace Log 10 | { 11 | const int BUFFER_SIZE = 256; 12 | 13 | static bool s_Enable = true; 14 | 15 | HMODULE libModule; 16 | CRITICAL_SECTION logCS; 17 | 18 | void Error(const char * fileName, const char * funcName, int line, const char * msg, ...) 19 | { 20 | EnterCriticalSection(&logCS); 21 | 22 | static char buffer[BUFFER_SIZE] = {0,}; 23 | va_list args; 24 | va_start(args, msg); 25 | vsnprintf_s(buffer, BUFFER_SIZE, BUFFER_SIZE-1, msg, args); 26 | va_end(args); 27 | 28 | cout << "File: " << fileName << "\nFunction: " << funcName << "\nLine: " << line \ 29 | << "\nError: " << buffer << endl; 30 | 31 | LeaveCriticalSection(&logCS); 32 | } 33 | 34 | void Error(const char * fileName, const char * funcName, int line, int code, const char * msg, ...) 35 | { 36 | EnterCriticalSection(&logCS); 37 | 38 | char* lpMessageBuffer; 39 | 40 | FormatMessageA( 41 | FORMAT_MESSAGE_ALLOCATE_BUFFER | 42 | FORMAT_MESSAGE_FROM_SYSTEM | 43 | FORMAT_MESSAGE_FROM_HMODULE, 44 | libModule, 45 | code, 46 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 47 | (LPSTR) &lpMessageBuffer, 48 | 0, 49 | NULL ); 50 | 51 | static char buffer[BUFFER_SIZE] = {0,}; 52 | va_list args; 53 | va_start(args, msg); 54 | vsnprintf_s(buffer, BUFFER_SIZE, BUFFER_SIZE-1, msg, args); 55 | va_end(args); 56 | 57 | cout << "File: " << fileName << "\nFunction: " << funcName << "\nLine: " << line \ 58 | << "\nError: " << buffer << "\nMsg: " << lpMessageBuffer << "Code: " << code << " 0x" << hex << code << endl; 59 | 60 | cout << dec; 61 | 62 | // Free the buffer allocated by the system. 63 | LocalFree( lpMessageBuffer ); 64 | 65 | LeaveCriticalSection(&logCS); 66 | } 67 | 68 | void Trace(const char * msg, ...) 69 | { 70 | if( s_Enable ) 71 | { 72 | EnterCriticalSection(&logCS); 73 | 74 | static char buffer[BUFFER_SIZE] = {0,}; 75 | va_list args; 76 | va_start(args, msg); 77 | vsnprintf_s(buffer, BUFFER_SIZE, BUFFER_SIZE-1, msg, args); 78 | va_end(args); 79 | 80 | cout << buffer << endl; 81 | 82 | LeaveCriticalSection(&logCS); 83 | } 84 | } 85 | 86 | void Setup() 87 | { 88 | InitializeCriticalSection(&logCS); 89 | 90 | libModule = LoadLibraryA("NTDLL.DLL"); 91 | } 92 | 93 | void Cleanup() 94 | { 95 | EnterCriticalSection(&logCS); 96 | 97 | if(false == FreeLibrary(libModule)) 98 | { 99 | ERROR_CODE(GetLastError(), "Log::CleanUp() - FreeLibrary() failed."); 100 | } 101 | 102 | DeleteCriticalSection(&logCS); 103 | } 104 | 105 | void EnableTrace(bool enable) 106 | { 107 | s_Enable = enable; 108 | } 109 | } -------------------------------------------------------------------------------- /IOCP - OldThreadPool/Log.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Log.h" 4 | #include 5 | #include 6 | #include 7 | using namespace std; 8 | 9 | namespace Log 10 | { 11 | const int BUFFER_SIZE = 256; 12 | 13 | static bool s_Enable = true; 14 | 15 | HMODULE libModule; 16 | CRITICAL_SECTION logCS; 17 | 18 | void Error(const char * fileName, const char * funcName, int line, const char * msg, ...) 19 | { 20 | EnterCriticalSection(&logCS); 21 | 22 | static char buffer[BUFFER_SIZE] = {0,}; 23 | va_list args; 24 | va_start(args, msg); 25 | vsnprintf_s(buffer, BUFFER_SIZE, BUFFER_SIZE-1, msg, args); 26 | va_end(args); 27 | 28 | cout << "File: " << fileName << "\nFunction: " << funcName << "\nLine: " << line \ 29 | << "\nError: " << buffer << endl; 30 | 31 | LeaveCriticalSection(&logCS); 32 | } 33 | 34 | void Error(const char * fileName, const char * funcName, int line, int code, const char * msg, ...) 35 | { 36 | EnterCriticalSection(&logCS); 37 | 38 | char* lpMessageBuffer; 39 | 40 | FormatMessageA( 41 | FORMAT_MESSAGE_ALLOCATE_BUFFER | 42 | FORMAT_MESSAGE_FROM_SYSTEM | 43 | FORMAT_MESSAGE_FROM_HMODULE, 44 | libModule, 45 | code, 46 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 47 | (LPSTR) &lpMessageBuffer, 48 | 0, 49 | NULL ); 50 | 51 | static char buffer[BUFFER_SIZE] = {0,}; 52 | va_list args; 53 | va_start(args, msg); 54 | vsnprintf_s(buffer, BUFFER_SIZE, BUFFER_SIZE-1, msg, args); 55 | va_end(args); 56 | 57 | cout << "File: " << fileName << "\nFunction: " << funcName << "\nLine: " << line \ 58 | << "\nError: " << buffer << "\nMsg: " << lpMessageBuffer << "Code: " << code << " 0x" << hex << code << endl; 59 | 60 | cout << dec; 61 | 62 | // Free the buffer allocated by the system. 63 | LocalFree( lpMessageBuffer ); 64 | 65 | LeaveCriticalSection(&logCS); 66 | } 67 | 68 | void Trace(const char * msg, ...) 69 | { 70 | if( s_Enable ) 71 | { 72 | EnterCriticalSection(&logCS); 73 | 74 | static char buffer[BUFFER_SIZE] = {0,}; 75 | va_list args; 76 | va_start(args, msg); 77 | vsnprintf_s(buffer, BUFFER_SIZE, BUFFER_SIZE-1, msg, args); 78 | va_end(args); 79 | 80 | cout << buffer << endl; 81 | 82 | LeaveCriticalSection(&logCS); 83 | } 84 | } 85 | 86 | void Setup() 87 | { 88 | InitializeCriticalSection(&logCS); 89 | 90 | libModule = LoadLibraryA("NTDLL.DLL"); 91 | } 92 | 93 | void Cleanup() 94 | { 95 | EnterCriticalSection(&logCS); 96 | 97 | if(false == FreeLibrary(libModule)) 98 | { 99 | ERROR_CODE(GetLastError(), "Log::CleanUp() - FreeLibrary() failed."); 100 | } 101 | 102 | DeleteCriticalSection(&logCS); 103 | } 104 | 105 | void EnableTrace(bool enable) 106 | { 107 | s_Enable = enable; 108 | } 109 | } -------------------------------------------------------------------------------- /IOCP - OldThreadPool/Client/ClientMan.cpp: -------------------------------------------------------------------------------- 1 | #include "ClientMan.h" 2 | #include "Client.h" 3 | #include 4 | 5 | namespace 6 | { 7 | // Memory Pool for clients. 8 | typedef boost::singleton_pool PoolClient; 9 | } 10 | 11 | ClientMan::ClientMan(void) 12 | { 13 | InitializeCriticalSection(&m_CSForClients); 14 | } 15 | 16 | ClientMan::~ClientMan(void) 17 | { 18 | RemoveClients(); 19 | 20 | EnterCriticalSection(&m_CSForClients); 21 | } 22 | 23 | 24 | void ClientMan::AddClients(short& port, int numClients) 25 | { 26 | EnterCriticalSection(&m_CSForClients); 27 | 28 | int total = m_listClient.size() + numClients; 29 | 30 | while( m_listClient.size() < total ) 31 | { 32 | Client* client = m_PoolClient.construct(); 33 | 34 | if(client->Create(port++)) 35 | { 36 | m_listClient.push_back(client); 37 | } 38 | else 39 | { 40 | m_PoolClient.destroy(client); 41 | } 42 | } 43 | 44 | LeaveCriticalSection(&m_CSForClients); 45 | } 46 | 47 | void ClientMan::ConnectClients(const char* ip, u_short port) 48 | { 49 | EnterCriticalSection(&m_CSForClients); 50 | 51 | for(int i = 0 ; i != static_cast(m_listClient.size()) ; ++i) 52 | { 53 | m_listClient[i]->PostConnect(ip, port); 54 | } 55 | 56 | LeaveCriticalSection(&m_CSForClients); 57 | } 58 | 59 | void ClientMan::ShutdownClients() 60 | { 61 | EnterCriticalSection(&m_CSForClients); 62 | 63 | for(int i = 0 ; i != static_cast(m_listClient.size()) ; ++i) 64 | { 65 | m_listClient[i]->Shutdown(); 66 | } 67 | 68 | LeaveCriticalSection(&m_CSForClients); 69 | } 70 | 71 | void ClientMan::RemoveClients() 72 | { 73 | EnterCriticalSection(&m_CSForClients); 74 | 75 | for(int i = 0 ; i != static_cast(m_listClient.size()) ; ++i) 76 | { 77 | m_PoolClient.destroy(m_listClient[i]); 78 | } 79 | m_listClient.clear(); 80 | 81 | LeaveCriticalSection(&m_CSForClients); 82 | } 83 | 84 | void ClientMan::Send(const string& msg) 85 | { 86 | EnterCriticalSection(&m_CSForClients); 87 | 88 | for(int i = 0 ; i != static_cast(m_listClient.size()) ; ++i) 89 | { 90 | m_listClient[i]->PostSend(msg.c_str(), msg.length()); 91 | } 92 | 93 | LeaveCriticalSection(&m_CSForClients); 94 | } 95 | 96 | void ClientMan::RemoveClient(const Client* client) 97 | { 98 | EnterCriticalSection(&m_CSForClients); 99 | 100 | ClientList::iterator itor = find(m_listClient.begin(), m_listClient.end(), client); 101 | 102 | if( itor != m_listClient.end() ) 103 | { 104 | m_PoolClient.destroy(*itor); 105 | m_listClient.erase(itor); 106 | } 107 | 108 | LeaveCriticalSection(&m_CSForClients); 109 | } 110 | 111 | size_t ClientMan::GetNumClients() 112 | { 113 | EnterCriticalSection(&m_CSForClients); 114 | 115 | size_t num = m_listClient.size(); 116 | 117 | LeaveCriticalSection(&m_CSForClients); 118 | 119 | return num; 120 | } 121 | 122 | bool ClientMan::IsAlive(const Client* client) 123 | { 124 | EnterCriticalSection(&m_CSForClients); 125 | 126 | ClientList::const_iterator itor = find(m_listClient.begin(), m_listClient.end(), client); 127 | bool result = itor != m_listClient.end(); 128 | 129 | LeaveCriticalSection(&m_CSForClients); 130 | 131 | return result; 132 | } -------------------------------------------------------------------------------- /IOCP - NewThreadPool/Client/ClientMan.cpp: -------------------------------------------------------------------------------- 1 | #include "ClientMan.h" 2 | #include "Client.h" 3 | 4 | #include "..\Log.h" 5 | 6 | #include 7 | 8 | namespace 9 | { 10 | // Memory Pool for clients. 11 | typedef boost::singleton_pool PoolClient; 12 | } 13 | 14 | 15 | /* static */ void CALLBACK ClientMan::WorkerRemoveClient(PTP_CALLBACK_INSTANCE /* Instance */, PVOID Context) 16 | { 17 | Client* client = static_cast(Context); 18 | assert(client); 19 | 20 | ClientMan::Instance()->RemoveClient(client); 21 | } 22 | 23 | 24 | ClientMan::ClientMan(void) 25 | { 26 | InitializeCriticalSection(&m_CSForClients); 27 | } 28 | 29 | ClientMan::~ClientMan(void) 30 | { 31 | RemoveClients(); 32 | 33 | EnterCriticalSection(&m_CSForClients); 34 | } 35 | 36 | 37 | void ClientMan::AddClients(int numClients) 38 | { 39 | EnterCriticalSection(&m_CSForClients); 40 | 41 | for( int i = 0; i < numClients ; ++ i ) 42 | { 43 | Client* client = m_PoolClient.construct(); 44 | 45 | if(client->Create(0)) 46 | { 47 | m_listClient.push_back(client); 48 | } 49 | else 50 | { 51 | m_PoolClient.destroy(client); 52 | } 53 | } 54 | 55 | LeaveCriticalSection(&m_CSForClients); 56 | } 57 | 58 | void ClientMan::ConnectClients(const char* ip, u_short port) 59 | { 60 | EnterCriticalSection(&m_CSForClients); 61 | 62 | for(int i = 0 ; i != static_cast(m_listClient.size()) ; ++i) 63 | { 64 | m_listClient[i]->PostConnect(ip, port); 65 | } 66 | 67 | LeaveCriticalSection(&m_CSForClients); 68 | } 69 | 70 | void ClientMan::ShutdownClients() 71 | { 72 | EnterCriticalSection(&m_CSForClients); 73 | 74 | for(int i = 0 ; i != static_cast(m_listClient.size()) ; ++i) 75 | { 76 | m_listClient[i]->Shutdown(); 77 | } 78 | 79 | LeaveCriticalSection(&m_CSForClients); 80 | } 81 | 82 | void ClientMan::RemoveClients() 83 | { 84 | EnterCriticalSection(&m_CSForClients); 85 | 86 | for(int i = 0 ; i != static_cast(m_listClient.size()) ; ++i) 87 | { 88 | m_PoolClient.destroy(m_listClient[i]); 89 | } 90 | m_listClient.clear(); 91 | 92 | LeaveCriticalSection(&m_CSForClients); 93 | } 94 | 95 | void ClientMan::Send(const string& msg) 96 | { 97 | EnterCriticalSection(&m_CSForClients); 98 | 99 | for(int i = 0 ; i != static_cast(m_listClient.size()) ; ++i) 100 | { 101 | m_listClient[i]->PostSend(msg.c_str(), msg.length()); 102 | } 103 | 104 | LeaveCriticalSection(&m_CSForClients); 105 | } 106 | 107 | void ClientMan::PostRemoveClient(Client* client) 108 | { 109 | if(TrySubmitThreadpoolCallback(ClientMan::WorkerRemoveClient, client, NULL) == false) 110 | { 111 | ERROR_CODE(GetLastError(), "Could not start WorkerRemoveClient."); 112 | 113 | // This is not good. We should remove the client in a different thread to wait until its IO operations are complete. 114 | // You need a fallback strategy. DO NOT JUST FOLLOW THIS EXAMPLE. YOU HAVE BEEN WARNED. 115 | RemoveClient(client); 116 | } 117 | } 118 | 119 | void ClientMan::RemoveClient(Client* client) 120 | { 121 | EnterCriticalSection(&m_CSForClients); 122 | 123 | ClientList::iterator itor = find(m_listClient.begin(), m_listClient.end(), client); 124 | 125 | if( itor != m_listClient.end() ) 126 | { 127 | m_PoolClient.destroy(*itor); 128 | m_listClient.erase(itor); 129 | } 130 | 131 | LeaveCriticalSection(&m_CSForClients); 132 | } 133 | 134 | size_t ClientMan::GetNumClients() 135 | { 136 | EnterCriticalSection(&m_CSForClients); 137 | 138 | size_t num = m_listClient.size(); 139 | 140 | LeaveCriticalSection(&m_CSForClients); 141 | 142 | return num; 143 | } 144 | 145 | bool ClientMan::IsAlive(const Client* client) 146 | { 147 | EnterCriticalSection(&m_CSForClients); 148 | 149 | ClientList::const_iterator itor = find(m_listClient.begin(), m_listClient.end(), client); 150 | bool result = itor != m_listClient.end(); 151 | 152 | LeaveCriticalSection(&m_CSForClients); 153 | 154 | return result; 155 | } -------------------------------------------------------------------------------- /IOCP - NewThreadPool/Network.cpp: -------------------------------------------------------------------------------- 1 | #include "Network.h" 2 | #include "Log.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | 10 | 11 | namespace 12 | { 13 | LPFN_ACCEPTEX s_AcceptEx = NULL; 14 | LPFN_CONNECTEX s_ConnectEx = NULL; 15 | 16 | bool BindSocket(SOCKET socket, addrinfo* info) 17 | { 18 | if(bind(socket, info->ai_addr, static_cast(info->ai_addrlen)) == SOCKET_ERROR) 19 | { 20 | ERROR_CODE(WSAGetLastError(), "bind() failed."); 21 | return false; 22 | } 23 | 24 | std::string ip; 25 | u_short port; 26 | Network::GetLocalAddress(socket, ip, port); 27 | TRACE("Bind Address : ip[%s], port[%d]", ip.c_str(), port); 28 | 29 | return true; 30 | } 31 | } 32 | 33 | 34 | //---------------------------------------------------------------------------------// 35 | //---------------------------------------------------------------------------------// 36 | bool Network::Initialize() 37 | { 38 | WSADATA wd = {0, }; 39 | if(WSAStartup(WINSOCK_VERSION, &wd) != 0) 40 | { 41 | ERROR_MSG("WSAStartup failed."); 42 | return false; 43 | } 44 | 45 | return true; 46 | } 47 | 48 | 49 | void Network::Deinitialize() 50 | { 51 | WSACleanup(); 52 | } 53 | 54 | 55 | SOCKET Network::CreateSocket(bool bind, u_short port) 56 | { 57 | // Get Address Info 58 | addrinfo hints; 59 | ZeroMemory(&hints, sizeof(addrinfo)); 60 | hints.ai_family = AF_UNSPEC; 61 | hints.ai_socktype = SOCK_STREAM; 62 | hints.ai_protocol = IPPROTO_TCP; 63 | hints.ai_flags = bind ? AI_PASSIVE : 0; 64 | 65 | stringstream portBuff; 66 | portBuff << port; 67 | 68 | struct addrinfo* infoList = NULL; 69 | // Passing NULL for pNodeName should return INADDR_ANY 70 | if (getaddrinfo(NULL, portBuff.str().c_str(), &hints, &infoList) != 0) 71 | { 72 | ERROR_CODE(WSAGetLastError(), "getaddrinfo() failed. port : %d", port); 73 | return INVALID_SOCKET; 74 | } 75 | 76 | // loop through all the results and use the first we can 77 | struct addrinfo* info = infoList; 78 | SOCKET socket = INVALID_SOCKET; 79 | for(; info != NULL; info = info->ai_next) 80 | { 81 | socket = WSASocket(info->ai_family, info->ai_socktype, info->ai_protocol, NULL, 0, WSA_FLAG_OVERLAPPED); 82 | if(socket != INVALID_SOCKET) 83 | { 84 | if(!bind) 85 | break; 86 | 87 | if(BindSocket(socket, info)) 88 | break; 89 | 90 | CloseSocket(socket); 91 | socket = INVALID_SOCKET; 92 | } 93 | else 94 | { 95 | ERROR_CODE(WSAGetLastError(), "WSASocket() failed. port : %d", port); 96 | } 97 | } 98 | 99 | freeaddrinfo(infoList); 100 | 101 | return socket; 102 | } 103 | 104 | 105 | void Network::CloseSocket(SOCKET socket) 106 | { 107 | if(closesocket(socket) == SOCKET_ERROR) 108 | { 109 | ERROR_CODE(WSAGetLastError(), "closesocket() failed"); 110 | } 111 | } 112 | 113 | 114 | BOOL Network::AcceptEx(SOCKET listenSocket, SOCKET newSocket, LPOVERLAPPED overlapped) 115 | { 116 | if(s_AcceptEx == NULL) 117 | { 118 | DWORD dwBytes = 0; 119 | GUID guidAcceptEx = WSAID_ACCEPTEX; 120 | if (WSAIoctl(listenSocket, SIO_GET_EXTENSION_FUNCTION_POINTER, &guidAcceptEx, sizeof(guidAcceptEx), &s_AcceptEx, sizeof(s_AcceptEx), &dwBytes, 0, 0) == SOCKET_ERROR) 121 | { 122 | ERROR_CODE(WSAGetLastError(), "WSAIoctl() to get AcceptEx() failed."); 123 | return FALSE; 124 | } 125 | } 126 | 127 | // This value is for retriving first data, local and remote addresses from AcceptEx by calling GetAcceptExSockaddrs() latter. 128 | // Each address buffer must be at least 16 bytes more than the maximum address length for the transport protocol in use. 129 | // It seems we don't need to use GetAcceptExSockaddrs() as we can get the address from getsockname(), getpeername() once we set SO_UPDATE_ACCEPT_CONTEXT. 130 | static BYTE buffer[(sizeof(sockaddr_in6) + 16)*2]; 131 | 132 | return s_AcceptEx(listenSocket, newSocket, &buffer, 0, sizeof(sockaddr_in6) + 16, sizeof(sockaddr_in6) + 16, NULL, overlapped); 133 | } 134 | 135 | 136 | BOOL Network::ConnectEx(SOCKET socket, sockaddr* addr, int addrlen, LPOVERLAPPED overlapped) 137 | { 138 | if(s_ConnectEx == NULL) 139 | { 140 | DWORD dwBytes = 0; 141 | GUID guidConnectEx = WSAID_CONNECTEX; 142 | if (WSAIoctl(socket, SIO_GET_EXTENSION_FUNCTION_POINTER, &guidConnectEx, sizeof(guidConnectEx), &s_ConnectEx, sizeof(s_ConnectEx), &dwBytes, 0, 0) == SOCKET_ERROR) 143 | { 144 | ERROR_CODE(WSAGetLastError(), "WSAIoctl() to get ConnectEx() failed"); 145 | return FALSE; 146 | } 147 | } 148 | 149 | return s_ConnectEx(socket, addr, addrlen, NULL, 0, NULL, overlapped); 150 | } 151 | 152 | 153 | bool Network::GetLocalAddress(SOCKET socket, std::string& ip, u_short& port) 154 | { 155 | sockaddr_in6 addr6; 156 | ZeroMemory(&addr6, sizeof(addr6)); 157 | int size = sizeof(addr6); 158 | 159 | char buff[INET6_ADDRSTRLEN] = {0,}; 160 | 161 | if( 0 == getsockname(socket, reinterpret_cast(&addr6), &size) ) 162 | { 163 | if( size == sizeof(sockaddr_in6) ) 164 | { 165 | port = ntohs(addr6.sin6_port); 166 | inet_ntop(AF_INET6, &addr6.sin6_addr, buff, INET6_ADDRSTRLEN); 167 | 168 | ip = buff; 169 | } 170 | else if ( size == sizeof(sockaddr_in) ) 171 | { 172 | sockaddr_in* pAddr4 = reinterpret_cast(&addr6); 173 | 174 | port = ntohs(pAddr4->sin_port); 175 | inet_ntop(AF_INET, &pAddr4->sin_addr, buff, INET_ADDRSTRLEN); 176 | 177 | ip = buff; 178 | } 179 | else 180 | { 181 | return false; 182 | } 183 | 184 | return true; 185 | } 186 | 187 | return false; 188 | } 189 | 190 | 191 | bool Network::GetRemoteAddress(SOCKET socket, std::string& ip, u_short& port) 192 | { 193 | char buff[INET6_ADDRSTRLEN] = {0,}; 194 | 195 | sockaddr_in6 addr6; 196 | ZeroMemory(&addr6, sizeof(addr6)); 197 | int size = sizeof(addr6); 198 | 199 | if( 0 == getpeername(socket, reinterpret_cast(&addr6), &size) ) 200 | { 201 | if( size == sizeof(sockaddr_in6) ) 202 | { 203 | port = ntohs(addr6.sin6_port); 204 | inet_ntop(AF_INET6, &addr6.sin6_addr, buff, INET6_ADDRSTRLEN); 205 | 206 | ip = buff; 207 | } 208 | else if ( size == sizeof(sockaddr_in) ) 209 | { 210 | sockaddr_in* pAddr4 = reinterpret_cast(&addr6); 211 | port = ntohs(pAddr4->sin_port); 212 | inet_ntop(AF_INET, &pAddr4->sin_addr, buff, INET_ADDRSTRLEN); 213 | 214 | ip = buff; 215 | } 216 | else 217 | { 218 | return false; 219 | } 220 | 221 | return true; 222 | } 223 | 224 | return false; 225 | } 226 | -------------------------------------------------------------------------------- /IOCP - OldThreadPool/Network.cpp: -------------------------------------------------------------------------------- 1 | #include "Network.h" 2 | #include "Log.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | 10 | 11 | namespace 12 | { 13 | LPFN_ACCEPTEX s_AcceptEx = NULL; 14 | LPFN_CONNECTEX s_ConnectEx = NULL; 15 | 16 | bool BindSocket(SOCKET socket, addrinfo* info) 17 | { 18 | if(bind(socket, info->ai_addr, static_cast(info->ai_addrlen)) == SOCKET_ERROR) 19 | { 20 | ERROR_CODE(WSAGetLastError(), "bind() failed."); 21 | return false; 22 | } 23 | 24 | std::string ip; 25 | u_short port; 26 | Network::GetLocalAddress(socket, ip, port); 27 | TRACE("Bind Address : ip[%s], port[%d]", ip.c_str(), port); 28 | 29 | return true; 30 | } 31 | } 32 | 33 | 34 | //---------------------------------------------------------------------------------// 35 | //---------------------------------------------------------------------------------// 36 | bool Network::Initialize() 37 | { 38 | WSADATA wd = {0, }; 39 | if(WSAStartup(WINSOCK_VERSION, &wd) != 0) 40 | { 41 | ERROR_MSG("WSAStartup failed."); 42 | return false; 43 | } 44 | 45 | return true; 46 | } 47 | 48 | 49 | void Network::Deinitialize() 50 | { 51 | WSACleanup(); 52 | } 53 | 54 | 55 | SOCKET Network::CreateSocket(bool bind, u_short port) 56 | { 57 | // Get Address Info 58 | addrinfo hints; 59 | ZeroMemory(&hints, sizeof(addrinfo)); 60 | hints.ai_family = AF_UNSPEC; 61 | hints.ai_socktype = SOCK_STREAM; 62 | hints.ai_protocol = IPPROTO_TCP; 63 | hints.ai_flags = bind ? AI_PASSIVE : 0; 64 | 65 | stringstream portBuff; 66 | portBuff << port; 67 | 68 | struct addrinfo* infoList = NULL; 69 | // Passing NULL for pNodeName should return INADDR_ANY 70 | if (getaddrinfo(NULL, portBuff.str().c_str(), &hints, &infoList) != 0) 71 | { 72 | ERROR_CODE(WSAGetLastError(), "getaddrinfo() failed. port : %d", port); 73 | return INVALID_SOCKET; 74 | } 75 | 76 | // loop through all the results and use the first we can 77 | struct addrinfo* info = infoList; 78 | SOCKET socket = INVALID_SOCKET; 79 | for(; info != NULL; info = info->ai_next) 80 | { 81 | socket = WSASocket(info->ai_family, info->ai_socktype, info->ai_protocol, NULL, 0, WSA_FLAG_OVERLAPPED); 82 | if(socket != INVALID_SOCKET) 83 | { 84 | if(!bind) 85 | break; 86 | 87 | if(BindSocket(socket, info)) 88 | break; 89 | 90 | CloseSocket(socket); 91 | socket = INVALID_SOCKET; 92 | } 93 | else 94 | { 95 | ERROR_CODE(WSAGetLastError(), "WSASocket() failed. port : %d", port); 96 | } 97 | } 98 | 99 | freeaddrinfo(infoList); 100 | 101 | return socket; 102 | } 103 | 104 | 105 | void Network::CloseSocket(SOCKET socket) 106 | { 107 | if(closesocket(socket) == SOCKET_ERROR) 108 | { 109 | ERROR_CODE(WSAGetLastError(), "closesocket() failed"); 110 | } 111 | } 112 | 113 | 114 | BOOL Network::AcceptEx(SOCKET listenSocket, SOCKET newSocket, LPOVERLAPPED overlapped) 115 | { 116 | if(s_AcceptEx == NULL) 117 | { 118 | DWORD dwBytes = 0; 119 | GUID guidAcceptEx = WSAID_ACCEPTEX; 120 | if (WSAIoctl(listenSocket, SIO_GET_EXTENSION_FUNCTION_POINTER, &guidAcceptEx, sizeof(guidAcceptEx), &s_AcceptEx, sizeof(s_AcceptEx), &dwBytes, 0, 0) == SOCKET_ERROR) 121 | { 122 | ERROR_CODE(WSAGetLastError(), "WSAIoctl() to get AcceptEx() failed."); 123 | return FALSE; 124 | } 125 | } 126 | 127 | // This value is for retriving first data, local and remote addresses from AcceptEx by calling GetAcceptExSockaddrs() latter. 128 | // Each address buffer must be at least 16 bytes more than the maximum address length for the transport protocol in use. 129 | // It seems we don't need to use GetAcceptExSockaddrs() as we can get the address from getsockname(), getpeername() once we set SO_UPDATE_ACCEPT_CONTEXT. 130 | static BYTE buffer[(sizeof(sockaddr_in6) + 16)*2]; 131 | 132 | return s_AcceptEx(listenSocket, newSocket, &buffer, 0, sizeof(sockaddr_in6) + 16, sizeof(sockaddr_in6) + 16, NULL, overlapped); 133 | } 134 | 135 | 136 | BOOL Network::ConnectEx(SOCKET socket, sockaddr* addr, int addrlen, LPOVERLAPPED overlapped) 137 | { 138 | if(s_ConnectEx == NULL) 139 | { 140 | DWORD dwBytes = 0; 141 | GUID guidConnectEx = WSAID_CONNECTEX; 142 | if (WSAIoctl(socket, SIO_GET_EXTENSION_FUNCTION_POINTER, &guidConnectEx, sizeof(guidConnectEx), &s_ConnectEx, sizeof(s_ConnectEx), &dwBytes, 0, 0) == SOCKET_ERROR) 143 | { 144 | ERROR_CODE(WSAGetLastError(), "WSAIoctl() to get ConnectEx() failed"); 145 | return FALSE; 146 | } 147 | } 148 | 149 | return s_ConnectEx(socket, addr, addrlen, NULL, 0, NULL, overlapped); 150 | } 151 | 152 | 153 | bool Network::GetLocalAddress(SOCKET socket, std::string& ip, u_short& port) 154 | { 155 | sockaddr_in6 addr6; 156 | ZeroMemory(&addr6, sizeof(addr6)); 157 | int size = sizeof(addr6); 158 | 159 | char buff[INET6_ADDRSTRLEN] = {0,}; 160 | 161 | if( 0 == getsockname(socket, reinterpret_cast(&addr6), &size) ) 162 | { 163 | if( size == sizeof(sockaddr_in6) ) 164 | { 165 | port = ntohs(addr6.sin6_port); 166 | inet_ntop(AF_INET6, &addr6.sin6_addr, buff, INET6_ADDRSTRLEN); 167 | 168 | ip = buff; 169 | } 170 | else if ( size == sizeof(sockaddr_in) ) 171 | { 172 | sockaddr_in* pAddr4 = reinterpret_cast(&addr6); 173 | 174 | port = ntohs(pAddr4->sin_port); 175 | inet_ntop(AF_INET, &pAddr4->sin_addr, buff, INET_ADDRSTRLEN); 176 | 177 | ip = buff; 178 | } 179 | else 180 | { 181 | return false; 182 | } 183 | 184 | return true; 185 | } 186 | 187 | return false; 188 | } 189 | 190 | 191 | bool Network::GetRemoteAddress(SOCKET socket, std::string& ip, u_short& port) 192 | { 193 | char buff[INET6_ADDRSTRLEN] = {0,}; 194 | 195 | sockaddr_in6 addr6; 196 | ZeroMemory(&addr6, sizeof(addr6)); 197 | int size = sizeof(addr6); 198 | 199 | if( 0 == getpeername(socket, reinterpret_cast(&addr6), &size) ) 200 | { 201 | if( size == sizeof(sockaddr_in6) ) 202 | { 203 | port = ntohs(addr6.sin6_port); 204 | inet_ntop(AF_INET6, &addr6.sin6_addr, buff, INET6_ADDRSTRLEN); 205 | 206 | ip = buff; 207 | } 208 | else if ( size == sizeof(sockaddr_in) ) 209 | { 210 | sockaddr_in* pAddr4 = reinterpret_cast(&addr6); 211 | port = ntohs(pAddr4->sin_port); 212 | inet_ntop(AF_INET, &pAddr4->sin_addr, buff, INET_ADDRSTRLEN); 213 | 214 | ip = buff; 215 | } 216 | else 217 | { 218 | return false; 219 | } 220 | 221 | return true; 222 | } 223 | 224 | return false; 225 | } 226 | -------------------------------------------------------------------------------- /IOCP - NewThreadPool/Client/Client.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 15 | 18 | 19 | 20 | 21 | 22 | 29 | 32 | 35 | 38 | 41 | 44 | 58 | 61 | 64 | 67 | 77 | 80 | 83 | 86 | 89 | 92 | 95 | 98 | 99 | 107 | 110 | 113 | 116 | 119 | 122 | 133 | 136 | 139 | 142 | 154 | 157 | 160 | 163 | 166 | 169 | 172 | 175 | 176 | 183 | 186 | 189 | 192 | 195 | 199 | 212 | 215 | 218 | 221 | 229 | 232 | 235 | 238 | 241 | 244 | 247 | 250 | 253 | 254 | 262 | 265 | 268 | 271 | 274 | 278 | 287 | 290 | 293 | 296 | 305 | 308 | 311 | 314 | 317 | 320 | 323 | 326 | 329 | 330 | 331 | 332 | 333 | 334 | 337 | 338 | 341 | 342 | 345 | 346 | 349 | 350 | 353 | 354 | 357 | 358 | 361 | 362 | 365 | 366 | 369 | 370 | 373 | 374 | 375 | 376 | 377 | 378 | -------------------------------------------------------------------------------- /IOCP - OldThreadPool/Client/Client.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 15 | 18 | 19 | 20 | 21 | 22 | 29 | 32 | 35 | 38 | 41 | 44 | 58 | 61 | 64 | 67 | 77 | 80 | 83 | 86 | 89 | 92 | 95 | 98 | 99 | 107 | 110 | 113 | 116 | 119 | 122 | 133 | 136 | 139 | 142 | 154 | 157 | 160 | 163 | 166 | 169 | 172 | 175 | 176 | 183 | 186 | 189 | 192 | 195 | 199 | 212 | 215 | 218 | 221 | 229 | 232 | 235 | 238 | 241 | 244 | 247 | 250 | 253 | 254 | 262 | 265 | 268 | 271 | 274 | 278 | 287 | 290 | 293 | 296 | 305 | 308 | 311 | 314 | 317 | 320 | 323 | 326 | 329 | 330 | 331 | 332 | 333 | 334 | 337 | 338 | 341 | 342 | 345 | 346 | 349 | 350 | 353 | 354 | 357 | 358 | 361 | 362 | 365 | 366 | 369 | 370 | 373 | 374 | 375 | 376 | 377 | 378 | -------------------------------------------------------------------------------- /IOCP - NewThreadPool/Server/Server.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 15 | 18 | 19 | 20 | 21 | 22 | 29 | 32 | 35 | 38 | 41 | 44 | 57 | 60 | 63 | 66 | 76 | 79 | 82 | 85 | 88 | 91 | 94 | 97 | 98 | 106 | 109 | 112 | 115 | 118 | 121 | 131 | 134 | 137 | 140 | 152 | 155 | 158 | 161 | 164 | 167 | 170 | 173 | 174 | 181 | 184 | 187 | 190 | 193 | 197 | 210 | 213 | 216 | 219 | 227 | 230 | 233 | 236 | 239 | 242 | 245 | 248 | 251 | 252 | 260 | 263 | 266 | 269 | 272 | 276 | 286 | 289 | 292 | 295 | 305 | 308 | 311 | 314 | 317 | 320 | 323 | 326 | 329 | 330 | 331 | 332 | 333 | 334 | 337 | 338 | 341 | 342 | 345 | 346 | 349 | 350 | 353 | 354 | 357 | 358 | 361 | 362 | 365 | 366 | 369 | 370 | 373 | 374 | 377 | 378 | 381 | 382 | 385 | 386 | 389 | 390 | 391 | 392 | 393 | 394 | -------------------------------------------------------------------------------- /IOCP - OldThreadPool/Server/Server.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 15 | 18 | 19 | 20 | 21 | 22 | 29 | 32 | 35 | 38 | 41 | 44 | 57 | 60 | 63 | 66 | 76 | 79 | 82 | 85 | 88 | 91 | 94 | 97 | 98 | 106 | 109 | 112 | 115 | 118 | 121 | 131 | 134 | 137 | 140 | 152 | 155 | 158 | 161 | 164 | 167 | 170 | 173 | 174 | 181 | 184 | 187 | 190 | 193 | 197 | 210 | 213 | 216 | 219 | 227 | 230 | 233 | 236 | 239 | 242 | 245 | 248 | 251 | 252 | 260 | 263 | 266 | 269 | 272 | 276 | 286 | 289 | 292 | 295 | 305 | 308 | 311 | 314 | 317 | 320 | 323 | 326 | 329 | 330 | 331 | 332 | 333 | 334 | 337 | 338 | 341 | 342 | 345 | 346 | 349 | 350 | 353 | 354 | 357 | 358 | 361 | 362 | 365 | 366 | 369 | 370 | 373 | 374 | 377 | 378 | 381 | 382 | 385 | 386 | 389 | 390 | 391 | 392 | 393 | 394 | -------------------------------------------------------------------------------- /IOCP - OldThreadPool/Client/Client.cpp: -------------------------------------------------------------------------------- 1 | #include "Client.h" 2 | #include "ClientMan.h" 3 | 4 | #include "..\Log.h" 5 | #include "..\Network.h" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | namespace 15 | { 16 | class IOEvent 17 | { 18 | public: 19 | enum Type 20 | { 21 | CONNECT, 22 | RECV, 23 | SEND, 24 | }; 25 | 26 | public: 27 | static IOEvent* Create(Client* clent, Type type); 28 | static void Destroy(IOEvent* event); 29 | 30 | public: 31 | OVERLAPPED overlapped; 32 | Client* client; 33 | Type type; 34 | 35 | private: 36 | IOEvent(); 37 | ~IOEvent(); 38 | IOEvent(const IOEvent& rhs); 39 | IOEvent& operator=(IOEvent& rhs); 40 | }; 41 | 42 | // use thread-safe memory pool 43 | typedef boost::singleton_pool IOEventPool; 44 | 45 | /* static */ IOEvent* IOEvent::Create(Client* client, Type type) 46 | { 47 | IOEvent* event = static_cast(IOEventPool::malloc()); 48 | ZeroMemory(event, sizeof(IOEvent)); 49 | event->client = client; 50 | event->type = type; 51 | return event; 52 | } 53 | 54 | /* static */ void IOEvent::Destroy(IOEvent* event) 55 | { 56 | IOEventPool::free(event); 57 | } 58 | 59 | void PrintConnectionInfo(SOCKET socket) 60 | { 61 | std::string serverIP, clientIP; 62 | u_short serverPort = 0, clientPort = 0; 63 | Network::GetLocalAddress(socket, clientIP, clientPort); 64 | Network::GetRemoteAddress(socket, serverIP, serverPort); 65 | 66 | TRACE("Connection from ip[%s], port[%d] to ip[%s], port[%d] succeeded.", clientIP.c_str(), clientPort, serverIP.c_str(), serverPort); 67 | } 68 | } 69 | 70 | //---------------------------------------------------------------------------------// 71 | //---------------------------------------------------------------------------------// 72 | /* static */ void WINAPI Client::OnIOCompletion(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped) 73 | { 74 | IOEvent* event = CONTAINING_RECORD(lpOverlapped, IOEvent, overlapped); 75 | assert(event); 76 | assert(event->client); 77 | 78 | if ( false == ClientMan::Instance()->IsAlive(event->client) ) 79 | { 80 | // No client for this event. 81 | IOEvent::Destroy(event); 82 | return; 83 | } 84 | 85 | if(dwErrorCode == ERROR_SUCCESS) 86 | { 87 | switch(event->type) 88 | { 89 | case IOEvent::CONNECT: 90 | event->client->OnConnect(); 91 | break; 92 | 93 | case IOEvent::RECV: 94 | if(dwNumberOfBytesTransfered > 0) 95 | { 96 | event->client->OnRecv(dwNumberOfBytesTransfered); 97 | } 98 | else 99 | { 100 | event->client->OnClose(); 101 | } 102 | break; 103 | 104 | case IOEvent::SEND: 105 | event->client->OnSend(dwNumberOfBytesTransfered); 106 | break; 107 | 108 | default: assert(false); break; 109 | } 110 | } 111 | else 112 | { 113 | ERROR_CODE(dwErrorCode, "I/O operation failed."); 114 | PrintConnectionInfo(event->client->GetSocket()); 115 | 116 | event->client->OnClose(); 117 | } 118 | 119 | IOEvent::Destroy(event); 120 | } 121 | 122 | //---------------------------------------------------------------------------------// 123 | //---------------------------------------------------------------------------------// 124 | Client::Client() 125 | : m_Socket(INVALID_SOCKET), m_State(WAIT) 126 | { 127 | } 128 | 129 | //---------------------------------------------------------------------------------// 130 | //---------------------------------------------------------------------------------// 131 | Client::~Client() 132 | { 133 | Destroy(); 134 | } 135 | 136 | 137 | //---------------------------------------------------------------------------------// 138 | //---------------------------------------------------------------------------------// 139 | bool Client::Create(short port) 140 | { 141 | assert(m_Socket == INVALID_SOCKET); 142 | assert(m_State == WAIT); 143 | 144 | // Create Socket 145 | m_Socket = Network::CreateSocket(true, port); 146 | if(m_Socket == INVALID_SOCKET) 147 | { 148 | return false; 149 | } 150 | 151 | // Make the address re-usable to re-run the same client instantly. 152 | bool reuseAddr = true; 153 | if(setsockopt(m_Socket, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast(&reuseAddr), sizeof(reuseAddr)) == SOCKET_ERROR) 154 | { 155 | ERROR_CODE(WSAGetLastError(), "setsockopt() failed with SO_REUSEADDR."); 156 | return false; 157 | } 158 | 159 | // Connect the socket to IOCP 160 | if(BindIoCompletionCallback(reinterpret_cast(m_Socket), Client::OnIOCompletion, 0) == false) 161 | { 162 | ERROR_CODE(GetLastError(), "BindIoCompletionCallback() failed."); 163 | return false; 164 | } 165 | 166 | m_State = CREATED; 167 | 168 | return true; 169 | } 170 | 171 | //---------------------------------------------------------------------------------// 172 | //---------------------------------------------------------------------------------// 173 | void Client::Destroy() 174 | { 175 | if(m_State != CLOSED) 176 | { 177 | Network::CloseSocket(m_Socket); 178 | CancelIoEx(reinterpret_cast(m_Socket), NULL); 179 | m_Socket = INVALID_SOCKET; 180 | m_State = CLOSED; 181 | } 182 | } 183 | 184 | bool Client::PostConnect(const char* ip, short port) 185 | { 186 | if(m_State != CREATED) 187 | { 188 | return false; 189 | } 190 | 191 | assert(m_Socket != INVALID_SOCKET); 192 | 193 | // Get Address Info 194 | addrinfo hints; 195 | ZeroMemory(&hints, sizeof(addrinfo)); 196 | hints.ai_family = AF_UNSPEC; 197 | hints.ai_socktype = SOCK_STREAM; 198 | hints.ai_protocol = IPPROTO_TCP; 199 | hints.ai_flags = 0; 200 | 201 | char portStr[32] = ""; 202 | if( -1 == sprintf_s(portStr, sizeof(portStr), "%d", port) ) 203 | { 204 | return false; 205 | } 206 | 207 | struct addrinfo* infoList = NULL; 208 | if (getaddrinfo(ip, portStr, &hints, &infoList) != 0) 209 | { 210 | ERROR_CODE(WSAGetLastError(), "getaddrinfo() failed."); 211 | return false; 212 | } 213 | 214 | IOEvent* event = IOEvent::Create(this, IOEvent::CONNECT); 215 | 216 | // loop through all the results and connect to the first we can 217 | struct addrinfo* info = infoList; 218 | for(; info != NULL; info = info->ai_next) 219 | { 220 | if(Network::ConnectEx(m_Socket, info->ai_addr, info->ai_addrlen, &event->overlapped) == FALSE) 221 | { 222 | int error = WSAGetLastError(); 223 | 224 | if(error != ERROR_IO_PENDING) 225 | { 226 | ERROR_CODE(error, "ConnectEx() failed."); 227 | continue; 228 | } 229 | else 230 | { 231 | return true; 232 | } 233 | } 234 | else 235 | { 236 | OnConnect(); 237 | IOEvent::Destroy(event); 238 | return true; 239 | } 240 | } 241 | 242 | IOEvent::Destroy(event); 243 | return false; 244 | } 245 | 246 | 247 | void Client::PostReceive() 248 | { 249 | assert(m_State == CREATED || m_State == CONNECTED); 250 | 251 | WSABUF recvBufferDescriptor; 252 | recvBufferDescriptor.buf = reinterpret_cast(m_recvBuffer); 253 | recvBufferDescriptor.len = Client::MAX_RECV_BUFFER; 254 | 255 | DWORD numberOfBytes = 0; 256 | DWORD recvFlags = 0; 257 | 258 | IOEvent* event = IOEvent::Create(this, IOEvent::RECV); 259 | 260 | if(WSARecv(m_Socket, &recvBufferDescriptor, 1, &numberOfBytes, &recvFlags, &event->overlapped, NULL) == SOCKET_ERROR) 261 | { 262 | int error = WSAGetLastError(); 263 | 264 | if(error != ERROR_IO_PENDING) 265 | { 266 | if(m_State == CREATED) 267 | { 268 | // Even though we get successful connection event, if our first call of WSARecv failed, it means we failed in connecting. 269 | ERROR_CODE(error, "Server cannot accept this connection."); 270 | } 271 | else 272 | { 273 | ERROR_CODE(error, "WSARecv() failed."); 274 | } 275 | 276 | Destroy(); 277 | } 278 | else 279 | { 280 | // If this is the first call of WSARecv, we can now set the state CONNECTED. 281 | if(m_State == CREATED) 282 | { 283 | PrintConnectionInfo(m_Socket); 284 | m_State = CONNECTED; 285 | } 286 | } 287 | } 288 | else 289 | { 290 | // In this case, the completion routine will have already been scheduled to be called once the calling thread is in the alertable state. 291 | // I strongly believe it will trigger my OnIOCompletion() since there is no completion routine. 292 | 293 | // If this is the first call of WSARecv, we can now set the state CONNECTED. 294 | if(m_State == CREATED) 295 | { 296 | PrintConnectionInfo(m_Socket); 297 | m_State = CONNECTED; 298 | } 299 | } 300 | } 301 | 302 | 303 | void Client::PostSend(const char* buffer, unsigned int size) 304 | { 305 | if(m_State != CONNECTED) 306 | { 307 | return; 308 | } 309 | 310 | WSABUF recvBufferDescriptor; 311 | recvBufferDescriptor.buf = reinterpret_cast(m_sendBuffer); 312 | recvBufferDescriptor.len = size; 313 | 314 | CopyMemory(m_sendBuffer, buffer, size); 315 | 316 | DWORD numberOfBytes = size; 317 | DWORD sendFlags = 0; 318 | 319 | IOEvent* event = IOEvent::Create(this, IOEvent::SEND); 320 | 321 | if(WSASend(m_Socket, &recvBufferDescriptor, 1, &numberOfBytes, sendFlags, &event->overlapped, NULL) == SOCKET_ERROR) 322 | { 323 | int error = WSAGetLastError(); 324 | 325 | if(error != ERROR_IO_PENDING) 326 | { 327 | ERROR_CODE(error, "WSASend() failed."); 328 | 329 | // Error Handling!!! // 330 | Destroy(); 331 | } 332 | } 333 | else 334 | { 335 | // In this case, the completion routine will have already been scheduled to be called once the calling thread is in the alertable state. 336 | // I strongly believe it will trigger my OnIOCompletion() since there is no completion routine. 337 | } 338 | } 339 | 340 | 341 | bool Client::Shutdown() 342 | { 343 | if(m_State != CONNECTED) 344 | { 345 | return false; 346 | } 347 | 348 | assert(m_Socket != INVALID_SOCKET); 349 | 350 | if(shutdown(m_Socket, SD_SEND) == SOCKET_ERROR) 351 | { 352 | ERROR_CODE(WSAGetLastError(), "shutdown() failed."); 353 | return false; 354 | } 355 | 356 | return true; 357 | } 358 | 359 | 360 | void Client::OnConnect() 361 | { 362 | // The socket s does not enable previously set properties or options until SO_UPDATE_CONNECT_CONTEXT is set on the socket. 363 | if(setsockopt(m_Socket, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, NULL, 1) == SOCKET_ERROR) 364 | { 365 | ERROR_CODE(WSAGetLastError(), "setsockopt() failed."); 366 | } 367 | else 368 | { 369 | PostReceive(); 370 | } 371 | } 372 | 373 | 374 | void Client::OnRecv(DWORD dwNumberOfBytesTransfered) 375 | { 376 | // Do not process packet received here. 377 | // Instead, publish event with the packet and call PostRecv() 378 | m_recvBuffer[dwNumberOfBytesTransfered] = '\0'; 379 | TRACE("OnRecv() : %s", m_recvBuffer); 380 | 381 | // To maximize performance, post recv request ASAP. 382 | PostReceive(); 383 | } 384 | 385 | 386 | void Client::OnSend(DWORD dwNumberOfBytesTransfered) 387 | { 388 | TRACE("OnSend() : %d", dwNumberOfBytesTransfered); 389 | } 390 | 391 | 392 | void Client::OnClose() 393 | { 394 | TRACE("OnClose()"); 395 | 396 | Destroy(); 397 | 398 | ClientMan::Instance()->RemoveClient(this); 399 | } 400 | -------------------------------------------------------------------------------- /IOCP - NewThreadPool/Client/Client.cpp: -------------------------------------------------------------------------------- 1 | #include "Client.h" 2 | #include "ClientMan.h" 3 | 4 | #include "..\Log.h" 5 | #include "..\Network.h" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | namespace 15 | { 16 | class IOEvent 17 | { 18 | public: 19 | enum Type 20 | { 21 | CONNECT, 22 | RECV, 23 | SEND, 24 | }; 25 | 26 | public: 27 | static IOEvent* Create(Client* clent, Type type); 28 | static void Destroy(IOEvent* event); 29 | 30 | public: 31 | OVERLAPPED overlapped; 32 | Client* client; 33 | Type type; 34 | 35 | private: 36 | IOEvent(); 37 | ~IOEvent(); 38 | IOEvent(const IOEvent& rhs); 39 | IOEvent& operator=(IOEvent& rhs); 40 | }; 41 | 42 | // use thread-safe memory pool 43 | typedef boost::singleton_pool IOEventPool; 44 | 45 | /* static */ IOEvent* IOEvent::Create(Client* client, Type type) 46 | { 47 | IOEvent* event = static_cast(IOEventPool::malloc()); 48 | ZeroMemory(event, sizeof(IOEvent)); 49 | event->client = client; 50 | event->type = type; 51 | return event; 52 | } 53 | 54 | /* static */ void IOEvent::Destroy(IOEvent* event) 55 | { 56 | IOEventPool::free(event); 57 | } 58 | 59 | void PrintConnectionInfo(SOCKET socket) 60 | { 61 | std::string serverIP, clientIP; 62 | u_short serverPort = 0, clientPort = 0; 63 | Network::GetLocalAddress(socket, clientIP, clientPort); 64 | Network::GetRemoteAddress(socket, serverIP, serverPort); 65 | 66 | TRACE("Connection from ip[%s], port[%d] to ip[%s], port[%d] succeeded.", clientIP.c_str(), clientPort, serverIP.c_str(), serverPort); 67 | } 68 | } 69 | 70 | //---------------------------------------------------------------------------------// 71 | //---------------------------------------------------------------------------------// 72 | /* static */ void CALLBACK Client::IoCompletionCallback(PTP_CALLBACK_INSTANCE /* Instance */, PVOID /* Context */, 73 | PVOID Overlapped, ULONG IoResult, ULONG_PTR NumberOfBytesTransferred, PTP_IO /* Io */) 74 | { 75 | IOEvent* event = CONTAINING_RECORD(Overlapped, IOEvent, overlapped); 76 | assert(event); 77 | assert(event->client); 78 | 79 | if ( false == ClientMan::Instance()->IsAlive(event->client) ) 80 | { 81 | // No client for this event. 82 | IOEvent::Destroy(event); 83 | return; 84 | } 85 | 86 | if(IoResult == ERROR_SUCCESS) 87 | { 88 | switch(event->type) 89 | { 90 | case IOEvent::CONNECT: 91 | event->client->OnConnect(); 92 | break; 93 | 94 | case IOEvent::RECV: 95 | if(NumberOfBytesTransferred > 0) 96 | { 97 | event->client->OnRecv(NumberOfBytesTransferred); 98 | } 99 | else 100 | { 101 | event->client->OnClose(); 102 | ClientMan::Instance()->PostRemoveClient(event->client); 103 | } 104 | break; 105 | 106 | case IOEvent::SEND: 107 | event->client->OnSend(NumberOfBytesTransferred); 108 | break; 109 | 110 | default: assert(false); break; 111 | } 112 | } 113 | else 114 | { 115 | ERROR_CODE(IoResult, "I/O operation failed."); 116 | ClientMan::Instance()->PostRemoveClient(event->client); 117 | } 118 | 119 | IOEvent::Destroy(event); 120 | } 121 | 122 | //---------------------------------------------------------------------------------// 123 | //---------------------------------------------------------------------------------// 124 | Client::Client() 125 | : m_pTPIO(NULL), m_Socket(INVALID_SOCKET), m_State(WAIT) 126 | { 127 | } 128 | 129 | //---------------------------------------------------------------------------------// 130 | //---------------------------------------------------------------------------------// 131 | Client::~Client() 132 | { 133 | Destroy(); 134 | } 135 | 136 | 137 | //---------------------------------------------------------------------------------// 138 | //---------------------------------------------------------------------------------// 139 | bool Client::Create(short port) 140 | { 141 | assert(m_Socket == INVALID_SOCKET); 142 | assert(m_State == WAIT); 143 | 144 | // Create Socket 145 | m_Socket = Network::CreateSocket(true, port); 146 | if(m_Socket == INVALID_SOCKET) 147 | { 148 | return false; 149 | } 150 | 151 | // Make the address re-usable to re-run the same client instantly. 152 | bool reuseAddr = true; 153 | if(setsockopt(m_Socket, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast(&reuseAddr), sizeof(reuseAddr)) == SOCKET_ERROR) 154 | { 155 | ERROR_CODE(WSAGetLastError(), "setsockopt() failed with SO_REUSEADDR."); 156 | return false; 157 | } 158 | 159 | // Create & Start ThreaddPool for socket IO 160 | m_pTPIO = CreateThreadpoolIo(reinterpret_cast(m_Socket), IoCompletionCallback, NULL, NULL); 161 | if( m_pTPIO == NULL ) 162 | { 163 | ERROR_CODE(GetLastError(), "CreateThreadpoolIo() failed."); 164 | return false; 165 | } 166 | 167 | m_State = CREATED; 168 | 169 | return true; 170 | } 171 | 172 | //---------------------------------------------------------------------------------// 173 | //---------------------------------------------------------------------------------// 174 | void Client::Destroy() 175 | { 176 | if(m_State != CLOSED) 177 | { 178 | Network::CloseSocket(m_Socket); 179 | CancelIoEx(reinterpret_cast(m_Socket), NULL); 180 | m_Socket = INVALID_SOCKET; 181 | m_State = CLOSED; 182 | } 183 | 184 | if( m_pTPIO != NULL ) 185 | { 186 | WaitForThreadpoolIoCallbacks( m_pTPIO, false ); 187 | CloseThreadpoolIo( m_pTPIO ); 188 | m_pTPIO = NULL; 189 | } 190 | } 191 | 192 | bool Client::PostConnect(const char* ip, short port) 193 | { 194 | if(m_State != CREATED) 195 | { 196 | return false; 197 | } 198 | 199 | assert(m_Socket != INVALID_SOCKET); 200 | 201 | // Get Address Info 202 | addrinfo hints; 203 | ZeroMemory(&hints, sizeof(addrinfo)); 204 | hints.ai_family = AF_UNSPEC; 205 | hints.ai_socktype = SOCK_STREAM; 206 | hints.ai_protocol = IPPROTO_TCP; 207 | hints.ai_flags = 0; 208 | 209 | char portStr[32] = ""; 210 | if( -1 == sprintf_s(portStr, sizeof(portStr), "%d", port) ) 211 | { 212 | return false; 213 | } 214 | 215 | struct addrinfo* infoList = NULL; 216 | if (getaddrinfo(ip, portStr, &hints, &infoList) != 0) 217 | { 218 | ERROR_CODE(WSAGetLastError(), "getaddrinfo() failed."); 219 | return false; 220 | } 221 | 222 | IOEvent* event = IOEvent::Create(this, IOEvent::CONNECT); 223 | 224 | // loop through all the results and connect to the first we can 225 | struct addrinfo* info = infoList; 226 | for(; info != NULL; info = info->ai_next) 227 | { 228 | StartThreadpoolIo( m_pTPIO ); 229 | 230 | if(Network::ConnectEx(m_Socket, info->ai_addr, info->ai_addrlen, &event->overlapped) == FALSE) 231 | { 232 | int error = WSAGetLastError(); 233 | 234 | if(error != ERROR_IO_PENDING) 235 | { 236 | CancelThreadpoolIo( m_pTPIO ); 237 | ERROR_CODE(error, "ConnectEx() failed."); 238 | continue; 239 | } 240 | else 241 | { 242 | return true; 243 | } 244 | } 245 | else 246 | { 247 | OnConnect(); 248 | IOEvent::Destroy(event); 249 | return true; 250 | } 251 | } 252 | 253 | IOEvent::Destroy(event); 254 | return false; 255 | } 256 | 257 | 258 | void Client::PostReceive() 259 | { 260 | assert(m_State == CREATED || m_State == CONNECTED); 261 | 262 | WSABUF recvBufferDescriptor; 263 | recvBufferDescriptor.buf = reinterpret_cast(m_recvBuffer); 264 | recvBufferDescriptor.len = Client::MAX_RECV_BUFFER; 265 | 266 | DWORD numberOfBytes = 0; 267 | DWORD recvFlags = 0; 268 | 269 | IOEvent* event = IOEvent::Create(this, IOEvent::RECV); 270 | 271 | StartThreadpoolIo( m_pTPIO ); 272 | 273 | if(WSARecv(m_Socket, &recvBufferDescriptor, 1, &numberOfBytes, &recvFlags, &event->overlapped, NULL) == SOCKET_ERROR) 274 | { 275 | int error = WSAGetLastError(); 276 | 277 | if(error != ERROR_IO_PENDING) 278 | { 279 | CancelThreadpoolIo( m_pTPIO ); 280 | 281 | if(m_State == CREATED) 282 | { 283 | // Even though we get successful connection event, if our first call of WSARecv failed, it means we failed in connecting. 284 | ERROR_CODE(error, "Server cannot accept this connection."); 285 | } 286 | else 287 | { 288 | ERROR_CODE(error, "WSARecv() failed."); 289 | } 290 | 291 | Destroy(); 292 | } 293 | else 294 | { 295 | // If this is the first call of WSARecv, we can now set the state CONNECTED. 296 | if(m_State == CREATED) 297 | { 298 | PrintConnectionInfo(m_Socket); 299 | m_State = CONNECTED; 300 | } 301 | } 302 | } 303 | else 304 | { 305 | // If this is the first call of WSARecv, we can now set the state CONNECTED. 306 | if(m_State == CREATED) 307 | { 308 | PrintConnectionInfo(m_Socket); 309 | m_State = CONNECTED; 310 | } 311 | 312 | // In this case, the completion callback will have already been scheduled to be called. 313 | } 314 | } 315 | 316 | 317 | void Client::PostSend(const char* buffer, unsigned int size) 318 | { 319 | if(m_State != CONNECTED) 320 | { 321 | return; 322 | } 323 | 324 | WSABUF recvBufferDescriptor; 325 | recvBufferDescriptor.buf = reinterpret_cast(m_sendBuffer); 326 | recvBufferDescriptor.len = size; 327 | 328 | CopyMemory(m_sendBuffer, buffer, size); 329 | 330 | DWORD numberOfBytes = size; 331 | DWORD sendFlags = 0; 332 | 333 | IOEvent* event = IOEvent::Create(this, IOEvent::SEND); 334 | 335 | StartThreadpoolIo( m_pTPIO ); 336 | 337 | int ret = WSASend(m_Socket, &recvBufferDescriptor, 1, &numberOfBytes, sendFlags, &event->overlapped, NULL); 338 | if(ret == SOCKET_ERROR) 339 | { 340 | int error = WSAGetLastError(); 341 | 342 | if(error != ERROR_IO_PENDING) 343 | { 344 | CancelThreadpoolIo( m_pTPIO ); 345 | 346 | ERROR_CODE(error, "WSASend() failed."); 347 | 348 | // Error Handling!!! // 349 | Destroy(); 350 | } 351 | } 352 | else 353 | { 354 | // In this case, the completion callback will have already been scheduled to be called. 355 | } 356 | } 357 | 358 | 359 | bool Client::Shutdown() 360 | { 361 | if(m_State != CONNECTED) 362 | { 363 | return false; 364 | } 365 | 366 | assert(m_Socket != INVALID_SOCKET); 367 | 368 | if(shutdown(m_Socket, SD_SEND) == SOCKET_ERROR) 369 | { 370 | ERROR_CODE(WSAGetLastError(), "shutdown() failed."); 371 | return false; 372 | } 373 | 374 | return true; 375 | } 376 | 377 | 378 | void Client::OnConnect() 379 | { 380 | // The socket s does not enable previously set properties or options until SO_UPDATE_CONNECT_CONTEXT is set on the socket. 381 | if(setsockopt(m_Socket, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, NULL, 1) == SOCKET_ERROR) 382 | { 383 | ERROR_CODE(WSAGetLastError(), "setsockopt() failed."); 384 | } 385 | else 386 | { 387 | PostReceive(); 388 | } 389 | } 390 | 391 | 392 | void Client::OnRecv(DWORD dwNumberOfBytesTransfered) 393 | { 394 | // Do not process packet received here. 395 | // Instead, publish event with the packet and call PostRecv() 396 | m_recvBuffer[dwNumberOfBytesTransfered] = '\0'; 397 | TRACE("OnRecv() : %s", m_recvBuffer); 398 | 399 | // To maximize performance, post recv request ASAP. 400 | PostReceive(); 401 | } 402 | 403 | 404 | void Client::OnSend(DWORD dwNumberOfBytesTransfered) 405 | { 406 | TRACE("OnSend() : %d", dwNumberOfBytesTransfered); 407 | } 408 | 409 | 410 | void Client::OnClose() 411 | { 412 | TRACE("OnClose()"); 413 | 414 | Destroy(); 415 | } 416 | -------------------------------------------------------------------------------- /IOCP - OldThreadPool/Server/Server.cpp: -------------------------------------------------------------------------------- 1 | #include "Server.h" 2 | #include "Client.h" 3 | #include "Packet.h" 4 | #include "IOEvent.h" 5 | 6 | #include "..\Log.h" 7 | #include "..\Network.h" 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | 15 | //---------------------------------------------------------------------------------// 16 | //---------------------------------------------------------------------------------// 17 | void WINAPI Server::OnIOCompletion(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped) 18 | { 19 | IOEvent* event = CONTAINING_RECORD(lpOverlapped, IOEvent, GetOverlapped()); 20 | assert(event); 21 | 22 | if(dwErrorCode != ERROR_SUCCESS) 23 | { 24 | ERROR_CODE(dwErrorCode, "I/O operation failed. type[%d]", event->GetType()); 25 | 26 | switch(event->GetType()) 27 | { 28 | case IOEvent::SEND: 29 | Server::Instance()->OnSend(event, dwNumberOfBytesTransfered); 30 | break; 31 | } 32 | 33 | Server::Instance()->OnClose(event); 34 | } 35 | else 36 | { 37 | switch(event->GetType()) 38 | { 39 | case IOEvent::ACCEPT: 40 | Server::Instance()->OnAccept(event); 41 | break; 42 | 43 | case IOEvent::RECV: 44 | if(dwNumberOfBytesTransfered > 0) 45 | { 46 | Server::Instance()->OnRecv(event, dwNumberOfBytesTransfered); 47 | } 48 | else 49 | { 50 | Server::Instance()->OnClose(event); 51 | } 52 | break; 53 | 54 | case IOEvent::SEND: 55 | Server::Instance()->OnSend(event, dwNumberOfBytesTransfered); 56 | break; 57 | 58 | default: assert(false); break; 59 | } 60 | } 61 | 62 | IOEvent::Destroy(event); 63 | } 64 | 65 | 66 | DWORD WINAPI Server::WorkerPostAccept(LPVOID lpParam) 67 | { 68 | Server* server = static_cast(lpParam); 69 | assert(server); 70 | 71 | bool loop = true; 72 | while(loop) 73 | { 74 | server->PostAccept(); 75 | } 76 | 77 | return 0; 78 | } 79 | 80 | 81 | DWORD WINAPI Server::WorkerAddClient(LPVOID lpParam) 82 | { 83 | Client* client = static_cast(lpParam); 84 | assert(client); 85 | 86 | Server::Instance()->AddClient(client); 87 | return 0; 88 | } 89 | 90 | 91 | DWORD WINAPI Server::WorkerRemoveClient(LPVOID lpParam) 92 | { 93 | Client* client = static_cast(lpParam); 94 | assert(client); 95 | 96 | Server::Instance()->RemoveClient(client); 97 | return 0; 98 | } 99 | 100 | 101 | DWORD WINAPI Server::WorkerProcessRecvPacket(LPVOID lpParam) 102 | { 103 | Packet* packet = static_cast(lpParam); 104 | assert(packet); 105 | 106 | Server::Instance()->Echo(packet); 107 | return 0; 108 | } 109 | 110 | 111 | //---------------------------------------------------------------------------------// 112 | //---------------------------------------------------------------------------------// 113 | Server::Server(void) 114 | : m_listenSocket(INVALID_SOCKET), 115 | m_MaxPostAccept(0), 116 | m_NumPostAccept(0) 117 | { 118 | } 119 | 120 | 121 | Server::~Server(void) 122 | { 123 | Destroy(); 124 | } 125 | 126 | 127 | bool Server::Create(short port, int maxPostAccept) 128 | { 129 | assert(maxPostAccept > 0); 130 | 131 | m_MaxPostAccept = maxPostAccept; 132 | 133 | // Create Listen Socket 134 | m_listenSocket = Network::CreateSocket(true, port); 135 | if(m_listenSocket == INVALID_SOCKET) 136 | { 137 | return false; 138 | } 139 | 140 | // Make the address re-usable to re-run the same server instantly. 141 | bool reuseAddr = true; 142 | if(setsockopt(m_listenSocket, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast(&reuseAddr), sizeof(reuseAddr)) == SOCKET_ERROR) 143 | { 144 | ERROR_CODE(WSAGetLastError(), "setsockopt() failed with SO_REUSEADDR."); 145 | Destroy(); 146 | return false; 147 | } 148 | 149 | // Connect the listener socket to IOCP 150 | if(BindIoCompletionCallback(reinterpret_cast(m_listenSocket), Server::OnIOCompletion, 0) == false) 151 | { 152 | ERROR_CODE(WSAGetLastError(), "Could not assign the listen socket to the IOCP handle."); 153 | Destroy(); 154 | return false; 155 | } 156 | 157 | // Start listening 158 | if(listen(m_listenSocket, SOMAXCONN) == SOCKET_ERROR) 159 | { 160 | ERROR_CODE(WSAGetLastError(), "listen() failed."); 161 | return false; 162 | } 163 | 164 | // Create critical sections for m_Clients 165 | InitializeCriticalSection(&m_CSForClients); 166 | 167 | // Start posting AcceptEx requests 168 | if(QueueUserWorkItem(Server::WorkerPostAccept, this, WT_EXECUTEDEFAULT) == false) 169 | { 170 | ERROR_CODE(GetLastError(), "Could not start posting AcceptEx."); 171 | Destroy(); 172 | return false; 173 | } 174 | 175 | return true; 176 | } 177 | 178 | 179 | void Server::Destroy() 180 | { 181 | Network::CloseSocket(m_listenSocket); 182 | 183 | EnterCriticalSection(&m_CSForClients); 184 | for(ClientList::iterator itor = m_Clients.begin() ; itor != m_Clients.end() ; ++itor) 185 | { 186 | Client::Destroy(*itor); 187 | } 188 | m_Clients.clear(); 189 | LeaveCriticalSection(&m_CSForClients); 190 | 191 | DeleteCriticalSection(&m_CSForClients); 192 | } 193 | 194 | 195 | void Server::PostAccept() 196 | { 197 | // If the number of clients is too big, we can just stop posting aceept. 198 | // That's one of the benefits from AcceptEx. 199 | int count = m_MaxPostAccept - m_NumPostAccept; 200 | if( count > 0 ) 201 | { 202 | int i = 0; 203 | for( ; i < count ; ++i ) 204 | { 205 | Client* client = Client::Create(); 206 | if( !client ) 207 | { 208 | break; 209 | } 210 | 211 | IOEvent* event = IOEvent::Create(IOEvent::ACCEPT, client); 212 | assert(event); 213 | 214 | if ( FALSE == Network::AcceptEx(m_listenSocket, client->GetSocket(), &event->GetOverlapped())) 215 | { 216 | int error = WSAGetLastError(); 217 | 218 | if(error != ERROR_IO_PENDING) 219 | { 220 | ERROR_CODE(error, "AcceptEx() failed."); 221 | Client::Destroy(client); 222 | IOEvent::Destroy(event); 223 | break; 224 | } 225 | } 226 | else 227 | { 228 | OnAccept(event); 229 | IOEvent::Destroy(event); 230 | } 231 | } 232 | 233 | InterlockedExchangeAdd(&m_NumPostAccept, i); 234 | 235 | TRACE("[%d] Post AcceptEx : %d", GetCurrentThreadId(), m_NumPostAccept); 236 | } 237 | } 238 | 239 | 240 | void Server::PostRecv(Client* client) 241 | { 242 | assert(client); 243 | 244 | WSABUF recvBufferDescriptor; 245 | recvBufferDescriptor.buf = reinterpret_cast(client->GetRecvBuff()); 246 | recvBufferDescriptor.len = Client::MAX_RECV_BUFFER; 247 | 248 | DWORD numberOfBytes = 0; 249 | DWORD recvFlags = 0; 250 | 251 | IOEvent* event = IOEvent::Create(IOEvent::RECV, client); 252 | assert(event); 253 | 254 | if(WSARecv(client->GetSocket(), &recvBufferDescriptor, 1, &numberOfBytes, &recvFlags, &event->GetOverlapped(), NULL) == SOCKET_ERROR) 255 | { 256 | int error = WSAGetLastError(); 257 | 258 | if(error != ERROR_IO_PENDING) 259 | { 260 | ERROR_CODE(error, "WSARecv() failed."); 261 | 262 | OnClose(event); 263 | IOEvent::Destroy(event); 264 | } 265 | } 266 | else 267 | { 268 | // MSDN 269 | // In this case, the completion routine will have already been scheduled to be called once the calling thread is in the alertable state. 270 | } 271 | } 272 | 273 | 274 | void Server::PostSend(Client* client, Packet* packet) 275 | { 276 | assert(client); 277 | assert(packet); 278 | 279 | WSABUF recvBufferDescriptor; 280 | recvBufferDescriptor.buf = reinterpret_cast(packet->GetData()); 281 | recvBufferDescriptor.len = packet->GetSize(); 282 | 283 | DWORD sendFlags = 0; 284 | 285 | IOEvent* event = IOEvent::Create(IOEvent::SEND, client, packet); 286 | assert(event); 287 | 288 | if(WSASend(client->GetSocket(), &recvBufferDescriptor, 1, NULL, sendFlags, &event->GetOverlapped(), NULL) == SOCKET_ERROR) 289 | { 290 | int error = WSAGetLastError(); 291 | 292 | if(error != ERROR_IO_PENDING) 293 | { 294 | ERROR_CODE(error, "WSASend() failed."); 295 | 296 | RemoveClient(client); 297 | } 298 | } 299 | else 300 | { 301 | // MSDN 302 | // In this case, the completion routine will have already been scheduled to be called once the calling thread is in the alertable state. 303 | } 304 | } 305 | 306 | 307 | void Server::OnAccept(IOEvent* event) 308 | { 309 | assert(event); 310 | 311 | TRACE("[%d] Enter OnAccept()", GetCurrentThreadId()); 312 | assert(event->GetType() == IOEvent::ACCEPT); 313 | 314 | // Check if we need to post more accept requests. 315 | InterlockedDecrement(&m_NumPostAccept); 316 | 317 | // Add client in a different thread. 318 | // It is because we need to return this function ASAP so that this IO worker thread can process the other IO notifications. 319 | // If adding client is fast enough, we can call it here but I assume it's slow. 320 | if(QueueUserWorkItem(Server::WorkerAddClient, event->GetClient(), WT_EXECUTEDEFAULT) == false) 321 | { 322 | ERROR_CODE(GetLastError(), "Could not start WorkerAddClient."); 323 | 324 | AddClient(event->GetClient()); 325 | } 326 | 327 | TRACE("[%d] Leave OnAccept()", GetCurrentThreadId()); 328 | } 329 | 330 | 331 | void Server::OnRecv(IOEvent* event, DWORD dwNumberOfBytesTransfered) 332 | { 333 | assert(event); 334 | 335 | TRACE("[%d] Enter OnRecv()", GetCurrentThreadId()); 336 | 337 | BYTE* buff = event->GetClient()->GetRecvBuff(); 338 | buff[dwNumberOfBytesTransfered] = '\0'; 339 | TRACE("[%d] OnRecv : %s", GetCurrentThreadId(), buff); 340 | 341 | // Create packet by copying recv buff. 342 | Packet* packet = Packet::Create(event->GetClient(), event->GetClient()->GetRecvBuff(), dwNumberOfBytesTransfered); 343 | 344 | // If whatever game logics relying on the packet are fast enough, we can manage them here but I assume they are slow. 345 | // I think it's better to request receiving ASAP and handle packets received in another thread. 346 | if(QueueUserWorkItem(Server::WorkerProcessRecvPacket, packet, WT_EXECUTEDEFAULT) == false) 347 | { 348 | ERROR_CODE(GetLastError(), "Could not start WorkerProcessRecvPacket. call it directly."); 349 | 350 | WorkerProcessRecvPacket(packet); 351 | } 352 | 353 | PostRecv(event->GetClient()); 354 | 355 | TRACE("[%d] Leave OnRecv()", GetCurrentThreadId()); 356 | } 357 | 358 | 359 | void Server::OnSend(IOEvent* event, DWORD dwNumberOfBytesTransfered) 360 | { 361 | assert(event); 362 | 363 | TRACE("[%d] OnSend : %d", GetCurrentThreadId(), dwNumberOfBytesTransfered); 364 | 365 | // This should be fast enough to do in this I/O thread. 366 | // if not, we need to queue it like what we do in OnRecv(). 367 | Packet::Destroy(event->GetPacket()); 368 | } 369 | 370 | 371 | void Server::OnClose(IOEvent* event) 372 | { 373 | assert(event); 374 | 375 | TRACE("Client's socket has been closed."); 376 | 377 | // If whatever game logics about this event are fast enough, we can manage them here but I assume they are slow. 378 | if(QueueUserWorkItem(Server::WorkerRemoveClient, event->GetClient(), WT_EXECUTEDEFAULT) == false) 379 | { 380 | ERROR_CODE(GetLastError(), "can't start WorkerRemoveClient. call it directly."); 381 | 382 | WorkerRemoveClient(event->GetClient()); 383 | } 384 | } 385 | 386 | 387 | void Server::AddClient(Client* client) 388 | { 389 | assert(client); 390 | 391 | // The socket sAcceptSocket does not inherit the properties of the socket associated with sListenSocket parameter until SO_UPDATE_ACCEPT_CONTEXT is set on the socket. 392 | if (setsockopt(client->GetSocket(), SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, reinterpret_cast(&m_listenSocket), sizeof(m_listenSocket)) == SOCKET_ERROR) 393 | { 394 | ERROR_CODE(WSAGetLastError(), "setsockopt() for AcceptEx() failed."); 395 | 396 | RemoveClient(client); 397 | } 398 | else 399 | { 400 | client->SetState(Client::ACCEPTED); 401 | 402 | // Connect the socket to IOCP 403 | if(false == BindIoCompletionCallback(reinterpret_cast(client->GetSocket()), Server::OnIOCompletion, 0)) 404 | { 405 | ERROR_CODE(GetLastError(), "Could not assign the socket to the IOCP handle."); 406 | 407 | RemoveClient(client); 408 | } 409 | else 410 | { 411 | std::string ip; 412 | u_short port = 0; 413 | Network::GetRemoteAddress(client->GetSocket(), ip, port); 414 | TRACE("[%d] Accept succeeded. client address : ip[%s], port[%d]", GetCurrentThreadId(), ip.c_str(), port); 415 | 416 | EnterCriticalSection(&m_CSForClients); 417 | m_Clients.push_back(client); 418 | LeaveCriticalSection(&m_CSForClients); 419 | 420 | PostRecv(client); 421 | } 422 | } 423 | } 424 | 425 | 426 | void Server::RemoveClient(Client* client) 427 | { 428 | assert(client); 429 | 430 | EnterCriticalSection(&m_CSForClients); 431 | 432 | ClientList::iterator itor = std::remove(m_Clients.begin(), m_Clients.end(), client); 433 | 434 | if(itor != m_Clients.end()) 435 | { 436 | TRACE("[%d] RemoveClient succeeded.", GetCurrentThreadId()); 437 | 438 | Client::Destroy(client); 439 | 440 | m_Clients.erase(itor); 441 | } 442 | 443 | LeaveCriticalSection(&m_CSForClients); 444 | } 445 | 446 | 447 | void Server::Echo(Packet* packet) 448 | { 449 | assert(packet); 450 | assert(packet->GetSender()); 451 | 452 | EnterCriticalSection(&m_CSForClients); 453 | 454 | ClientList::iterator itor = std::find(m_Clients.begin(), m_Clients.end(), packet->GetSender()); 455 | 456 | if( itor == m_Clients.end()) 457 | { 458 | // No client to send it back. 459 | Packet::Destroy(packet); 460 | } 461 | else 462 | { 463 | PostSend(packet->GetSender(), packet); 464 | } 465 | 466 | LeaveCriticalSection(&m_CSForClients); 467 | } 468 | 469 | 470 | size_t Server::GetNumClients() 471 | { 472 | EnterCriticalSection(&m_CSForClients); 473 | 474 | size_t num = m_Clients.size(); 475 | 476 | LeaveCriticalSection(&m_CSForClients); 477 | 478 | return num; 479 | } 480 | 481 | long Server::GetNumPostAccepts() 482 | { 483 | return m_NumPostAccept; 484 | } 485 | -------------------------------------------------------------------------------- /IOCP - NewThreadPool/Server/Server.cpp: -------------------------------------------------------------------------------- 1 | #include "Server.h" 2 | #include "Client.h" 3 | #include "Packet.h" 4 | #include "IOEvent.h" 5 | 6 | #include "..\Log.h" 7 | #include "..\Network.h" 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | 15 | //---------------------------------------------------------------------------------// 16 | //---------------------------------------------------------------------------------// 17 | /* static */ void CALLBACK Server::IoCompletionCallback(PTP_CALLBACK_INSTANCE /* Instance */, PVOID /* Context */, 18 | PVOID Overlapped, ULONG IoResult, ULONG_PTR NumberOfBytesTransferred, PTP_IO /* Io */) 19 | { 20 | IOEvent* event = CONTAINING_RECORD(Overlapped, IOEvent, GetOverlapped()); 21 | assert(event); 22 | 23 | if(IoResult != ERROR_SUCCESS) 24 | { 25 | ERROR_CODE(IoResult, "I/O operation failed. type[%d]", event->GetType()); 26 | 27 | switch(event->GetType()) 28 | { 29 | case IOEvent::SEND: 30 | Server::Instance()->OnSend(event, NumberOfBytesTransferred); 31 | break; 32 | } 33 | 34 | Server::Instance()->OnClose(event); 35 | } 36 | else 37 | { 38 | switch(event->GetType()) 39 | { 40 | case IOEvent::ACCEPT: 41 | Server::Instance()->OnAccept(event); 42 | break; 43 | 44 | case IOEvent::RECV: 45 | if(NumberOfBytesTransferred > 0) 46 | { 47 | Server::Instance()->OnRecv(event, NumberOfBytesTransferred); 48 | } 49 | else 50 | { 51 | Server::Instance()->OnClose(event); 52 | } 53 | break; 54 | 55 | case IOEvent::SEND: 56 | Server::Instance()->OnSend(event, NumberOfBytesTransferred); 57 | break; 58 | 59 | default: assert(false); break; 60 | } 61 | } 62 | 63 | IOEvent::Destroy(event); 64 | } 65 | 66 | 67 | void CALLBACK Server::WorkerPostAccept(PTP_CALLBACK_INSTANCE /* Instance */, PVOID Context, PTP_WORK /* Work */) 68 | { 69 | Server* server = static_cast(Context); 70 | assert(server); 71 | 72 | while(!server->m_ShuttingDown) 73 | { 74 | server->PostAccept(); 75 | } 76 | } 77 | 78 | 79 | void CALLBACK Server::WorkerAddClient(PTP_CALLBACK_INSTANCE /* Instance */, PVOID Context) 80 | { 81 | Client* client = static_cast(Context); 82 | assert(client); 83 | 84 | Server::Instance()->AddClient(client); 85 | } 86 | 87 | 88 | void CALLBACK Server::WorkerRemoveClient(PTP_CALLBACK_INSTANCE /* Instance */, PVOID Context) 89 | { 90 | Client* client = static_cast(Context); 91 | assert(client); 92 | 93 | Server::Instance()->RemoveClient(client); 94 | } 95 | 96 | 97 | void CALLBACK Server::WorkerProcessRecvPacket(PTP_CALLBACK_INSTANCE /* Instance */, PVOID Context) 98 | { 99 | Packet* packet = static_cast(Context); 100 | assert(packet); 101 | 102 | Server::Instance()->Echo(packet); 103 | } 104 | 105 | 106 | //---------------------------------------------------------------------------------// 107 | //---------------------------------------------------------------------------------// 108 | Server::Server(void) 109 | : m_pTPIO(NULL), 110 | m_AcceptTPWORK(NULL), 111 | m_listenSocket(INVALID_SOCKET), 112 | m_MaxPostAccept(0), 113 | m_NumPostAccept(0), 114 | m_ClientTPCLEAN(NULL), 115 | m_ShuttingDown(true) 116 | { 117 | } 118 | 119 | 120 | Server::~Server(void) 121 | { 122 | Destroy(); 123 | } 124 | 125 | 126 | bool Server::Create(short port, int maxPostAccept) 127 | { 128 | assert(maxPostAccept > 0); 129 | 130 | m_MaxPostAccept = maxPostAccept; 131 | 132 | // Create Client Work Thread Env for using cleaning group. We need this for shutting down properly. 133 | InitializeThreadpoolEnvironment(&m_ClientTPENV); 134 | m_ClientTPCLEAN = CreateThreadpoolCleanupGroup(); 135 | if (m_ClientTPCLEAN == NULL) 136 | { 137 | ERROR_CODE(GetLastError(), "Could not create client cleaning group."); 138 | return false; 139 | } 140 | SetThreadpoolCallbackCleanupGroup(&m_ClientTPENV, m_ClientTPCLEAN, NULL); 141 | 142 | // Create Listen Socket 143 | m_listenSocket = Network::CreateSocket(true, port); 144 | if(m_listenSocket == INVALID_SOCKET) 145 | { 146 | return false; 147 | } 148 | 149 | // Make the address re-usable to re-run the same server instantly. 150 | bool reuseAddr = true; 151 | if(setsockopt(m_listenSocket, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast(&reuseAddr), sizeof(reuseAddr)) == SOCKET_ERROR) 152 | { 153 | ERROR_CODE(WSAGetLastError(), "setsockopt() failed with SO_REUSEADDR."); 154 | Destroy(); 155 | return false; 156 | } 157 | 158 | // Create & Start ThreaddPool for socket IO 159 | m_pTPIO = CreateThreadpoolIo(reinterpret_cast(m_listenSocket), Server::IoCompletionCallback, NULL, NULL); 160 | if( m_pTPIO == NULL ) 161 | { 162 | ERROR_CODE(WSAGetLastError(), "Could not assign the listen socket to the IOCP handle."); 163 | Destroy(); 164 | return false; 165 | } 166 | 167 | // Start listening 168 | StartThreadpoolIo( m_pTPIO ); 169 | if(listen(m_listenSocket, SOMAXCONN) == SOCKET_ERROR) 170 | { 171 | ERROR_CODE(WSAGetLastError(), "listen() failed."); 172 | return false; 173 | } 174 | 175 | // Create critical sections for m_Clients 176 | InitializeCriticalSection(&m_CSForClients); 177 | 178 | // Create Accept worker 179 | m_AcceptTPWORK = CreateThreadpoolWork(Server::WorkerPostAccept, this, NULL); 180 | if(m_AcceptTPWORK == NULL) 181 | { 182 | ERROR_CODE(GetLastError(), "Could not create AcceptEx worker TPIO."); 183 | Destroy(); 184 | return false; 185 | } 186 | 187 | m_ShuttingDown = false; 188 | 189 | SubmitThreadpoolWork(m_AcceptTPWORK); 190 | 191 | return true; 192 | } 193 | 194 | 195 | void Server::Destroy() 196 | { 197 | m_ShuttingDown = true; 198 | 199 | if( m_AcceptTPWORK != NULL ) 200 | { 201 | WaitForThreadpoolWorkCallbacks( m_AcceptTPWORK, true ); 202 | CloseThreadpoolWork( m_AcceptTPWORK ); 203 | m_AcceptTPWORK = NULL; 204 | } 205 | 206 | if( m_listenSocket != INVALID_SOCKET ) 207 | { 208 | Network::CloseSocket(m_listenSocket); 209 | CancelIoEx(reinterpret_cast(m_listenSocket), NULL); 210 | m_listenSocket = INVALID_SOCKET; 211 | } 212 | 213 | if( m_pTPIO != NULL ) 214 | { 215 | WaitForThreadpoolIoCallbacks( m_pTPIO, true ); 216 | CloseThreadpoolIo( m_pTPIO ); 217 | m_pTPIO = NULL; 218 | } 219 | 220 | if (m_ClientTPCLEAN != NULL) 221 | { 222 | CloseThreadpoolCleanupGroupMembers(m_ClientTPCLEAN, false, NULL); 223 | CloseThreadpoolCleanupGroup(m_ClientTPCLEAN); 224 | DestroyThreadpoolEnvironment(&m_ClientTPENV); 225 | m_ClientTPCLEAN = NULL; 226 | } 227 | 228 | EnterCriticalSection(&m_CSForClients); 229 | for(ClientList::iterator itor = m_Clients.begin() ; itor != m_Clients.end() ; ++itor) 230 | { 231 | Client::Destroy(*itor); 232 | } 233 | m_Clients.clear(); 234 | LeaveCriticalSection(&m_CSForClients); 235 | 236 | 237 | DeleteCriticalSection(&m_CSForClients); 238 | } 239 | 240 | 241 | void Server::PostAccept() 242 | { 243 | // If the number of clients is too big, we can just stop posting aceept. 244 | // That's one of the benefits from AcceptEx. 245 | int count = m_MaxPostAccept - m_NumPostAccept; 246 | if( count > 0 ) 247 | { 248 | int i = 0; 249 | for( ; i < count ; ++i ) 250 | { 251 | Client* client = Client::Create(); 252 | if( !client ) 253 | { 254 | break; 255 | } 256 | 257 | IOEvent* event = IOEvent::Create(IOEvent::ACCEPT, client); 258 | assert(event); 259 | 260 | StartThreadpoolIo( m_pTPIO ); 261 | if ( FALSE == Network::AcceptEx(m_listenSocket, client->GetSocket(), &event->GetOverlapped())) 262 | { 263 | int error = WSAGetLastError(); 264 | 265 | if(error != ERROR_IO_PENDING) 266 | { 267 | CancelThreadpoolIo( m_pTPIO ); 268 | 269 | ERROR_CODE(error, "AcceptEx() failed."); 270 | Client::Destroy(client); 271 | IOEvent::Destroy(event); 272 | break; 273 | } 274 | } 275 | else 276 | { 277 | OnAccept(event); 278 | IOEvent::Destroy(event); 279 | } 280 | } 281 | 282 | InterlockedExchangeAdd(&m_NumPostAccept, i); 283 | 284 | TRACE("[%d] Post AcceptEx : %d", GetCurrentThreadId(), m_NumPostAccept); 285 | } 286 | } 287 | 288 | 289 | void Server::PostRecv(Client* client) 290 | { 291 | assert(client); 292 | 293 | WSABUF recvBufferDescriptor; 294 | recvBufferDescriptor.buf = reinterpret_cast(client->GetRecvBuff()); 295 | recvBufferDescriptor.len = Client::MAX_RECV_BUFFER; 296 | 297 | DWORD numberOfBytes = 0; 298 | DWORD recvFlags = 0; 299 | 300 | IOEvent* event = IOEvent::Create(IOEvent::RECV, client); 301 | assert(event); 302 | 303 | StartThreadpoolIo(client->GetTPIO()); 304 | 305 | if(WSARecv(client->GetSocket(), &recvBufferDescriptor, 1, &numberOfBytes, &recvFlags, &event->GetOverlapped(), NULL) == SOCKET_ERROR) 306 | { 307 | int error = WSAGetLastError(); 308 | 309 | if(error != ERROR_IO_PENDING) 310 | { 311 | CancelThreadpoolIo(client->GetTPIO()); 312 | 313 | ERROR_CODE(error, "WSARecv() failed."); 314 | 315 | OnClose(event); 316 | IOEvent::Destroy(event); 317 | } 318 | } 319 | else 320 | { 321 | // In this case, the completion callback will have already been scheduled to be called. 322 | } 323 | } 324 | 325 | 326 | void Server::PostSend(Client* client, Packet* packet) 327 | { 328 | assert(client); 329 | assert(packet); 330 | 331 | WSABUF recvBufferDescriptor; 332 | recvBufferDescriptor.buf = reinterpret_cast(packet->GetData()); 333 | recvBufferDescriptor.len = packet->GetSize(); 334 | 335 | DWORD sendFlags = 0; 336 | 337 | IOEvent* event = IOEvent::Create(IOEvent::SEND, client, packet); 338 | assert(event); 339 | 340 | StartThreadpoolIo(client->GetTPIO()); 341 | 342 | if(WSASend(client->GetSocket(), &recvBufferDescriptor, 1, NULL, sendFlags, &event->GetOverlapped(), NULL) == SOCKET_ERROR) 343 | { 344 | int error = WSAGetLastError(); 345 | 346 | if(error != ERROR_IO_PENDING) 347 | { 348 | CancelThreadpoolIo(client->GetTPIO()); 349 | 350 | ERROR_CODE(error, "WSASend() failed."); 351 | 352 | RemoveClient(client); 353 | } 354 | } 355 | else 356 | { 357 | // In this case, the completion callback will have already been scheduled to be called. 358 | } 359 | } 360 | 361 | 362 | void Server::OnAccept(IOEvent* event) 363 | { 364 | assert(event); 365 | 366 | TRACE("[%d] Enter OnAccept()", GetCurrentThreadId()); 367 | assert(event->GetType() == IOEvent::ACCEPT); 368 | 369 | // Check if we need to post more accept requests. 370 | InterlockedDecrement(&m_NumPostAccept); 371 | 372 | // Add client in a different thread. 373 | // It is because we need to return this function ASAP so that this IO worker thread can process the other IO notifications. 374 | // If adding client is fast enough, we can call it here but I assume it's slow. 375 | if(!m_ShuttingDown && TrySubmitThreadpoolCallback(Server::WorkerAddClient, event->GetClient(), &m_ClientTPENV) == false) 376 | { 377 | ERROR_CODE(GetLastError(), "Could not start WorkerAddClient."); 378 | 379 | AddClient(event->GetClient()); 380 | } 381 | 382 | TRACE("[%d] Leave OnAccept()", GetCurrentThreadId()); 383 | } 384 | 385 | 386 | void Server::OnRecv(IOEvent* event, DWORD dwNumberOfBytesTransfered) 387 | { 388 | assert(event); 389 | 390 | TRACE("[%d] Enter OnRecv()", GetCurrentThreadId()); 391 | 392 | BYTE* buff = event->GetClient()->GetRecvBuff(); 393 | buff[dwNumberOfBytesTransfered] = '\0'; 394 | TRACE("[%d] OnRecv : %s", GetCurrentThreadId(), buff); 395 | 396 | // Create packet by copying recv buff. 397 | Packet* packet = Packet::Create(event->GetClient(), event->GetClient()->GetRecvBuff(), dwNumberOfBytesTransfered); 398 | 399 | // If whatever game logics relying on the packet are fast enough, we can manage them here but I assume they are slow. 400 | // I think it's better to request receiving ASAP and handle packets received in another thread. 401 | if(TrySubmitThreadpoolCallback(Server::WorkerProcessRecvPacket, packet, NULL) == false) 402 | { 403 | ERROR_CODE(GetLastError(), "Could not start WorkerProcessRecvPacket. call it directly."); 404 | 405 | Echo(packet); 406 | } 407 | 408 | PostRecv(event->GetClient()); 409 | 410 | TRACE("[%d] Leave OnRecv()", GetCurrentThreadId()); 411 | } 412 | 413 | 414 | void Server::OnSend(IOEvent* event, DWORD dwNumberOfBytesTransfered) 415 | { 416 | assert(event); 417 | 418 | TRACE("[%d] OnSend : %d", GetCurrentThreadId(), dwNumberOfBytesTransfered); 419 | 420 | // This should be fast enough to do in this I/O thread. 421 | // if not, we need to queue it like what we do in OnRecv(). 422 | Packet::Destroy(event->GetPacket()); 423 | } 424 | 425 | 426 | void Server::OnClose(IOEvent* event) 427 | { 428 | assert(event); 429 | 430 | TRACE("Client's socket has been closed."); 431 | 432 | // If whatever game logics about this event are fast enough, we can manage them here but I assume they are slow. 433 | if(!m_ShuttingDown && TrySubmitThreadpoolCallback(Server::WorkerRemoveClient, event->GetClient(), &m_ClientTPENV) == false) 434 | { 435 | ERROR_CODE(GetLastError(), "can't start WorkerRemoveClient. call it directly."); 436 | 437 | RemoveClient(event->GetClient()); 438 | } 439 | } 440 | 441 | 442 | void Server::AddClient(Client* client) 443 | { 444 | assert(client); 445 | 446 | // The socket sAcceptSocket does not inherit the properties of the socket associated with sListenSocket parameter until SO_UPDATE_ACCEPT_CONTEXT is set on the socket. 447 | if (setsockopt(client->GetSocket(), SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, reinterpret_cast(&m_listenSocket), sizeof(m_listenSocket)) == SOCKET_ERROR) 448 | { 449 | ERROR_CODE(WSAGetLastError(), "setsockopt() for AcceptEx() failed."); 450 | 451 | RemoveClient(client); 452 | } 453 | else 454 | { 455 | client->SetState(Client::ACCEPTED); 456 | 457 | // Connect the socket to IOCP 458 | TP_IO* pTPIO = CreateThreadpoolIo(reinterpret_cast(client->GetSocket()), Server::IoCompletionCallback, NULL, NULL); 459 | if(pTPIO == NULL) 460 | { 461 | ERROR_CODE(GetLastError(), "CreateThreadpoolIo failed for a client."); 462 | 463 | RemoveClient(client); 464 | } 465 | else 466 | { 467 | std::string ip; 468 | u_short port = 0; 469 | Network::GetRemoteAddress(client->GetSocket(), ip, port); 470 | TRACE("[%d] Accept succeeded. client address : ip[%s], port[%d]", GetCurrentThreadId(), ip.c_str(), port); 471 | 472 | client->SetTPIO(pTPIO); 473 | 474 | EnterCriticalSection(&m_CSForClients); 475 | m_Clients.push_back(client); 476 | LeaveCriticalSection(&m_CSForClients); 477 | 478 | PostRecv(client); 479 | } 480 | } 481 | } 482 | 483 | 484 | void Server::RemoveClient(Client* client) 485 | { 486 | assert(client); 487 | 488 | EnterCriticalSection(&m_CSForClients); 489 | 490 | ClientList::iterator itor = std::remove(m_Clients.begin(), m_Clients.end(), client); 491 | 492 | if(itor != m_Clients.end()) 493 | { 494 | TRACE("[%d] RemoveClient succeeded.", GetCurrentThreadId()); 495 | 496 | Client::Destroy(client); 497 | 498 | m_Clients.erase(itor); 499 | } 500 | 501 | LeaveCriticalSection(&m_CSForClients); 502 | } 503 | 504 | 505 | void Server::Echo(Packet* packet) 506 | { 507 | assert(packet); 508 | assert(packet->GetSender()); 509 | 510 | EnterCriticalSection(&m_CSForClients); 511 | 512 | ClientList::iterator itor = std::find(m_Clients.begin(), m_Clients.end(), packet->GetSender()); 513 | 514 | if( itor == m_Clients.end()) 515 | { 516 | // No client to send it back. 517 | Packet::Destroy(packet); 518 | } 519 | else 520 | { 521 | PostSend(packet->GetSender(), packet); 522 | } 523 | 524 | LeaveCriticalSection(&m_CSForClients); 525 | } 526 | 527 | 528 | size_t Server::GetNumClients() 529 | { 530 | EnterCriticalSection(&m_CSForClients); 531 | 532 | size_t num = m_Clients.size(); 533 | 534 | LeaveCriticalSection(&m_CSForClients); 535 | 536 | return num; 537 | } 538 | 539 | long Server::GetNumPostAccepts() 540 | { 541 | return m_NumPostAccept; 542 | } 543 | --------------------------------------------------------------------------------