socket模型使归纳

共有五种类型的套接字I/O模型,可让Winsock应用程序对I/O进行管理,它们包括:select(选择)、WSAAsyncSelect(异步选择)、WSAEventSelect(事件选择)、overlapped(重叠)以及completion port(完成端口)

1.select
最初设计该模型,主要是面向某些使用Unix操作系统的计算机.使用大概原理设置一个集合,通过一个宏的定义来查询集合类的套接字可否使用。做个端口扫描用这个还是比较开心的。

2.WSAAsyncSelect
模仿WINDOWS消息机制来实现,使用起来很方便。个人比较喜欢。MFC中的CSOCKET也采用了这个模型。
相关函数:
int WSAAsyncSelect(SOCKET s, HWND hWnd, unsigned int wMsg, long lEvent);
lEvent表示一个掩码组合,比如FD_CONNECT|FD_READ

LREWULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
wParam: 发生了一个网络事件的套接字
lParam: (低位)指定了已经发生的网络事件WSAGETSELECTEVENT (高位)包含了可能出现的任何错误代码 用WSAGETSELECTERROR获取

大概使用框架如下:
创建套接字,使用WSAAsyncSelect进行套接字和事件绑定,在回调函数中写清消息响应

#define WM_SOCKET WM_USER+1
int WINAPI WinMain(HINSTANCE hINstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
SOCKET Listen;
HWND Window;
//Create a window and assign the winproc
//Start Winsock and create a socket
WSAStartup(...);
Listen = Socket();
bind(...);
WSAAsyscSelect(Listen, Window, WM_SOCKET, FD_ACCEPT | FD_CLOSE);
listen(Listen, 5);
}

BOOL CALLBACK WinProc(HWND hDlg, WORD wMsg, WORD wParam, DWORD lParam)
{
SOCKET Accept;
switch(wMsg)
{
case WM_SOCKET:
//whether an error occurred on the socket by using the WSAGETSELECTERROR() macro
if(WSAGETSELECTERROR(lParam))
{
closesocket...
}
//what event occurred on the socket
switch( WSAGETSELECTEVENT(lParam) )
{
case FD_ACCEPT:
case FD_READ:
case FD_WRITE:
}
}
}

FD_WRITE说明:三种条件下才会发出
使用connect WSAConnect,一个套接字首次建立连接
使用accept WSAAccept,套接字被接受以后
若send WSASend sendto WSASendTo操作失败,返回WSAEWOULDBLOCK错误,而且缓冲区空间变得可用
也就是说,收到首条FD_WRITE消息,便应认为自己必然能在一个套接字上发数据.

3 WSAEventSelect
你可以想象着,一排的空套接字等着对方的连接...
如上章所述,async投递一个窗口例程,而Event投递一个事件对象句柄.
或者更清楚解释为,套接字和事件对象对应着,当一个套接字有事件发生,事件对象返回相应的值,通过这个值来索引这个套接字。
要注意该模式里两种工作状态和模式,signaled/nonsignaled manual reset/auto reset
一开始默认为未传信(nonsignaled)和人工重设(manual reset)状态,随着网络事件的触发,工作状态从未船信到已传信.在完成一个I/O请求处理后,要负责将工作状态改变

首先创建一个事件对象 WSAEVENT WSACreateEvent(void);
其次将事件对象和套接字联系在一起 int WSAEventSelect(SOCKET s, WSAEVENT hEventObject, long lNetworkEvents);
等待网络事件触发事件对象句柄状态 DWORD WSAWaitForMultipleEvents(....DWORD dwTimeout, BOOL fAlertable);
dwTimeout参数规定等待一个网络事件发生有多长时间,毫秒为单位.超过立即返回,即使由fWaitAll参数规定条件未满足也如此.如果设为0,函数会检测指定的事件对象状态,然后返回.这样造成一个"轮询",尽量避免设为0.若设为WSA_INFINITE,那么只有在一个网络事件传回一个事件对象后,才会返回.
fAlertable:忽略,设为FALSE,主要用于重叠式I/O模型中

将已传信状态更改为未传信 BOOL WSAResetEvent(WSAEVENT hEvent);
释放事件句柄使用的系统资源 BOOL WSACloseEvent(WSAEVENT hEvent);

现在还需解决的一问题是,怎么获得发生事件的套接字,async直接用一个socket变量接收,而在event里,是通过事先的一个数组索引获得.这个方法名为WSAEnumNetworkEvents();

代码框架如下:
//先创建事件数组和套接字数组
SOCKET Socket[常量];
WSAEVENT Event[];
DWORD EvenTotal = 0;
//这里进行套接字准备到bind那步,创建一个事件,并且联系
NewEvent = WSACreateEvent();
WSAEventSelect(Listen, NewEvent, FD_ACCEPT|FD_CLOSE);

//最重要一步,加入到数组
Socket[EventTotal] = Listen;
Event[EventTotal] = NewEvent;
EventTotal++;

while(TRUE)
{
//等待一个套接字连接
Index = WSAWaitForMultipleEvents(..);
//在EnumNetworkEvents中进行查询,判断在哪个套接字上,发生什么网络事件类型.
WSAEnumNetworkEvents(
SocketArray[Index - WSA_WAIT_EVENT_0],
EventArray[Index - WSA_WAIT_EVENT_0],
NetworkEvents);

}


对一个发生事件套接字操作
WSAWaitForMultipleEvents返回值:减去预定值WSA_WAIT_EVENT_0
Iindex = WSAWaitForMultipleEvents(..);
MyEvent = EventArray[Index - WSA_WAIT_EVENT_0];
接下来可调用WSAEnumNetworkEvents函数,调查发生什么类型网络事件


4IO重叠
对一个套接字多次利用,利用CRITICAL_SECTION来进行互斥

5。。。略
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值