// // Player 是指已經通過網絡連接進入服務器端程序的客戶 // // // #ifndef __PLAYER_H__ #define __PLAYER_H__ #include "Type.h" #include "Socket.h" #include "SocketInputStream.h" #include "SocketOutputStream.h" #include "Packet.h" #define MAX_CACHE_SIZE 1024 //如果在一定時間內沒有收到任何消息,則斷開此客戶端的網絡連接 #define MAX_KICK_TIME 300000 //排隊消息發送時間 #define MAX_TRUN_MESSAGE_TIME 5000 enum PACKET_FLAG { PF_NONE=0 , PF_REMOVE , }; struct ASYNC_PACKET { Packet* m_pPacket ; PlayerID_t m_PlayerID ; uint m_Flag ; ASYNC_PACKET( ) { m_pPacket = NULL ; m_PlayerID = INVALID_ID ; m_Flag = PF_NONE ; }; ~ASYNC_PACKET( ) { SAFE_DELETE( m_pPacket ) ; m_PlayerID = INVALID_ID ; m_Flag = PF_NONE ; }; }; class Player { public : Player( BOOL bIsServer=FALSE ) ; ~Player( ) ; //從緩衝區中取數據 virtual BOOL ProcessInput( ) ; //打包數據放入緩衝區 virtual BOOL ProcessOutput( ) ; virtual BOOL ProcessCommand( BOOL Option = TRUE ) ; virtual BOOL HeartBeat( UINT uTime=0 ) ; virtual BOOL SendPacket( Packet* pPacket ) ; virtual VOID Encrypt_SC(CHAR* header, UINT uLen, UINT uBeginPlace)=0; virtual VOID DecryptHead_CS(CHAR* header)=0; virtual VOID Decrypt_CS(CHAR* header, UINT uLen, UINT uBeginPlace)=0; public : //通用接口 virtual BOOL IsLoginPlayer( )=0 ; virtual BOOL IsServerPlayer( )=0 ; //用於網通電信互聯,判斷是不是使用代理服務器的用戶和使用哪個代理服務器的用戶 //INT WhereThisPlayerFrom(VOID) const; //讀取設置玩家PID的接口,PlayerID 是由PlayerPool類分配出來的索引值 //PlayerID用於標識一個客戶端連接在整個系統中的數據位置信息 PlayerID_t PlayerID(){ return m_PID ; } ; VOID SetPlayerID( PlayerID_t id ){ m_PID = id ; } ; //讀取設置玩家UID的接口,UserID 是由UserPool類分配出來的索引值 //UserID用於標識玩家的遊戲存儲位置信息 ID_t UserID(){ return m_UID ; } ; VOID SetUserID( ID_t id ){ m_UID = id ; } ; //讀取設置玩家PMID的接口,PlayerManagerID 是由PlayerManager類分配出來的索引值 //PlayerManagerID用於標識當前玩家所在的某個PlayerManager中的位置信息,每個 //PlayerManager位於一個獨立的線程裏。 ID_t PlayerManagerID(){ return m_PlayerManagerID ; } ; VOID SetPlayerManagerID( ID_t id ){ m_PlayerManagerID = id ; } ; //讀取當前玩家的Socket類 //網絡連接接口 Socket* GetSocket(){ return m_pSocket ; } ; //斷開與當前玩家的網絡連接 virtual VOID Disconnect( ) ; //判斷當前玩家的網絡連接是否有效 virtual BOOL IsValid( ) ; //清除當前玩家網絡連接數據和緩存數據 virtual VOID CleanUp( ) ; //判斷當前玩家數據塊是否是空塊; //如果是空塊,則可以被PlayerPool分配出去用於接收新連接 BOOL IsEmpty( ) { return m_IsEmpty ; } VOID SetEmpty( BOOL opt = TRUE ) { m_IsEmpty = opt ; } BOOL IsDisconnect( ) { return m_IsDisconnect ; } VOID SetDisconnect( BOOL opt = TRUE ) { m_IsDisconnect = opt ; } virtual VOID ResetKick( ) ; private : BOOL m_IsEmpty ; BOOL m_IsDisconnect ; protected : //Player ID //統一由PlayerPool管理 PlayerID_t m_PID ; //User ID //統一由UserPool管理 ID_t m_UID ; //在PlayerManager類中player id數組的下標 ID_t m_PlayerManagerID ; //網絡連接句柄 Socket* m_pSocket ; //輸入輸出數據緩存 SocketInputStream* m_pSocketInputStream ; SocketOutputStream* m_pSocketOutputStream ; BYTE m_PacketIndex ; }; //CHAR* ProxyTool_GetCorrespondingIP(Player const* pPlayer, ID_t ServerID); //UINT ProxyTool_GetCorrespondingPort(Player const* pPlayer, ID_t ServerID); #endif
#include "stdafx.h" #include "Player.h" #include "Socket.h" #include "PacketFactoryManager.h" #include "TimeManager.h" #include "Log.h" using namespace Packets ; Player::Player( BOOL bIsServer ) { __ENTER_FUNCTION m_PID = INVALID_ID ; m_UID = INVALID_ID ; m_PlayerManagerID = INVALID_ID ; m_pSocket = new Socket ; Assert( m_pSocket ) ; if( bIsServer ) { m_pSocketInputStream = new SocketInputStream( m_pSocket,DEFAULTSOCKETINPUTBUFFERSIZE,64*1024*1024 ) ; Assert( m_pSocketInputStream ) ; m_pSocketOutputStream = new SocketOutputStream( m_pSocket,DEFAULTSOCKETOUTPUTBUFFERSIZE,64*1024*1024 ) ; Assert( m_pSocketOutputStream ) ; } else { m_pSocketInputStream = new SocketInputStream( m_pSocket ) ; Assert( m_pSocketInputStream ) ; m_pSocketOutputStream = new SocketOutputStream( m_pSocket ) ; Assert( m_pSocketOutputStream ) ; } m_IsEmpty = TRUE ; m_IsDisconnect = FALSE ; m_PacketIndex = 0 ; __LEAVE_FUNCTION } Player::~Player( ) { __ENTER_FUNCTION SAFE_DELETE( m_pSocketInputStream ) ; SAFE_DELETE( m_pSocketOutputStream ) ; SAFE_DELETE( m_pSocket ) ; __LEAVE_FUNCTION } VOID Player::CleanUp( ) { __ENTER_FUNCTION m_pSocket->close() ; m_pSocketInputStream->CleanUp() ; m_pSocketOutputStream->CleanUp() ; SetPlayerManagerID( INVALID_ID ) ; SetUserID( INVALID_ID ) ; m_PacketIndex = 0 ; SetDisconnect(FALSE) ; __LEAVE_FUNCTION } VOID Player::Disconnect( ) { __ENTER_FUNCTION _MY_TRY { m_pSocket->close() ; } _MY_CATCH { } __LEAVE_FUNCTION } BOOL Player::IsValid( ) { __ENTER_FUNCTION if( m_pSocket==NULL ) return FALSE ; if( !m_pSocket->isValid() ) return FALSE ; return TRUE ; __LEAVE_FUNCTION return FALSE ; } BOOL Player::ProcessInput( ) { __ENTER_FUNCTION if( IsDisconnect() ) return TRUE ; _MY_TRY { uint ret = m_pSocketInputStream->Fill( ) ; if( (INT)ret <= SOCKET_ERROR ) { Log::SaveLog( "./Log/LoginError.log", "[%d] m_pSocketInputStream->Fill ret:%d %s", g_pTimeManager->Time2DWORD(), (INT)ret, MySocketError() ) ; return FALSE ; } } _MY_CATCH { return FALSE ; } return TRUE ; __LEAVE_FUNCTION return FALSE ; } BOOL Player::ProcessCommand( BOOL Option ) { __ENTER_FUNCTION BOOL ret ; //包頭組成:消息包ID;包大小;包索引,packetuint還不知道幹啥用的 CHAR header[PACKET_HEADER_SIZE]; PacketID_t packetID; uint packetuint, packetSize, packetIndex; WORD packetTick; Packet* pPacket = NULL ; if( IsDisconnect( ) ) return TRUE ; _MY_TRY { if( Option ) {//執行部分選項操作 } for( ;; ) { if( !m_pSocketInputStream->Peek(&header[0], PACKET_HEADER_SIZE) ) {//數據不能填充消息頭 break ; } this->DecryptHead_CS(header);//封包頭解密 //分別獲取包頭的基本信息 memcpy( &packetID, &header[0], sizeof(PacketID_t) ) ; memcpy( &packetTick, &header[sizeof(WORD)], sizeof(WORD) ) ; memcpy( &packetuint, &header[sizeof(WORD)+sizeof(PacketID_t)], sizeof(uint) ); packetSize = GET_PACKET_LEN(packetuint) ; packetIndex = GET_PACKET_INDEX(packetuint) ; if( packetID >= (PacketID_t)PACKET_MAX ) {//無效的消息類型 Assert( FALSE ) ; return FALSE ; } //消息解密處理--Begin { //獲取緩衝區的各個屬性 UINT t_uSize = packetSize+PACKET_HEADER_SIZE; UINT t_uHead = m_pSocketInputStream->GetHead(); UINT t_uTail = m_pSocketInputStream->GetTail(); UINT t_uBufferLen = m_pSocketInputStream->GetBuffLen(); CHAR* t_szBuffer = m_pSocketInputStream->GetBuff(); //如果緩衝區的讀指針 小於 寫指針,數據未讀完,寫指針還未到緩衝區尾部 if ( t_uHead < t_uTail ) { //緩衝區的起始位置開始,進行包解密,包括包頭和包的內容 this->Decrypt_CS(&t_szBuffer[t_uHead], t_uSize, 0); } //否則的話,t_uHead >= t_uTail 可能的情況:寫指針已經寫到緩衝區尾,然後從緩衝區頭開始寫,讀指針已經讀取了一部分數據 else { //計算到緩衝區尾還有多少數據沒有讀 UINT rightLen = t_uBufferLen - t_uHead ; //如果到緩衝區尾部已經有足夠的數據可讀,那麼開始解密;否則,解密完這部分數據後,再從緩衝區頭開始解密其他部分的數據 if( t_uSize <= rightLen ) { this->Decrypt_CS(&t_szBuffer[t_uHead], t_uSize, 0); } else { this->Decrypt_CS(&t_szBuffer[t_uHead], rightLen, 0); this->Decrypt_CS(t_szBuffer, t_uSize-rightLen, rightLen); } } } //消息解密處理--End _MY_TRY { //如果緩衝區內的數據的大小還沒一個包數據的大小,則表示數據沒有接完,等待套接字數據 if( m_pSocketInputStream->Length()<PACKET_HEADER_SIZE+packetSize ) {//消息沒有接收全 break; } if( packetSize>g_pPacketFactoryManager->GetPacketMaxSize(packetID) ) {//消息的大小出現異常,收到的消息比預定義消息的最大值還要大 Assert( FALSE ) ; // m_pSocketInputStream->Skip( PACKET_HEADER_SIZE+packetSize ) ; return FALSE ; } //使用工廠方法的設計模式,創建一個包的產品實例 Packet* pPacket = g_pPacketFactoryManager->CreatePacket( packetID ) ; if( pPacket==NULL ) {//不能分配到足夠的內存 Assert( FALSE ) ; // m_pSocketInputStream->Skip( PACKET_HEADER_SIZE+packetSize ) ; return FALSE ; } //設置消息序列號 pPacket->SetPacketIndex( packetIndex ) ; ret = m_pSocketInputStream->ReadPacket( pPacket ) ; if( ret==FALSE ) {//讀取消息內容錯誤 Assert( FALSE ) ; g_pPacketFactoryManager->RemovePacket( pPacket ) ; return FALSE ; } BOOL bNeedRemove = TRUE ; _MY_TRY { //修正m_KickTime信息,m_KickTime信息中的值爲判斷是否需要踢掉 //客戶端的依據 this->ResetKick( ) ; //此處玩家處理客戶端的包需求的行爲,一切都是爲了這個目的 uint uret = pPacket->Execute( this ) ; if( uret==PACKET_EXE_ERROR ) {//出現異常錯誤,斷開此玩家連接 if( pPacket ) g_pPacketFactoryManager->RemovePacket( pPacket ) ; return FALSE ; } else if( uret==PACKET_EXE_BREAK ) {//當前消息的解析執行將停止 //直到下個循環時才繼續對緩存中的數據進行消息格式 //化和執行。 //當需要將客戶端的執行從一個場景轉移到另外一個場景時: //需要在發送轉移消息後將執行在本線程中停止。 if( pPacket ) g_pPacketFactoryManager->RemovePacket( pPacket ) ; break ; } else if( uret==PACKET_EXE_CONTINUE ) {//繼續解析剩下的消息 } else if( uret==PACKET_EXE_NOTREMOVE ) {//繼續解析剩下的消息,並且不回收當前消息 bNeedRemove = FALSE ; } else if( uret == PACKET_EXE_NOTREMOVE_ERROR ) { return FALSE ; } else {//未知的返回值 Assert(FALSE) ; } } _MY_CATCH { } if( pPacket && bNeedRemove ) g_pPacketFactoryManager->RemovePacket( pPacket ) ; } _MY_CATCH { return FALSE; } } } _MY_CATCH { } return TRUE ; __LEAVE_FUNCTION return FALSE ; } BOOL Player::ProcessOutput( ) { __ENTER_FUNCTION if( IsDisconnect( ) ) return TRUE ; _MY_TRY { uint size = m_pSocketOutputStream->Length() ; if( size==0 ) { return TRUE ; } uint ret = m_pSocketOutputStream->Flush( ) ; if( (INT)ret <= SOCKET_ERROR ) { Log::SaveLog( "./Log/LoginError.log", "[%d] m_pSocketOutputStream->Flush ret:%d %s", g_pTimeManager->Time2DWORD(), (INT)ret, MySocketError() ) ; return FALSE ; } } _MY_CATCH { return FALSE ; } return TRUE ; __LEAVE_FUNCTION return FALSE ; } BOOL Player::SendPacket( Packet* pPacket ) { __ENTER_FUNCTION //判斷套接字連接是否正常 if( IsDisconnect( ) ) return TRUE ; if( m_pSocketOutputStream!=NULL ) { //設置包索引 pPacket->SetPacketIndex( m_PacketIndex++ ) ; //設置包ID PacketID_t packetID = pPacket->GetPacketID() ; UINT w; //包ID是否合法,如果是,則先向緩衝區中寫入包分隔符 if ( packetID < PACKET_LC_MAXCOUNT) { w = m_pSocketOutputStream->Write( PACK_COMPART , PACK_COMPART_SIZE ) ; } //獲取緩衝區的寫指針的位置,作爲開始寫的位置 UINT t_uTail_Begin = m_pSocketOutputStream->GetTail();//查詢當前包尾位置。記錄寫包前位置 //先寫入包頭的包ID w = m_pSocketOutputStream->Write( (CHAR*)&packetID , sizeof(PacketID_t) ) ; //獲取時間戳,並寫入緩衝區 WORD packetTick = g_pTimeManager->RunTick(); w = m_pSocketOutputStream->Write( (CHAR*)&packetTick , sizeof(WORD) ) ; //再繼續寫入包索引和包大小 UINT packetUINT ; UINT packetSize = pPacket->GetPacketSize( ) ; UINT packetIndex = pPacket->GetPacketIndex( ) ; SET_PACKET_INDEX(packetUINT, packetIndex) ; SET_PACKET_LEN(packetUINT, packetSize) ; w = m_pSocketOutputStream->Write( (CHAR*)&packetUINT, sizeof(UINT) ) ; //向緩衝區寫入包的內容 BOOL ret = pPacket->Write( *m_pSocketOutputStream ) ; UINT t_uTail_End = m_pSocketOutputStream->GetTail();//查詢當前包尾位置。記錄寫包後位置 //消息加密處理--Begin { //分別計算緩衝區的屬性 //數據大小,寫指針位置,讀指針位置,緩衝區長度,緩衝區指針 UINT t_uSize = t_uTail_End - t_uTail_Begin; UINT t_uHead = m_pSocketOutputStream->GetHead(); UINT t_uTail = m_pSocketOutputStream->GetTail(); UINT t_uBufferLen = m_pSocketOutputStream->GetBuffLen(); CHAR* t_szBuffer = m_pSocketOutputStream->GetBuff(); //加密 if ( t_uHead < t_uTail ) { this->Encrypt_SC(&(t_szBuffer[t_uTail_Begin]), t_uSize, 0); } else { UINT rightLen = t_uBufferLen - t_uHead ; //包加密 if( t_uSize <= rightLen ) { this->Encrypt_SC(&(t_szBuffer[t_uTail_Begin]), t_uSize, 0); } else { this->Encrypt_SC(&(t_szBuffer[t_uTail_Begin]), rightLen, 0); this->Encrypt_SC(t_szBuffer, t_uSize-rightLen, rightLen); } } } //消息加密處理--End //BOOL ret = m_pSocketOutputStream->WritePacket( pPacket ) ; Assert( ret ) ; //Log::SaveLog( "./Log/LoginDebug.log", "SendPacket! SOCKET=%d, ID=%d", // m_pSocket->getSOCKET(), pPacket->GetPacketID() ) ; } return TRUE ; __LEAVE_FUNCTION return FALSE ; } BOOL Player::HeartBeat( UINT uTime ) { __ENTER_FUNCTION return TRUE ; __LEAVE_FUNCTION return FALSE ; } VOID Player::ResetKick( ) { __ENTER_FUNCTION __LEAVE_FUNCTION } //INT Player::WhereThisPlayerFrom(VOID) const //{ // if(NULL!=m_pSocket) // { // return g_Config.m_InternalIpofProxy.WhereThisIpFrom(m_pSocket->m_Host); // } // return INVALID_ISP; //} //CHAR* ProxyTool_GetCorrespondingIP(Player const* pPlayer, ID_t ServerID) //{ // __ENTER_FUNCTION // _SERVER_DATA* pData = g_pServerManager->FindServerInfo( ServerID ); // if(NULL==pData) // { // CHAR szLog[1024]; // tsnprintf(szLog, sizeof(szLog), "[ProxyTool_GetCorrespondingIP] Error: Can't found the specific server(%d).", ServerID); // szLog[sizeof(szLog)-1] = '/0'; // AssertEx(pData, szLog); // } // INT nIsp = pPlayer->WhereThisPlayerFrom(); // if(INVALID_ISP==nIsp) // { // return pData->m_IP0; // } // else // { // if(TRUE==RangeCheckForIndex_Assert(nIsp, 0, NUM_OF_ISP-1, "ProxyTool_GetCorrespondingIP")) // { // PROXY_DATA& rProxy = pData->m_aProxy[nIsp]; // if(TRUE==rProxy.m_bEnabled) // { // return rProxy.m_szIP; // } // return pData->m_IP0; // } // else // { // return pData->m_IP0; // } // } // __LEAVE_FUNCTION // return NULL; //} //UINT ProxyTool_GetCorrespondingPort(Player const* pPlayer, ID_t ServerID) //{ // __ENTER_FUNCTION // _SERVER_DATA* pData = g_pServerManager->FindServerInfo( ServerID ); // if(NULL==pData) // { // CHAR szLog[1024]; // tsnprintf(szLog, sizeof(szLog), "[ProxyTool_GetCorrespondingPort] Error: Can't found the specific server(%d).", ServerID); // szLog[sizeof(szLog)-1] = '/0'; // AssertEx(pData, szLog); // } // INT nIsp = pPlayer->WhereThisPlayerFrom(); // if(INVALID_ISP==nIsp) // { // return pData->m_Port0; // } // else // { // if(TRUE==RangeCheckForIndex_Assert(nIsp, 0, NUM_OF_ISP-1, "ProxyTool_GetCorrespondingIP")) // { // PROXY_DATA& rProxy = pData->m_aProxy[nIsp]; // if(TRUE==rProxy.m_bEnabled) // { // return rProxy.m_nPort; // } // return pData->m_Port0; // } // else // { // return pData->m_Port0; // } // } // __LEAVE_FUNCTION // return NULL; //}
此類主要是用來加密,解密,處理數據包
嘗試用命令卻找不到任何佔用這個端口的程序。 # 49793 請自行替換爲實際的端口號 netstat -ano | findstr "49793" Windows系統或某些軟件爲了實現某些功能,需要預先保留一部分端口。 執行以下命令查看
TypeScript error TS2345 All In One error TS2345: Argument of type 'number' is not assignable to parameter of type 'stri
零、資料 LRU和LFU 緩存淘汰算法(javascript與go語言實現) 一、基本概念 LRU(Least Recently Used)和LFU(Least Frequently Used)是兩種常見的緩存淘汰算法, 用於在緩
Cron表達式簡明教程 Cron表達式的起源可以追溯到1970年代早期的UNIX系統。以下是關於Cron表達式起源的詳細介紹: 起源: 時間背景:Cron表達式最初是在1970年代早期的UNIX系統中創建的。 設計者:雖然Cron表達式的
https://blog.csdn.net/weixin_45325204/article/details/127062917
https://blog.csdn.net/huayula/article/details/135609835
最近跟在粉絲羣先聊到一個問題,數據庫的寫入方式,最多能寫入多少行數據。經過一些網絡搜索和查詢,據悉MySQL單表插入極限是3w~5w。 席間大家也都說了幾種寫入方式,其中有一個非壓測的方式在可查閱的資料中是最厲害的,據悉是程序寫入的20倍以
前言 使用QGis的目的是進行二次開發,或者說是融入我們的應用(無人車、無人船、無人機),本片描述搭建QGis二次基礎開發環境,由於實在是太長了,進行了分篇: 上半部分:主要是安裝好後,使用QtCreator可以使用QGIs
在Linux內核編程中,READ_ONCE 宏用於確保從內存中讀取一個變量的值時,編譯器不會對這個讀取操作進行優化,從而保證了讀取操作的原子性。這個宏通常在需要防止編譯器優化、多線程或中斷上下文中使用,以確保數據的一致性和正確性。 以下是
find_sys_call_table 和 kallsyms_lookup_name 都可以用於查找內核符號,但它們的具體作用和使用場景有所不同。以下是兩者的詳細對比: 1. find_sys_call_table 作用 find_sys_
05.01 斷舍離,節儉、樸素、素雅,生活的長遠之道。 05.02 蝴蝶翩翩,小鳥啾啾,花葉搖曳,水流潺潺。有一番自在之景,有一顆自在之心。 事起於微末之中,收於微末之中。 憑你多華美的詞藻,所見不過凡常。 以前的操作員是現在的程序員
title: Vue3使用Composition API實現響應式 date: 2024/5/29 下午8:10:24 updated: 2024/5/29 下午8:10:24 categories: 前端開發 tags: Vue3
項目代碼 1 #include <ESP8266WiFi.h> 2 #include <PubSubClient.h> 3 #include "DHT.h" 4 5 6 /* 配置WIFI 7 */
PaddleSegSharp 是一個基於百度飛槳PaddleSeg項目的人像分割模塊而開發的.NET的工具類庫。 PaddleSegSharp 中PaddleSeg.dll文件是基於開源項目最新發布版本PaddleSeg PaddleSeg
>>上一篇(學校上課,是耽誤我學習了。。) 2016年9月,我大二了。 自從我發現上課會耽誤我學習,只要我認爲不影響我期末學分的,我就逃課了。 絕大多數課都是要簽到的,有的是老師突擊喊名字,有的是手機打卡簽到。 如果上課老師一開始就喊名字簽