自己做的类库 封装socket类 请问怎样实现非阻塞模式? 我是自己封装的类库 做了tcp的server一个类 不能使用mfc类 也没有窗口 请问怎样做?用WSAEventSelect可以实现吗? 应该怎样做呢 哪位有这方面的例子? 谢谢! 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 建议你看看ACE库,它有非阻塞的封装ACE-5.4\ACE_wrappers\examples\Connection\non_blocking 我在程序里开了一个线程 然后用WSAWaitForMultipleEvents的时候返回的index-=WSA_WAIT_EVENT_0 总是一个很大的数 不在事件数组范围之内 这是为什么呢? 还有捕捉FD_READ消息总是捕捉不到。 已经写好了的库,你可以直接使用了。源码请参考http://www.vczx.com/article/show.php?id=1041 我对这方面还不熟悉 请大家赐教下边的代码都有什么问题? unsigned _stdcall Recieve(VOID* pParam) { CFsTcpClient* client = NULL; client = (CFsTcpClient*)pParam; client->Recv(); return 0; } VOID CFsTcpClient::SrvRcv() { ULONG hThread = _beginthreadex(NULL,0,Recieve,this,0,NULL); } // INT CFsTcpClient::Recv() { WSAEVENT eventList[1]; eventList[0] = WSACreateEvent(); WSAEventSelect(iSock,eventList,FD_READ | FD_WRITE | FD_CONNECT | FD_ACCEPT | FD_CLOSE); if( !WSAResetEvent(eventList[0]) ) return -1; INT iIndex = 0; while( (iIndex = WSAWaitForMultipleEvents(1,eventList, false,1000,true)) == WSA_WAIT_FAILED) { iIndex -= WSA_WAIT_EVENT_0; WSANETWORKEVENTS type; WSAEnumNetworkEvents(iSock,eventList[iIndex],&type); if(type.lNetworkEvents & FD_READ) { fd_set fdsSocks; struct timeval stTimeout; memset(szOutBuf, 0, MAX_SOCK_BUFFER); iErr = 0; if ((iBuf == 1) && (iEnd1 != 0)) // Copy the contents of buf 1. { if (MAX_SOCK_BUFFER >= (iEnd1 - iBeg1)) // Copy all the bytes. { memcpy(szOutBuf, szBuf1 + iBeg1, iEnd1 - iBeg1); iErr = iEnd1 - iBeg1; iBeg1 = iEnd1 = 0; iBuf = 2; } else // Only copy the requested number. { memcpy(szOutBuf, szBuf1 + iBeg1, MAX_SOCK_BUFFER); iErr = MAX_SOCK_BUFFER; // This many bytes sent back. iBeg1 += MAX_SOCK_BUFFER; // Advance to this location. } } else if ((iBuf == 2) && (iEnd2 != 0)) // Copy the contents of buf 2. { if (MAX_SOCK_BUFFER >= (iEnd2 - iBeg2)) { memcpy(szOutBuf, szBuf2 + iBeg2, iEnd2 - iBeg2); iErr = iEnd2 - iBeg2; iBeg2 = iEnd2 = 0; iBuf = 1; } else { memcpy(szOutBuf, szBuf2 + iBeg2, MAX_SOCK_BUFFER); iErr = MAX_SOCK_BUFFER; iBeg1 += MAX_SOCK_BUFFER; } } else { FD_ZERO(&fdsSocks); FD_SET(iSock, &fdsSocks); stTimeout.tv_sec = ulTimeout; iErr = select(1, &fdsSocks, 0, 0, &stTimeout); if (iErr < 1) // Error occured. { return -1; } iErr = recv(iSock, szOutBuf, MAX_SOCK_BUFFER, 0); szOutBuf[iErr] = '\0'; if (iErr == 0) return -1; } } } return iErr; } while( (iIndex = WSAWaitForMultipleEvents(1,eventList, false,1000,true)) == WSA_WAIT_FAILED)这个地方的1000本来是这个WSA_INFINITE 但是每次都是堵塞在这里 所以我就换了1000, 然后进去以后iIndex是258 可是数组只有1个元素。。 在非阻塞模式下 利用 socket 事件 的消息机制, Server 端与 Client 端之间的通信处于异步状态下。 通常需要从 CSocket 类派生一个新类,派生新类的目的是重载 socket 事件 的消息函数,然后在 socket 事件 的消息函数中添入合适的代码以完成 Client 端与 Server 端之间的通信,与阻塞模式相比,非阻塞模式无需创建一个新线程。 这里将讨论当 Server 端 socket 事件 - FD_ACCEPT 被触发后,该事件的处理函数 OnAccept 是如何进一步被触发的。其它事件的处理函数如 OnConnect, OnReceive 等的触发方式与此类似。 在 1 中已提到 Client/Server 端通信时, Server 端 socket 正在接收来自 Client 端 socket 连接请求,这将会触发 FD_ACCEPT 事件,同时 Server 端的 网络传输服务进程 向 Server 端的 socket window (CSocketWnd )发送事件通知消息 WM_SOCKET_NOTIFY , 通知有 FD_ACCEPT 事件产生 , CsocketWnd 在收到事件通知消息后,调用消息处理函数 OnSocketNotifyLRESULT CSocketWnd::OnSocketNotify(WPARAM wParam, LPARAM lParam) { CSocket::AuxQueueAdd(WM_SOCKET_NOTIFY, wParam, lParam); CSocket::ProcessAuxQueue(); return 0L ; } 消息参数 wParam 是 socket 的句柄, lParam 是 socket 事件 。这里稍作解释一下,CSocketWnd 类是作为 CSocket 类的 友元类 ,这意味着它可以访问 CSocket 类中的保护和私有成员函数和变量, AuxQueueAdd 和 ProcessAuxQueue 是 CSocket 类的静态成员函数,如果你对友元不熟悉,请迅速找本有关 C++ 书看一下友元的使用方法吧! ProcessAuxQueue 是实质处理 socket 事件的函数,在该函数中有这样一句代码: CAsyncSocket* pSocket = CAsyncSocket::LookupHandle((SOCKET)wParam, TRUE); 其实也就是由 socket 句柄得到发送事件通知消息的 socket 指针 pSocket:从 m_pmapSocketHandle 中查找(见 1 )! 最后, WSAGETSELECTEVENT(lParam) 会取出事件类型,在一个简单的 switch 语句中判断事件类型并调用事件处理函数。在这里,事件类型是 FD_ACCEPT ,当然就调用 pSocket->OnAccept ! http://www.codeguru.com/Cpp/I-N/network/messaging/article.php/c5453 采用 CSocket 类编写的基于 Client/Server 的网络聊天程序,它是基于非阻塞模式的Client/Server端网络程序典型示例 我是自己写的类库 不能用MFC类的 也没有窗口 像上边那样写处理消息行不行呢? 对于许多初学者来说,网络通信程序的开发,普遍的一个现象就是觉得难以入手。许多概念,诸如:同步(Sync)/异步(Async),阻塞(Block)/非阻塞(Unblock)等,初学者往往迷惑不清,只知其所以而不知起所以然。 同步方式指的是发送方不等接收方响应,便接着发下个数据包的通信方式;而异步指发送方发出数据后,等收到接收方发回的响应,才发下一个数据包的通信方式。 阻塞套接字是指执行此套接字的网络调用时,直到成功才返回,否则一直阻塞在此网络调用上,比如调用recv()函数读取网络缓冲区中的数据,如果没有数据到达,将一直挂在recv()这个函数调用上,直到读到一些数据,此函数调用才返回;而非阻塞套接字是指执行此套接字的网络调用时,不管是否执行成功,都立即返回。比如调用recv()函数读取网络缓冲区中数据,不管是否读到数据都立即返回,而不会一直挂在此函数调用上。在实际Windows网络通信软件开发中,异步非阻塞套接字是用的最多的。平常所说的C/S(客户端/服务器)结构的软件就是异步非阻塞模式的。 对于这些概念,初学者的理解也许只能似是而非,我将用一个最简单的例子说明异步非阻塞Socket的基本原理和工作机制。目的是让初学者不仅对Socket异步非阻塞的概念有个非常透彻的理解,而且也给他们提供一个用Socket开发网络通信应用程序的快速入门方法。操作系统是Windows 98(或NT4.0),开发工具是Visual C++6.0。 MFC提供了一个异步类CAsyncSocket,它封装了异步、非阻塞Socket的基本功能,用它做常用的网络通信软件很方便。但它屏蔽了Socket的异步、非阻塞等概念,开发人员无需了解异步、非阻塞Socket的原理和工作机制。因此,建议初学者学习编网络通信程序时,暂且不要用MFC提供的类,而先用Winsock2 API,这样有助于对异步、非阻塞Socket编程机制的理解。 为了简单起见,服务器端和客户端的应用程序均是基于MFC的标准对话框,网络通信部分基于Winsock2 API实现。 先做服务器端应用程序。 用MFC向导做一个基于对话框的应用程序SocketSever,注意第三步中不要选上Windwos Sockets选项。在做好工程后,创建一个SeverSock,将它设置为异步非阻塞模式,并为它注册各种网络异步事件,然后与自定义的网络异步事件联系上,最后还要将它设置为监听模式。在自定义的网络异步事件的回调函数中,你可以得到各种网络异步事件,根据它们的类型,做不同的处理。下面将详细介绍如何编写相关代码。 在SocketSeverDlg.h文件的类定义之前增加如下定义: #define NETWORK_EVENT WM_USER+166 file://定义网络事件 SOCKET ServerSock; file://服务器端Socket 在类定义中增加如下定义: class CSocketSeverDlg : CDialog { … public: SOCKET ClientSock[CLNT_MAX_NUM]; file://存储与客户端通信的Socket的数组 /*各种网络异步事件的处理函数*/ void OnClose(SOCKET CurSock); file://对端Socket断开 void OnSend(SOCKET CurSock); file://发送网络数据包 void OnReceive(SOCKET CurSock); file://网络数据包到达 void OnAccept(SOCKET CurSock); file://客户端连接请求 BOOL InitNetwork(); file://初始化网络函数 void OnNetEvent(WPARAM wParam, LPARAM lParam); file://异步事件回调函数 … }; http://www.zjol.com.cn/gb/node2/node195/node56935/node56938/userobject7ai23757.html unsigned long j=1;ioctlsocket(sock,FIONBIO,&j);//非阻塞 用ioctlsocket函数设置FIONBIO选项。 请教删除指针数组出错问题。 http底层是通过socket实现的吗? EVC串口通讯程序死机 在窗口回调函数的WM_DESTROY消息中,还能够进行哪些处理? 一个简单的问题高手请进!!一定给分!! 关于网络编程? 一个关于图片显示的问题 VC编译出来的RELEASE版和DEBUG版有什么不同? 各位大哥,救急!!! 什么原因???各位大虾帮忙!!!(敬送50分) 100分求解!!请位大侠指点!! 添加打印驱动端口问题,急!!100分
ACE-5.4\ACE_wrappers\examples\Connection\non_blocking
源码请参考
http://www.vczx.com/article/show.php?id=1041
unsigned _stdcall Recieve(VOID* pParam)
{
CFsTcpClient* client = NULL;
client = (CFsTcpClient*)pParam;
client->Recv();
return 0;
}
VOID CFsTcpClient::SrvRcv()
{
ULONG hThread = _beginthreadex(NULL,0,Recieve,this,0,NULL);
} //
INT CFsTcpClient::Recv()
{
WSAEVENT eventList[1];
eventList[0] = WSACreateEvent();
WSAEventSelect(iSock,eventList,FD_READ | FD_WRITE | FD_CONNECT | FD_ACCEPT | FD_CLOSE);
if( !WSAResetEvent(eventList[0]) )
return -1;
INT iIndex = 0;
while( (iIndex = WSAWaitForMultipleEvents(1,eventList,
false,1000,true)) == WSA_WAIT_FAILED)
{
iIndex -= WSA_WAIT_EVENT_0;
WSANETWORKEVENTS type;
WSAEnumNetworkEvents(iSock,eventList[iIndex],&type);
if(type.lNetworkEvents & FD_READ)
{
fd_set fdsSocks;
struct timeval stTimeout;
memset(szOutBuf, 0, MAX_SOCK_BUFFER);
iErr = 0;
if ((iBuf == 1) && (iEnd1 != 0)) // Copy the contents of buf 1.
{
if (MAX_SOCK_BUFFER >= (iEnd1 - iBeg1)) // Copy all the bytes.
{
memcpy(szOutBuf, szBuf1 + iBeg1, iEnd1 - iBeg1);
iErr = iEnd1 - iBeg1;
iBeg1 = iEnd1 = 0;
iBuf = 2;
}
else // Only copy the requested number.
{
memcpy(szOutBuf, szBuf1 + iBeg1, MAX_SOCK_BUFFER);
iErr = MAX_SOCK_BUFFER; // This many bytes sent back.
iBeg1 += MAX_SOCK_BUFFER; // Advance to this location.
}
}
else if ((iBuf == 2) && (iEnd2 != 0)) // Copy the contents of buf 2.
{
if (MAX_SOCK_BUFFER >= (iEnd2 - iBeg2))
{
memcpy(szOutBuf, szBuf2 + iBeg2, iEnd2 - iBeg2);
iErr = iEnd2 - iBeg2;
iBeg2 = iEnd2 = 0;
iBuf = 1;
}
else
{
memcpy(szOutBuf, szBuf2 + iBeg2, MAX_SOCK_BUFFER);
iErr = MAX_SOCK_BUFFER;
iBeg1 += MAX_SOCK_BUFFER;
}
}
else
{
FD_ZERO(&fdsSocks);
FD_SET(iSock, &fdsSocks);
stTimeout.tv_sec = ulTimeout;
iErr = select(1, &fdsSocks, 0, 0, &stTimeout);
if (iErr < 1) // Error occured.
{
return -1;
}
iErr = recv(iSock, szOutBuf, MAX_SOCK_BUFFER, 0);
szOutBuf[iErr] = '\0';
if (iErr == 0) return -1;
}
}
}
return iErr;
}
false,1000,true)) == WSA_WAIT_FAILED)
这个地方的1000本来是这个WSA_INFINITE 但是每次都是堵塞在这里 所以我就换了1000, 然后进去以后iIndex是258 可是数组只有1个元素。。
通常需要从 CSocket 类派生一个新类,派生新类的目的是重载 socket 事件 的消息函数,然后在 socket 事件 的消息函数中添入合适的代码以完成 Client 端与 Server 端之间的通信,与阻塞模式相比,非阻塞模式无需创建一个新线程。
这里将讨论当 Server 端 socket 事件 - FD_ACCEPT 被触发后,该事件的处理函数 OnAccept 是如何进一步被触发的。其它事件的处理函数如 OnConnect, OnReceive 等的触发方式与此类似。
在 1 中已提到 Client/Server 端通信时, Server 端 socket 正在接收来自 Client 端 socket 连接请求,这将会触发 FD_ACCEPT 事件,同时 Server 端的 网络传输服务进程 向 Server 端的 socket window (CSocketWnd )发送事件通知消息 WM_SOCKET_NOTIFY , 通知有 FD_ACCEPT 事件产生 , CsocketWnd 在收到事件通知消息后,调用消息处理函数 OnSocketNotify
LRESULT CSocketWnd::OnSocketNotify(WPARAM wParam, LPARAM lParam)
{
CSocket::AuxQueueAdd(WM_SOCKET_NOTIFY, wParam, lParam);
CSocket::ProcessAuxQueue();
return 0L ;
} 消息参数 wParam 是 socket 的句柄, lParam 是 socket 事件 。这里稍作解释一下,CSocketWnd 类是作为 CSocket 类的 友元类 ,这意味着它可以访问 CSocket 类中的保护和私有成员函数和变量, AuxQueueAdd 和 ProcessAuxQueue 是 CSocket 类的静态成员函数,如果你对友元不熟悉,请迅速找本有关 C++ 书看一下友元的使用方法吧!
ProcessAuxQueue 是实质处理 socket 事件的函数,在该函数中有这样一句代码: CAsyncSocket* pSocket = CAsyncSocket::LookupHandle((SOCKET)wParam, TRUE);
其实也就是由 socket 句柄得到发送事件通知消息的 socket 指针 pSocket:从 m_pmapSocketHandle 中查找(见 1 )!
最后, WSAGETSELECTEVENT(lParam) 会取出事件类型,在一个简单的 switch 语句中判断事件类型并调用事件处理函数。在这里,事件类型是 FD_ACCEPT ,当然就调用 pSocket->OnAccept !
采用 CSocket 类编写的基于 Client/Server 的网络聊天程序,它是基于非阻塞模式的Client/Server
端网络程序典型示例
同步方式指的是发送方不等接收方响应,便接着发下个数据包的通信方式;而异步指发送方发出数据后,等收到接收方发回的响应,才发下一个数据包的通信方式。
阻塞套接字是指执行此套接字的网络调用时,直到成功才返回,否则一直阻塞在此网络调用上,比如调用recv()函数读取网络缓冲区中的数据,如果没有数据到达,将一直挂在recv()这个函数调用上,直到读到一些数据,此函数调用才返回;而非阻塞套接字是指执行此套接字的网络调用时,不管是否执行成功,都立即返回。比如调用recv()函数读取网络缓冲区中数据,不管是否读到数据都立即返回,而不会一直挂在此函数调用上。在实际Windows网络通信软件开发中,异步非阻塞套接字是用的最多的。平常所说的C/S(客户端/服务器)结构的软件就是异步非阻塞模式的。
对于这些概念,初学者的理解也许只能似是而非,我将用一个最简单的例子说明异步非阻塞Socket的基本原理和工作机制。目的是让初学者不仅对Socket异步非阻塞的概念有个非常透彻的理解,而且也给他们提供一个用Socket开发网络通信应用程序的快速入门方法。操作系统是Windows 98(或NT4.0),开发工具是Visual C++6.0。
MFC提供了一个异步类CAsyncSocket,它封装了异步、非阻塞Socket的基本功能,用它做常用的网络通信软件很方便。但它屏蔽了Socket的异步、非阻塞等概念,开发人员无需了解异步、非阻塞Socket的原理和工作机制。因此,建议初学者学习编网络通信程序时,暂且不要用MFC提供的类,而先用Winsock2 API,这样有助于对异步、非阻塞Socket编程机制的理解。
为了简单起见,服务器端和客户端的应用程序均是基于MFC的标准对话框,网络通信部分基于Winsock2 API实现。
先做服务器端应用程序。
用MFC向导做一个基于对话框的应用程序SocketSever,注意第三步中不要选上Windwos Sockets选项。在做好工程后,创建一个SeverSock,将它设置为异步非阻塞模式,并为它注册各种网络异步事件,然后与自定义的网络异步事件联系上,最后还要将它设置为监听模式。在自定义的网络异步事件的回调函数中,你可以得到各种网络异步事件,根据它们的类型,做不同的处理。下面将详细介绍如何编写相关代码。
在SocketSeverDlg.h文件的类定义之前增加如下定义:
#define NETWORK_EVENT WM_USER+166 file://定义网络事件
SOCKET ServerSock; file://服务器端Socket
在类定义中增加如下定义:
class CSocketSeverDlg : CDialog
{
…
public:
SOCKET ClientSock[CLNT_MAX_NUM]; file://存储与客户端通信的Socket的数组 /*各种网络异步事件的处理函数*/
void OnClose(SOCKET CurSock); file://对端Socket断开
void OnSend(SOCKET CurSock); file://发送网络数据包
void OnReceive(SOCKET CurSock); file://网络数据包到达
void OnAccept(SOCKET CurSock); file://客户端连接请求 BOOL InitNetwork(); file://初始化网络函数
void OnNetEvent(WPARAM wParam, LPARAM lParam); file://异步事件回调函数
…
};
ioctlsocket(sock,FIONBIO,&j);//非阻塞