socketOverlappedEvent.h
/******************************************************************** 创建时间: 2013/04/11 文件名: socketOverlappedEvent.h 描述: 重叠I/O 事件通知模式 作者: fengsh QQ : 19985430 电子邮件: [email protected] Blog : http://blog.csdn.net/fengsh998 @CopyRight fengsh WSASocket、AcceptEx、WSACreateEvent、WSAWaitForMultipleEvents、WSAResetEvent、WSAGetOverlappedResult、WSARecv、WSASetEvent。具体使用方法各位可以看下面的例子或者查一下MSDN,里面有介绍。 首先我们先看看重叠模型的使用步骤: 创建一个带Overlapped标志的Socket句柄(其实也可以是文件句柄); 准备好一个与这个Socket句柄对应的Overlapped对象,并准备好事件句柄,以便让后面的WaitForXXX函数使用 使用支持Overlapped的函数对上面的句柄作操作(向这个句柄投递请求),这些函数都有一个共同点,就是它们都有个参数是Overlapped类型的。例如AcceptEx、WriteFile、WSARecv等; 在一个循环或者一个线程中使用WSAWaitForMultipleEvents来等待事件的发生; 事件发生后,使用WSAGetOverlappedResult 来取得对应的结果并做处理。 继续向句柄投递操作请求(向它发东西啊,收东西啊等等的!)。 *********************************************************************/ #pragma once #include "socketbase.h" #include "SocketConst.h" typedef struct tagOVERLAPPED { WSAOVERLAPPED overlap; WSABUF Buffer; char buf[BUFFERMAX]; DWORD dwNumOfBytesRecved; DWORD Flags; }PER_IO_OPERATION_DATA,*LPPER_IO_OPERATION_DATA; typedef struct tagLISTENDATA { int iCount; SOCKET stAddr[MAXIMUM_WAIT_OBJECTS]; WSAEVENT wtHandle[WSA_MAXIMUM_WAIT_EVENTS]; LPPER_IO_OPERATION_DATA optiondata[MAXIMUM_WAIT_OBJECTS]; }LISTENDATA,*PTR_LISTENDATA; class CSocketOverlappedEvent : public CSocketBase { public: CSocketOverlappedEvent(void); ~CSocketOverlappedEvent(void); int startServer() ; int stopServer() ; bool sendtext(const std::string& content) ; //调整数组长度 void adjustDataSize(int idx); void deleteDataByIndex(int idx); void destoryAllData(); void doOverlapDataListen(SOCKET client); bool terminated(); PTR_LISTENDATA m_data; private: void *wcid; void *dataid; bool m_bterminate; };
socketOverlappedEvent.cpp
#include "socketOverlappedEvent.h" #include "socketThread.h" //客户端连接等待线程 static void* wait_client_thread(void* param); static void* data_listen_thread(void* param); CSocketOverlappedEvent::CSocketOverlappedEvent(void):m_bterminate(false) { m_data = (PTR_LISTENDATA)malloc(sizeof(LISTENDATA)); memset(m_data,0,sizeof(LISTENDATA)); } CSocketOverlappedEvent::~CSocketOverlappedEvent(void) { delete[] m_data; } int CSocketOverlappedEvent::startServer() { if (initSocket()) { m_bterminate = false; socket_thread_create(&wcid,wait_client_thread,(void*)this); socket_thread_create(&dataid,data_listen_thread,(void*)this); } return -1; } int CSocketOverlappedEvent::stopServer() { dispatchcallback(cbServerClose,NULL); m_bterminate = true; closesocket(m_listenSocket); destoryAllData(); return -1; } bool CSocketOverlappedEvent::sendtext( const std::string& content ) { for (int i = 0;i < m_data->iCount; i++) { sendData(m_data->stAddr[i],content); } return true; } void CSocketOverlappedEvent::adjustDataSize(int idx) { //当前IDX与最后一个赋值 if( idx < m_data->iCount - 1) { m_data->stAddr[idx] = m_data->stAddr[m_data->iCount-1]; m_data->wtHandle[idx] = m_data->wtHandle[m_data->iCount-1]; m_data->optiondata[idx] = m_data->optiondata[m_data->iCount-1]; } m_data->optiondata[--m_data->iCount]=NULL; } void CSocketOverlappedEvent::deleteDataByIndex( int idx ) { closesocket(m_data->stAddr[idx]); WSACloseEvent(m_data->wtHandle[idx]); HeapFree(GetProcessHeap(),0,m_data->optiondata[idx]); } void CSocketOverlappedEvent::destoryAllData() { int icount = m_data->iCount; for (int i=0;i < icount; i++) { deleteDataByIndex(i); } memset(m_data,0,sizeof(LISTENDATA)); } /* WSAGetLastError(); WSANOTINITIALISED 在调用本API之前应成功调用WSAStartup()。 WSAENETDOWN 网络子系统失效。 WSAENOTCONN 套接口未连接。 WSAEINTR 通过WSACancelBlockingCall()函数取消(阻塞)调用。 WSAEINPROGRESS 一个阻塞的WinSock调用正在进行中,或者服务提供者仍在处理一个回调函数 WSAENETRESET 由于远端的复位造成连接的中止。 WSAENOTSOCK 描述字不是一个套接口。 WSAEOPNOTSUPP 设置了MSG_OOB,但是该套接口不是诸如SOCK_STREAM流类型的,与套接口相关的通讯域不支持带外数据,或者套接口是单向的,只支持发送操作。 WSAESHUTDOWN 套接口已经关闭;一个套接口以SD_RECEIVE或 SD_BOTH的how参数shutdown()后,无法进行WSARecv()调用。 WSAEWOULDBLOCK 重叠套接口:太多重叠的输入/输出请求。非重叠套接口:套接口被标志为非阻塞,但是操作不能立即完成。 WSAEINVAL 套接口未用bind()捆绑,或者套接口未用重叠标志创建。 WSAECONNABORTED 由于超时或其他错误导致虚电路中止。 WSAECONNRESET 虚电路被远端复位。 WSAEDISCON 远端优雅的结束了连接。 WSA_IO_PENDING 成功启动一个重叠操作,过后将有完成指示。 */ void CSocketOverlappedEvent::doOverlapDataListen( SOCKET client ) { int idx = m_data->iCount; m_data->stAddr[idx] = client; //分配内存 m_data->optiondata[idx] = (LPPER_IO_OPERATION_DATA)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,sizeof(PER_IO_OPERATION_DATA)); m_data->optiondata[idx]->Buffer.len = BUFFERMAX; m_data->optiondata[idx]->Buffer.buf = m_data->optiondata[idx]->buf; //创建事件 m_data->wtHandle[idx] = m_data->optiondata[idx]->overlap.hEvent = WSACreateEvent(); //监听网络事件 WSARecv(m_data->stAddr[idx],&m_data->optiondata[idx]->Buffer,1, &m_data->optiondata[idx]->dwNumOfBytesRecved,&m_data->optiondata[idx]->Flags, &m_data->optiondata[idx]->overlap,NULL); m_data->iCount++; } bool CSocketOverlappedEvent::terminated() { return m_bterminate; } static void* wait_client_thread(void *param) { CSocketOverlappedEvent *overlapped = (CSocketOverlappedEvent*)param; DISPATCHPARAM dp; memset(&dp,0,sizeof(DISPATCHPARAM)); SOCKET socketClient; while(true) { SOCKADDR_IN addrClient; int addrClientSize=sizeof(SOCKADDR_IN); socketClient=accept(overlapped->m_listenSocket,(struct sockaddr*)&addrClient,&addrClientSize); if (socketClient==INVALID_SOCKET) { socketClient = NULL; if (overlapped->checkSocketError(WSAGetLastError())) { break; } continue; } else { overlapped->doOverlapDataListen(socketClient); strcpy(dp.info.ip,inet_ntoa(addrClient.sin_addr)); dp.info.port = addrClient.sin_port; overlapped->dispatchcallback(cbHasConnect,&dp); } } return 0; } static void* data_listen_thread(void* param) { CSocketOverlappedEvent *overlapped = (CSocketOverlappedEvent*)param; DISPATCHPARAM dp; memset(&dp,0,sizeof(DISPATCHPARAM)); int nRet,index; DWORD cbTransfered; while(true) { if (overlapped->terminated()) { break; } nRet = WSAWaitForMultipleEvents(overlapped->m_data->iCount,overlapped->m_data->wtHandle,FALSE,1000,FALSE); if (nRet == WSA_WAIT_FAILED || nRet == WSA_WAIT_TIMEOUT) { continue; } index = nRet - WAIT_OBJECT_0; //重设事件,已重新接收消息 WSAResetEvent(overlapped->m_data->wtHandle[index]); WSAGetOverlappedResult(overlapped->m_data->stAddr[index],&overlapped->m_data->optiondata[index]->overlap, &cbTransfered,true,&overlapped->m_data->optiondata[index]->Flags); if (cbTransfered == 0) { overlapped->deleteDataByIndex(index); overlapped->adjustDataSize(index); } else { strcpy(dp.msg,overlapped->m_data->optiondata[index]->buf); //回调到界面 overlapped->dispatchcallback(cbCommunication,&dp); //回调到接收完成 overlapped->dispatchcallback(cbRecviced,NULL); //ZeroMemory(&overlapped->m_data->optiondata[index]->overlap,sizeof(OVERLAPPED)); WSARecv(overlapped->m_data->stAddr[index],&overlapped->m_data->optiondata[index]->Buffer,1, &overlapped->m_data->optiondata[index]->dwNumOfBytesRecved,&overlapped->m_data->optiondata[index]->Flags, &overlapped->m_data->optiondata[index]->overlap,NULL); } } return 0; }