基於重疊IO模型的 回顯TCP服務器設計

---------------------1 套接字對象----------------------數組

爲每一個套接字建立一個SOCKET_OBJ對象,記錄與之相關的信息。socket

typedef struct _SOCKET_OBJ{ SOCKET s; int nOutstandingOps;//重疊IO數量
    LPFN_ACCEPTEX lpfnAcceptEx; //擴展AcceptEx指針
}SOCKET_OBJ,*PSOCKET_OBJ;

全部重疊IO提交到特定的套接字上,釋放對應套接字對象,必須保證此套接字再沒有重疊IO,即nOutstandingOps=0函數

申請套接字對象,釋放套接字對象的函數ui

 PSOCKET_OBJ GetSocketObj(SOCKET s){ PSOCKET_OBJ pSocket = (PSOCKET_OBJ)::GlobalAlloc(GPTR,sizeof(SOCKET_OBJ)); if(pSocket != NULL) pSocket->s = s; return pSocket; } void FreeSocketObj(PSOCKET_OBJ pSocket){ if(pSocket->s != INVALID_SOCKET) ::closesocket(pSocket->s); ::GlobalFree(pSocket); }

---------------------2 緩衝區對象---------------------spa

緩衝區對象SOCKET_OBJ,記錄重疊IO的全部屬性線程

typedef struct _BUFFER_OBJ{ OVERLAPPED ol;//重疊結構
    char *buff;//使用的緩衝區
    int nLen;//buff長度
    PSOCKET_OBJ pSocket;//次io所屬的套接字對象
    int nOperation;//提交的操做類型
#define OP_ACCEPT    1
#define OP_READ        2
#define OP_WRITE    3 SOCKET sAccept;//保存AcceptEx接受客戶套接字
    _BUFFER_OBJ *pNext; }BUFFER_OBJ,*PBUFFER_OBJ;

pNext將BUFFER_OBJ對象練成一個鏈表指針

事件句柄數組 和 鏈表地址code

HANDLE g_events[WSA_MAXIMUM_WAIT_EVENTS]; int g_nBufferCount;//數量
PBUFFER_OBJ g_pBufferHead,g_pBufferTail;//地址

調用重疊IO函數以前,都要申請BUFFER_OBJ對象,記錄信息。IO完成後,再釋放BUFFER_OBJ對象對象

申請BUFFER_OBJ對象 的函數:blog

PBUFFER_OBJ GetBufferObj(PSOCKET_OBJ pSocket,ULONG nLen){ if(g_nBufferCount > WSA_MAXIMUM_WAIT_EVENTS) return NULL; PBUFFER_OBJ pBuffer = (PBUFFER_OBJ)::GlobalAlloc(GPTR,sizeof(BUFFER_OBJ)); if(pBuffer!=NULL) { pBuffer->buff = (char*)::GlobalAlloc(GPTR,nLen); pBuffer->ol.hEvent = ::WSACreateEvent(); pBuffer->pSocket = pSocket; pBuffer->sAccept = INVALID_SOCKET; //將新的BUFFER_OBJ添加到列表
        if(g_pBufferHead == NULL) { g_pBufferHead = g_pBufferTail = pBuffer; } else { g_pBufferTail->pNext = pBuffer; g_pBufferTail = pBuffer; } g_events[++g_nBufferCount] = pBuffer->ol.hEvent; } return pBuffer; }

釋放BUFFER_OBJ對象函數:

void FreeBufferObj(PBUFFER_OBJ pBuffer){ //從列表中移除BUFFER_OBJ對象
    PBUFFER_OBJ pTest = g_pBufferHead; BOOL bFind = FALSE; if(pTest == pBuffer){ g_pBufferHead = g_pBufferTail = NULL; bFind = TRUE; } else{ while(pTest!=NULL && pTest->pNext!=pBuffer) pTest = pTest->pNext; if(pTest!=NULL){ pTest->pNext = pBuffer->pNext; if(pTest->pNext == NULL) g_pBuffer Tail = pTest; bFind = TRUE; } } //釋放它佔用的空間
    if(bFind) { g_pBufferCount--; ::CloseHandle(pBuffer->ol.hEvent); ::GlobalFree(pBuffer->buff); ::GlobalFree(pBuffer); } }

