c++Socket 异步通讯
阻塞模式
在阻塞方式下,收发数据的函数在被调用后一直要到传送完毕或者出错才能返回。在阻塞期间,被阻的函数不会断调用系统函数GetMessage()来保持消息循环的正常进行。
非阻塞模式
将一个套接字置为非阻塞模式之后, Winsock API调用会立即返回。一般这些调用都会“失败”,并返回一个WSAEWOULDBLOCK。表明其操作在调用期间没有时间完成。如在系统的输入缓冲区中,并不存在等待的数据,那recv调用就会返回WSAEWOULDBLOCK错误。通常,我们需要重复调用同一个函数,直至获得一个成功返回代码。这不是一个好的方法。通常采用Winsock的套接字I/O模型去处理。
套接字I/O模型共有五种类型,如下:
select(选择)
WSAAsyncSelect(异步选择)
WSAEventSelect(事件选择)
overlapped(重叠)
completion port(完成端口)
*WSAAsyncSelect
Winsock通过WSAAsyncSelect()自动地设置套接字处于非阻塞方式。使用WindowsSockets实现Windows网络程序设计的关键就是它提供了对网络事件基于消息的异步存取,用于注册应用程序感兴趣的网络事件。它请求Windows Sockets DLL在检测到套接字上发生的网络事件时,向窗口发送一个消息。
int PASCAL FAR WSAAsyncSelect(SOCKET s,HWND hWnd,unsigned int wMsg,long lEvent);
hWnd:窗口句柄
wMsg:需要发送的消息
lEvent:事件(以下为事件的内容)
值: 含义:
FD_READ 期望在套接字上收到数据(即读准备好)时接到通知
FD_WRITE 期望在套接字上可发送数据(即写准备好)时接到通知
FD_OOB 期望在套接字上有带外数据到达时接到通知
FD_ACCEPT 期望在套接字上有外来连接时接到通知
FD_CONNECT 期望在套接字连接建立完成时接到通知
FD_CLOSE 期望在套接字关闭时接到通知
进行异步选择使用WSAAsyncSelect()函数时,有以下几点需要引起特别的注意:
.连续使用两次WSAAsyncSelect()函数时,只有第二次设置的事件有效,如:
WSAAsyncSelect(s,hwnd,wMsg1,FD_READ);
WSAAsyncSelect(s,hwnd,wMsg2,FD_CLOSE);
这样只有当FD_CLOSE事件发生时才会发送wMsg2消息。
.可以在设置过异步选择后通过再次调用WSAAsyncSelect(s,hwnd,0,0);的形式取消在套接字上所设置的异步事件。
.Windows Sockets DLL在一个网络事件发生后,通常只会给相应的应用程序发送一个消息,而不能发送多个消息。但通过使用一些函数隐式地允许重发此事件的消息,这样就可能再次接收到相应的消息。
.在调用过closesocket()函数关闭套接字之后不会再发生FD_CLOSE事件。
对UDP协议,这些网络事件主要为:
FD_READ 期望在套接字收到数据(即读准备好)时接收通知;
FD_WRITE 期望在套接字可发送数(即写准备好)时接收通知;
FD_CLOSE 期望在套接字关闭时接电通知
消息变量wParam指示发生网络事件的套接字,变量1Param的低字节描述发生的网络事件,高字包含错误码。如在窗口函数的消息循环中均加一个分支:
int ok=sizeof(SOCKADDR);
case wMsg;
switch(1Param)
{
case FD_READ: //套接字上读数据
if(recvfrom(sr.lpPlayData[j],dwDataSize,0,(struct sockaddr FAR*)&there1,
(int FAR*)&ok)==SOCKET_ERROR0) {
MessageBox(hwnd,“数据接收失败!”,“”,MB_OK);
return(FALSE);
}
case FD_WRITE: //套接字上写数据
}
break;
*WSAEventSelect
事件通知模型要求在程序中针对使用的每个套接字创建一个事件对象,然后通过事件模式通知程序其套接字是否收到或发送的信息。一般来说这种模式,一般就是通过类似调用waitformultipleObject一样在一个线程中等待信号事件来,来了就处理。具体调用的函数如下:
创建WSACreateEvent函数.该函数的返回值是一个创建好的事件对象句柄。事件对象句柄完后,接下来将其与某个套接字关联在一起,同时注册自己感兴趣的网络事件类型,方法是调用WSAEventSelect函数,对它的定义如下:
int WSAEventSelect (
SOCKET s, //需要非阻塞处理的套接字
WSAEVENT hEventObject, //WSACreateEvent 创建来的,关联到socket
long lNetworkEvents
);
lNetworkEvents,对应一个“位掩码”,用于指定应用程序感兴趣的各种网络事件类型的一个组合。要想获知对这些事件类型的详细说明,请参考早先讨论过的WSAAsyncSelect I/O模型。
为WSAEventSelect创建的事件拥有两种工作状态,以及两种工作模式。
两种工作状态分别是“已传信”(signaled)和 “未传信”(nonsignaled)。
工作模式则包括“人工”(manual reset)和“自动”(auto reset)。
WSACreateEvent缺省时其信号状态为0,且为人工设置,当网络事件触发了与一个套接字关联在一起的事件对象,其事件信号置1。在完成了一个I/O请求的处理之后,需要调用WSAResetEvent复位处理(置信号为0)。
一个套接字同一个事件对象句柄关联在一起后,应用程序便可开始I/O处理;方法是等待网络事件触发事件对象句柄的工作状态。
一般而言,在等待网络传来事件时,类似WaitforMultipleObject,其WSAWaitForMultipleEvents函数的设计宗旨便是用来等待一个或多个事件对象句柄,并在事先指定的一个或所有句柄进入有信号状态后,或在超过了一个规定的时间周期后,立即返回(线程往往在这里死等)。
下面是 WSAWaitForMultipleEvents函数的定义:
DWORD WSAWaitForMultipleEvents(
DWORD cEvents,
const WSAEVENT FAR *lphEvents,
BOOL fWaitAll,
DWORD dwTimeOUT,
BOOL fAlertable
);
其用法和WaitForMultipleObject类似。
cEvents和lphEvents参数定义了由WSAEVENT对象构成的一个数组。在这个数组中,cEvents指定的是事件对象的数量,而lphEvents对应的是一个指针,用于直接引用该数组。
要注意的是, WSAWaitForMultipleEvents只能支持由WSA_MAXIMUM_WAIT_EVENTS对象规定的一个最大值,在此定义成64个。故该I/O模型一次最多都只能支持64个套接字。假如想让这个模型同时管理不止64个套接字,必须创建更多的工作者线程,以便等待更多的事件对象。
fWaitAl l 参数指定了WSAWaitForMultiple Events如何等待在事件数组中的对象。
=TRUE,那么只有等lphEvents数组内包含的所有事件对象都处于有信号状态,函数才会返回;
=FALSE,任一个事件对象进入有信号时,函数就会返回。
dwTimeout参数规定了 WSAWaitForMultipleEvents最多可等待一个网络事件发生有多长时间。超过规定的时间,函数就会立即返回。并返回WSA_WAIT_TIMEOUT。如dwsTimeout设为WSA_INFIN ITE(永远等待),那么根据fWaiiAll或等待一个网络事件或所有网络事件都传信号后,才能从该函数退出。
fAlertable,缺省设为FALSE。主要用于在重叠式I/O模型中.
当设置fWaiAll=false,WaitForMultipleObject再有网络事件时,会返回一个值,指出造成函数返回的事件对象。根据WSAWaitForMultipleEvents的返回值,减去预定义值WSA_WAIT_EVENT_0,得到具体的引用值(即索引位置),程序便可用事件数组中已发信号的事件,检索与那个事件对应的套接字,知道了造成网络事件的套接字后,调用 WSAEnumNetworkEvents函数,调查发生了什么类型的网络事件。该函数定义如下:
int WSAEnumNetworkEvents (
SOCKET s, //检索该套接字
WSAEVENT hEventObject,
LPWSANETWORKEVENTS lpNetworkEvents
);
hEventObject参数则是可选的;它指定了一个事件句柄,对应于打算重设的那个事件对象。由于我们的事件对象处在一个有信号状态,所以可将它传入,令其自动成为无信号状态。
也可以采用使用 WSAResetEvent 函数复位事件信号。
lpNetworkEvents,就是返回的结果信息,它是一个指向WSANETWORKEVENTS结构的指针,用于接收套接字上发生的网络事件类型以及可能出现的任何错误代码。
其WSANETWORKEVENTS结构的定义:
typedef struct _WSANETWORKEVENTS
{
long lNetworkEvents;
int iErrorCode[FD_MAX_EVENTS];
} WSANETWORKEVENTS, FAR * LPWSANETWORKEVENTS;
lNetworkEvents参数指定了一个值,对应于套接字上发生的所有网络事件类型。
注意一个事件进入置1(有信号)状态时,可能会同时发生多个网络事件类型。如,一个忙的服务器可能同时收到FD_READ和FD_WRITE通知。 iErrorCode参数指定的是一个错误代码数组,同lNetworkEvents中的事件关联在一起。针对每个网络事件类型,都存在着一个特殊的事件索引,名字与事件类型的名字类似,只是要在事件名字后面添加一个“ _BIT”后缀字串即可。如,对FD_READ事件类型来说,iErrorCode数组的索引标识符便是FD_READ_BIT。
c++Socket 异步通讯的更多相关文章
- .net平台下socket异步通讯(代码实例)
你应该知道的.net平台下socket异步通讯(代码实例) 1,首先添加两个windows窗体项目,一个作为服务端server,一个作为客户端Client 2,然后添加服务端代码,添加命名空间,界面上 ...
- 你应该知道的.net平台下socket异步通讯(代码实例)
1,首先添加两个windows窗体项目,一个作为服务端server,一个作为客户端Client 2,然后添加服务端代码,添加命名空间,界面上添加TextBox控件 using System.Net; ...
- C#上位机之—WinForm实现Socket异步通讯示例
工作中常用到的一些知识点,总是用完就忘,第一次尝试用博客记录下来,以备后用: Socket通讯,Socket(套接字)是基于TCP/IP通讯方式的封装好的类,调用时需要添加下面的服务引用: using ...
- Socket异步通讯
1.可以通过多线程来解决(一会补上) 2.Socket在tcp/udp两种通信协议下的异步通信: 基于TCP的异步通信: BeginAccept方法和endeaccept方法 包含在System.Ne ...
- .net平台下socket异步通讯
1,首先添加两个windows窗体项目,一个作为服务端server,一个作为客户端Client 2,然后添加服务端代码,添加命名空间,界面上添加TextBox控件 using System.Net; ...
- C# socket异步通讯
Server: using System; using System.Net; using System.Net.Sockets; using System.Text; namespace TCP_S ...
- Socket网络通讯开发总结之:Java 与 C进行Socket通讯 + [备忘] Java和C之间的通讯
Socket网络通讯开发总结之:Java 与 C进行Socket通讯 http://blog.sina.com.cn/s/blog_55934df80100i55l.html (2010-04-08 ...
- socket异步编程--libevent的使用
使用 libevent 和 libev 提高网络应用性能 http://www.ibm.com/developerworks/cn/aix/library/au-libev/ libevent实现ht ...
- Socket异步发送的同步控制
在网络通信中,我们使用Socket异步发送数据,但在客户端,往往是需要等待服务器的返回结果后(握手过程)再往下执行,这就涉及到同步控制了,在多次的实现中,使用AutoResetEvent,实现不,即有 ...
随机推荐
- js添加onclick函数
document.getElementById('Add').setAttribute("onclick",AddNum()); 相当于不停的调用Addnum函数 应改成docum ...
- sql 判断表、列、视图等是否存在
1 判断数据库是否存在 if exists (select * from sys.databases where name = '数据库名') drop database [数据库名] 2 判 ...
- 安卓手机内外SD卡互换
相信有許多人....有內置sd太小...外置sd(sdcard2或extsd)卻只能放資料.... 一些遊戲或者是影音播放軟體....根本不會去讀外置sd(sdcard2或extsd)..... 記憶 ...
- (六)Angularjs - 启动引导
自动引导 AngularJs 通过 ng-app 指令进行自动引导 手工引导启动框架 如果一个HTML文件中 有多个ng-app,AngularJS只会自动引导启动它找到的第一个ng-app应用,这是 ...
- Java集合类笔试题
介绍Collection框架的结构 Collection接口是单值存放的最大父接口,可以向其中保存多个单值的数据(所谓单值就是指集合中的每个元素都是一个对象).其子接口主要有:List.Set.Que ...
- mysql服务启动
1.C:\Program Files (x86)\MySQL\mysql-5.5.33-win32\bin>net stop mysqlMySQL 服务正在停止.MySQL 服务已成功停止. 2 ...
- JGraph
php中JPGraph入门配置与应用 什么是PHP JPGraph?专门提供图表的类库.它使得作图变成了一件非常简单的事情.生成非美工人士生成的图表.二维码算法. 到官方网站下载.docportal ...
- ural 1090 In the Army Now
http://acm.timus.ru/problem.aspx?space=1&num=1090 #include <cstdio> #include <cstring&g ...
- Altium Designer 6 快速进行差分对走线
1: 在原理图中让一对网络前缀相同,后缀分别为_N 和_P,并且加上差分队对指示.在原理图中,让一对网络名称的前缀名相同,后缀分别为_N 和_P,左键点击Place DirectivesDiffere ...
- Printing Architecture
Printing Architecture http://www.codeproject.com/Articles/8916/Printing-Architecture This articl ...