庫地址:
=========================
ST**表示單線程 
//開始監聽
bool Start( int nMaxMonitor );
//增加一個監聽對象
bool AddMonitor( SOCKET socket );
//等待事件發生,block無作用
bool WaitEvent( void *eventArray, int &count, bool block );
//增加一個接受連接的操作,有連接進來,WaitEvent會返回
bool AddAccept(SOCKET listenSocket);
//增加一個接收數據的操作,有數據到達,WaitEvent會返回
bool AddRecv( SOCKET socket, char* recvBuf, unsigned short bufSize );
//增加一個發送數據的操作,發送完成,WaitEvent會返回
bool AddSend( SOCKET socket, char* dataBuf, unsigned short dataSize );

抽象控制的api
監聽套接字對象的方法,
IOCPMonitor
==========================
typedef struct IO_EVENT
{
SOCKET sock;
EventType type;
SOCKET client;
char *pData;
unsigned short uDataSize;
}IO_EVENT;
MemoryPool m_iocpDataPool;//iocp投遞參數池
typedef struct IOCP_OVERLAPPED
{
/**
* OVERLAPPED類型指針
* 指向完成操作參數
* 傳遞給AcceptEx()的最后一個參數
* 傳遞給WSARecv()的第個參數
* GetQueuedCompletionStatus()返回的第個參數
*/
OVERLAPPED m_overlapped;
/**
* 指向存有連接進來的客戶端局域網和外網地址的內存
* 必須使用動態分配的內存塊
* 傳遞給AcceptEx()的第個參數
*
*/
char m_outPutBuf[sizeof(SOCKADDR_IN)*2+32];
/**
* 客戶端局域網IP信息長度
* 傳遞給AcceptEx()的第個參數
*/
unsigned long m_dwLocalAddressLength;
/**
* 客戶端外網IP信息長度
* 傳遞給AcceptEx()的第個參數
*/
unsigned long m_dwRemoteAddressLength;
WSABUF m_wsaBuffer;//WSARecv接收緩沖數據,傳遞給WSARecv()的第個參數
SOCKET sock;
EventType completiontype;//完成類型recv 2send
}IOCP_OVERLAPPED;
IOCPMonitor::Start( int nMaxMonitor )
端口啟動
創建完全端口
線程數cpu數*2+2
IOCPMonitor::AddMonitor( SOCKET sock )
加入套接字到 IOCP列隊
IOCPMonitor::WaitEvent( void *eventArray, int &count, bool block )
等待一次完全端口的 事件
GetQueuedCompletionStatus( )
返回不同的iocp事件類型 或 數據 供上層循環控制
IOCPFrame : public NetEngine
繼承了 netengine 的通用和抽象的方法,
同時針對不同的os平臺實例化不同的網絡模型
IOCPFrame::IOCPFrame()
{
#ifdef WIN32
m_pNetMonitor = new IOCPMonitor;
#endif
IOCPFrame 控制監聽 接收 發送,集成 NetEngine 抽象
Child: one new IOCPMonitor;
class NetServer
{
friend class NetEngine;
NetEngine* m_pNetCard;
Netserver為 主要控制對象,里面抽象了邏輯的控制的 函數,可以繼承城市
同時 NetServer 和 NetEngine 是friend class
NetEngine 里面有監聽過程中的 一些寫業務的邏輯調用到 Netserver,幾個抽象的業務 接口 實現的地方 就獨立出來了。
NetEngine 業務控制抽象的幾種 業務調用
Threeadpool的任務

三種:業務實現
OnConnect
Onclose
OnMsg
比如

監聽到鏈接的 調用NetEngine 調用了 iocpframe監聽 到連接的事件
調用父輩方法
NetEngine::OnConnect( SOCKET sock, bool isConnectServer )
創建一個 NetConnect對象,通過內存池分配的對象
投遞一個 連接的任務的task給線程池
Onclose
OnMsg
類似
內存池設計
內存池 存儲 NetConnect對象,存儲管理netconnect對象 使用memorypool
//初始化內存池 預分配內存池
bool Init(unsigned short uMemorySize, unsigned short uMemoryCount);
// //分配內存(鏈表方法)
一個線程讀 一個線程寫 無鎖隊列
Iobuffer
包含vector 一張 Iobufferblock 表,存儲多個緩沖塊
讀取的時候
Iobufferblock 托管在內存池mempool BUFBLOCK_SIZE大小的內存塊
Iobuffer
Readdata
/**
* IO緩沖
* 定義宏BUFBLOCK_SIZE
* 編譯期靜態確定類大小
* 不能使用指針在運行時動態指定大小,參考池對象使用限制二
*/
unsigned char m_buffer[BUFBLOCK_SIZE];
//已收到數據的長度
unsigned short m_uLength;
//Recv()函數下次讀取數據的開始位置
unsigned short m_uRecvPos;
unsigned short IOBufferBlock::ReadData( unsigned char *data, unsigned short uLength, bool bDel )
從當前讀取位置開始讀取,如果越界 就用剩下的大小獲取
bool IOBuffer::ReadData( unsigned char *data, int uLength, bool bDel )
//這里檢查m_uDataSize不需要原子操作
//cpu與內存次交換最小長度就是byte,對于小于等于byte的類型的取值/賦值操作,
//本身就是原子操作
從頭來
遍歷 所有bufferblock 如果是需要刪除的,那么原子操作減一,標志不使用了內存池,同時刪除清理block
一讀一寫,沒有線程安全問題
====================
SharedPtr
通過原子加減操作達到 引用計數操作的線程安全
ShareMemory
依靠viewmap實現 內存映射文件
/*
* 創建/打開共享內存
* 參數
* key 全局標識,linux下只接收數字id
* size 共享大小
* if ( 是創建)
* 則創建size大小的共享內存,
* else //是打開已存在的共享內存
* if ( 是文件映射&& 是linux系統)
* 則使用當前共享內存大小與size中較大的一個,作為共享內存的大小
* else 無效
* else 無效
* path 使用文件映射的共享內存,文件路徑,key為文件名
*/
ShareMemory(const char *key, unsigned long size, const char *path);
/*
* 創建/打開共享內存
* 參數
* key 全局標識
* size 共享大小
* if ( 是創建)
* 則創建size大小的共享內存,
* else //是打開已存在的共享內存
* if ( 是文件映射&& 是linux系統)
* 則使用當前共享內存大小與size中較大的一個,作為共享內存的大小
* else 無效
* else 無效
* path 使用文件映射的共享內存,文件路徑,key為文件名
*/
ShareMemory(const int key, unsigned long size, const char *path);
public:
void* GetBuffer();
unsigned long GetSize();
void Destory();
一次性獲取數據,初始化的時候指定 了大小了。
內存映射文件的方法,沒啥好看的
Signal
采用事件做信號通知,
=========================================
ThreadPool
包含一個vect的任務隊列 里面帶的就是task
線程池 采用 事件信號通知。執行的函數 ThreadFunc
每次從 從m_tasks取任務,加了鎖地取法。
然后執行task的里面的Execute 方法 這樣就調用到 Executor的CallMethod方法 參數從入隊進入就提交了。
Memorypool

一、
一塊對象數據MEMERY_INFO + uMemorySize

二、一個 MemoryPool的 數據結構
存儲對象本身 8Byte
每一塊數據包含信息8byte 然后就是指向 目標管理對象的對象內存
nBlockStartPos += MEMERY_INFO;
pObject = &(m_pMemery[nBlockStartPos]);
內存塊數 初始化的時候 設置的 m_uMemoryCount

三、Alloc()
找尋本身memorypool是否存在可用內存,
有,就直接獲取地址出去使用
沒有的的話遍歷到最后會發現 pBlock->m_pNext 為空,這個時候重新new memorypool對象 教導鏈表上去
m_uFreeCount 未分配的 個數
通過遍歷 查詢AtomDec pBlock->m_uFreeCount 減1
if ( 0 < (int32)AtomDec(&pBlock->m_uFreeCount, 1) ) break; 執行分配
class MemoryPool void* Alloc();
* 無鎖堆(n讀n寫并發,不需加鎖)
* 內存池結構
* n個池組成鏈表
*
* 池結構
* 每個池都是一段連續內存保存在char數組中
* 0~7byte為池地址,后面是n個用于固定長度分配的內存塊(即內存塊是定長的)
*
* 內存塊結構
* 狀態byte+留空byte+內存塊塊序號byte
* 所以一個內存池最大可以保存的對象(內存塊)數量為unsigned short的最大值
*
* 狀態就個(分配/未分配),個byte就可以表示,使用byte是為了使用原子操作實現lock-free,而原子操作操作的是byte地址
* 2byte留空,是為了保證后面用于分配的內存守地址都是byte對齊
* 因為真實new出來的對象首地址是保證這點的,
* 且IOCP投遞緩沖struct,也要求首地址對齊,否則返回錯誤
初始化
//預分配內存=MemoryPool對象自身地址,byte,支持位機尋址
//記錄對象地址
//頭個字節保存對象自身地址,用于從內存地址找到內存池對象地址
if ( 8 == uAddrSize )
{
m_pMemery[nPos++] = (unsigned char)(uThis >> 56);
m_pMemery[nPos++] = (unsigned char)(uThis >> 48);
m_pMemery[nPos++] = (unsigned char)(uThis >> 40);
m_pMemery[nPos++] = (unsigned char)(uThis >> 32);
}
else
{
m_pMemery[nPos++] = 0;
m_pMemery[nPos++] = 0;
m_pMemery[nPos++] = 0;
m_pMemery[nPos++] = 0;
}
m_pMemery[nPos++] = (unsigned char)(uThis >> 24);
m_pMemery[nPos++] = (unsigned char)(uThis >> 16);
m_pMemery[nPos++] = (unsigned char)(uThis >> 8);
m_pMemery[nPos++] = (unsigned char)uThis;
//初始化內存
unsigned short i;
for ( i = 0; i < m_uMemoryCount; i++ )
{
//狀態未分配
m_pMemery[nPos++] = 0;
m_pMemery[nPos++] = 0;
m_pMemery[nPos++] = 0;
m_pMemery[nPos++] = 0;
//留空字節
m_pMemery[nPos++] = 0;
m_pMemery[nPos++] = 0;
//保存內存序號
m_pMemery[nPos++] = (unsigned char) (i >> 8);
m_pMemery[nPos++] = (unsigned char) i;
nPos += uMemorySize;
}
鏈表 內存池組
每個內存池
通過對象算出索引
通過索引算出對象都很方便
詳細參考另外一個筆記