提交重疊IO,傳遞參數有重疊結構IO和緩衝區指針buff。在IO完成後,獲得的是受信事件對象的句柄。根據這個句柄找到對應的BUFFER_OBJ對象。

查找BUFFER_OBJ對象的代碼:

PBUFFER_OBJ FindBufferObj(HANDLE hEvent){ PBUFFER_OBJ pBuffer = g_pBufferHead; while(pBuffer != NULL){ if(pBuffer->ol.hEvent == hEvent) break; pBuffer = pBuffer->pNext; } return pBuffer; }

更新時間句柄數組g_events中的內容:

void RebuildArray(){ PBUFFER_OBJ pBuffer = g_pBufferHead; int i= 1; while(pBuffer != NULL){ g_events[i++] = pBuffer->ol.hEvent; pBuffer = pBuffer->pNext; } }

---------------------3 提交重疊IO---------------------

投遞IO以後,線程在重疊IO事件上等待,一旦IO事件對象受信,等待函數就會返回

提交接受鏈接的BUFFER_OBJ對象代碼:

BOOL PostAccept(PBUFFER_OBJ pBuffer){ PSOCKET_OBJ pSocket = pBuffer->pSocket; if(pSocket->lpfnAcceptEx != NULL){ //設置IO類型,增長套接字上的重疊IO計數
        pBuffer->nOperation = OP_ACCEPT; pSocket->nOutstandingOps++; //投遞此重疊IO
 DWORD dwBytes; pBuffer->sAccept = ::WSASocket(AF_INET,SOCK_STREAM,0,NULL,0,WSA_FLAG_OVERLAPPED); BOOL b = pSocket->lpfnAcceptEx( pSocket->s, pBuffer->sAccept, pBuffer->buff, BUFFER_SIZE - ((sizeof(sockaddr_in+16))*2), sizeof(sockaddr_in)+16, sizeof(sockaddr_in)+16, &dwBytes, &pBuffer->ol ); if(!b){ if(::WSAGetLastError()!=WSA_IO_PENDING) return FALSE; } return TRUE; } return FALSE; };

接收數據的BUFFER_OBJ對象代碼:

BOOL PostRecv(PBUFFER_OBJ pBuffer){ //設置IO類型,增長套接字上的重疊IO計數
    pBuffer->nOperation = OP_ACCEPT; pBuffer->pSocket->nOutstandingOps++; //投遞此重疊IO
 DWORD dwBytes; DWORD dwFlags = 0; WSABUF buf; buf.buf = pBuffer->buff; buf.len = pBuffer->nLen; if(::WSARecv(pBuffer->pSocket->s,&buf,1,&dwBytes,&dwFlags,&pBuffer->ol,NULL)!=NO_ERROR){ if(::WSAGetLastError()!= WSA_IO_PENDING) return FALSE; } return TRUE; }

發送數據額BUFFER-obj對象代碼:

BOOL PostSend(PBUFFER_OBJ pBuffer){ //設置IO類型,增長套接字上的重疊IO計數
    pBuffer->nOperation = OP_ACCEPT; pBuffer->pSocket->nOutstandingOps++; //投遞此重疊IO
 DWORD dwBytes; DWORD dwFlags; WSABUF buf; buf.buf = pBuffer->buff; buf.len = pBuffer->nLen; if(::WSASend(pBuffer->pSocket->s,&buf,1,&dwBytes,&dwFlags,&pBuffer->ol,NULL)!=NO_ERROR){ if(::WSAGetLastError()!=WSA_IO_PENDING) return FALSE; } return TRUE; }

---------------------4 主函數---------------------

相關文章
相關標籤/搜索