注意:上面的代码没有任何检查函数返回值,如果你作网络编程就一定要
检查任何一个Winsock API函数的调用结果,因为很多时候函数调用
并不一定成功.上面介绍的函数,返回值类型是int的话,如果函数调
用失败的话,返回的都是SOCKET_ERROR.
5。Winsock编程的五种模型
上面介绍的仅仅是最简单的winsock通讯的方法,而实际中很多网络
通讯的却很多难以解决的意外情况.
例如,Winsock提供了两种套接字模式:锁定和非锁定.当我们使用锁
定套接字的时候,我们使用的很多函数,例如accpet,send,recv等等,
如果没有数据需要处理,这些函数都不会返回,也就是说,你的应用程
序会阻塞在那些函数的调用处.而 如果使用非阻塞模式,调用这些函
数,不管你有没有数据到达,他都会返回,所以,有可能我们在非阻塞
模式里,调用这些函数大部分的情况下会返回失败,所以就需要我们
来处理很多的意外出错.
这显然不是我们想要看到的情况.我们可以采用Winsock的通讯模型
来避免这些情况的发生。
Winsock提供了五种套接字I/O模型来解决这些问题.他们分别是
select(选择),WSAAsyncSelect(异步选择),
WSAEventSelect (事件选择), overlapped(重叠) , completion
port(完成端口) .
我们在这里详细介绍一下select,WSAASyncSelect两种模型.
select模型是最常见的I/O模型.
使用
int select( int nfds , fd_set FAR* readfds , fd_set FAR* writefds , fd_set FAR* exceptfds ,
const struct timeval FAR * timeout ) ;
函数来检查你要调用的socket套接字是否已经有了需要处理的数据.
select包含三个socket队列,分别代表:
readfds ,检查可读性,writefds,检查可写性,exceptfds,例外数据.
timeout是select函数的返回时间.
例如,我们想要检查一个套接字是否有数据需要接收,我们可以把套
接字句柄加入可读性检查队列中,然后调用select,如果,该套接字没
有数据需要接收,select函数会把该套接字从可读性检查队列中删除
掉,所以我们只要检查该套接字句柄是否还存在于可读性队列中,就
可以知道到底有没有数据需要接收了.
Winsock提供了一些宏用来操作套接字队列fd_set.
FD_CLR( s,*set) 从队列set删除句柄s.
FD_ISSET( s, *set) 检查句柄s是否存在与队列set中.
FD_SET( s,*set )把句柄s添加到队列set中.
FD_ZERO( *set ) 把set队列初始化成空队列.
WSAAsyncSelect(异步选择)模型:
WSAASyncSelect模型就是把一个窗口和套接字句柄建立起连接,套接
字的网络事件发生时时候,就会把某个消息发送到窗口,然后可以在
窗口的消息响应函数中处理数据的接收和发送.
int WSAAsyncSelect( SOCKET s, HWND hWnd , unsigned int wMsg , long lEvent ) ;
这个函数可以把套接字句柄和窗口建立起连接,
wMsg 是我们必须自定义的一个消息.
lEvent就是制定的网络事件.包括FD_READ , FD_WRITE , FD_ACCEPT
, FD_CONNECT , FD_CLOSE .
几个事件.
例如,我需要接收FD_READ , FD_WRITE , FD_CLOSE 的网络事件.可
以调用
WSAAsyncSelect( s , hWnd , WM_SOCKET , FD_READ | FD_WRITE | FD_CLOSE ) ;
这样,当有FD_READ , FD_WRITE 或者 FD_CLOSE网络事件时,窗口
hWnd将会收到WM_SOCKET消息,消息参数的lParam标志了是什么事件
发生.
其实大家应该见过这个模型,因为MFC的CSocket类,就是使用这个模
型.
上面为大家介绍了Winsock编程的一些方法.