socketAsynSelect.h
/******************************************************************** 创建时间: 2013/04/11 文件名: socketAsynSelect.h 描述: 异步选择I/O模型 需要有界面,要向UI抛WIN 消息。需要窗口句柄 作者: fengsh QQ : 19985430 电子邮件: [email protected] Blog : http://blog.csdn.net/fengsh998 @CopyRight fengsh *********************************************************************/ #pragma once #include "socketbase.h" //引入这个才能在DLL中使用SendMessage的API #pragma comment(lib, "User32.lib") class CSocketAsynSelect : public CSocketBase { private: void cancelEventNotify(); protected: void processAsynSelect(); public: CSocketAsynSelect(void); ~CSocketAsynSelect(void); int startServer() ; int stopServer() ; bool sendtext(const std::string& content) ; void asynResponse(unsigned int wParam, long lParam); private: SOCKET datasocket; };
socketAsynSelect.cpp
#include "socketAsynSelect.h" #include "SocketConst.h" CSocketAsynSelect::CSocketAsynSelect(void) { } CSocketAsynSelect::~CSocketAsynSelect(void) { } int CSocketAsynSelect::startServer() { if (initSocket()) { processAsynSelect(); return 1; } return -1; } int CSocketAsynSelect::stopServer() { dispatchcallback(cbServerClose,NULL); closesocket(datasocket); closesocket(m_listenSocket); dispatchcallback(cbDisconnect,NULL); return -1; } bool CSocketAsynSelect::sendtext( const std::string& content ) { return sendData(datasocket,content); } void CSocketAsynSelect::processAsynSelect() { if (m_handle) { if(SOCKET_ERROR == WSAAsyncSelect(m_listenSocket,(HWND)this->m_handle,WM_ASYNSOCKET,FD_ACCEPT)) { DISPATCHPARAM dp; memset(&dp,0,sizeof(DISPATCHPARAM)); dp.errcode = WSAGetLastError(); dispatchcallback(cbError,&dp); } //SendMessage((HWND)this->m_handle,WM_ASYNSOCKET,1,1); } else { //dispatchcallback(cbError,) } } /* 值 说明 触发条件 FD_READ 套接口有可读消息通知 recv,recvfrom,WSARecv或WSARecvFrom FD_WRITE 套接口有可发消息通知 send,sendto,WSASend或WSASendTo FD_OOB 套件口有外带数据消息通知 recv,recvfrom,WSARecv或WSARecvFrom FD_ACCEPT 套接口有链接请求消息通知 accept或WSAAccept(错误码不能WSATRY_AGAIN) FD_CONNECT 希望得到connect或多点join操作完成信息通知 无 FD_CLOSE (面向连接) 套接口关闭消息通知 无 FD_QOS 套接口QOS状态发生变化消息通知 WSAIoctl(SIO_GET_QOS) FD_GROUP_QOS 保留 Reserved FD_ROUTING_INTERFACE_CHANGE 特定方向的路由接口发生改变消息通知。 WSAIoctl(SIO_ROUTING_INTERFACE_CHANGE) FD_ADDRESS_LIST_CHANGE 得到本地地址列表上套接口协议族发生改变通知。 WSAIoctl(SIO_ADDRESS_LIST_CHANGE) */ void CSocketAsynSelect::asynResponse( unsigned int wParam, long lParam ) { if (WSAGETSELECTERROR(lParam)) { closesocket(wParam); return ; } DISPATCHPARAM dp; memset(&dp,0,sizeof(DISPATCHPARAM)); switch(lParam) { case FD_ACCEPT: { SOCKADDR_IN addrClient; int naddrClientSize=sizeof(SOCKADDR_IN); datasocket=accept(wParam,(struct sockaddr *)&addrClient,&naddrClientSize); if (datasocket==INVALID_SOCKET) { datasocket = NULL; checkSocketError(WSAGetLastError()); } else { strcpy(dp.info.ip,inet_ntoa(addrClient.sin_addr)); dp.info.port = addrClient.sin_port; dispatchcallback(cbHasConnect,&dp); } WSAAsyncSelect(datasocket,(HWND)m_handle,WM_ASYNSOCKET,FD_READ | FD_WRITE | FD_CLOSE); } break; case FD_READ: { int nRetSize = 0; char bufMsg[BUFFERMAX]; dispatchcallback(cbReadyRev,NULL); nRetSize=recv(wParam,bufMsg,BUFFERMAX,0); if (nRetSize>0) { strcpy(dp.msg,bufMsg); //回调到界面 dispatchcallback(cbCommunication,&dp); //回调到接收完成 dispatchcallback(cbRecviced,NULL); } else if (nRetSize == 0) {//客户端主动断连了。0 datasocket = NULL; dp.errcode = WSAGetLastError(); dispatchcallback(cbDisconnect,&dp); } else if (nRetSize == -1) { //客户端异常断开10054 当客户端在监听recv动作时被关闭了socket就会引发 //10053 服务器主动断开 //10093 在没有任何客户端连接的情况下,服务器关闭数据SOCKET引发 datasocket = NULL; strcpy(dp.errmsg,"client error."); dp.errcode = WSAGetLastError(); dispatchcallback(cbDisconnect,&dp); } } break; case FD_WRITE: { } break; case FD_CLOSE: { closesocket(wParam); dispatchcallback(cbDisconnect,NULL); } break; default: break; } } void CSocketAsynSelect::cancelEventNotify() { WSAAsyncSelect(m_listenSocket,(HWND)this->m_handle, 0, 0); }