---------------------1 套接字对象----------------------
为每个套接字创建一个SOCKET_OBJ对象,记录与之相关的信息。
typedef struct _SOCKET_OBJ{ SOCKET s; int nOutstandingOps;//重叠IO数量 LPFN_ACCEPTEX lpfnAcceptEx; //扩展AcceptEx指针 }SOCKET_OBJ,*PSOCKET_OBJ;
所有重叠IO提交到特定的套接字上,释放对应套接字对象,必须保证此套接字再没有重叠IO,即nOutstandingOps=0
申请套接字对象,释放套接字对象的函数
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 缓冲区对象---------------------
缓冲区对象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对象练成一个链表
事件句柄数组 和 链表地址
HANDLE g_events[WSA_MAXIMUM_WAIT_EVENTS]; int g_nBufferCount;//数量 PBUFFER_OBJ g_pBufferHead,g_pBufferTail;//地址
调用重叠IO函数之前,都要申请BUFFER_OBJ对象,记录信息。IO完成后,再释放BUFFER_OBJ对象
申请BUFFER_OBJ对象 的函数:
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 主函数---------------------