Select() 与 ioctlsocket()

Select() 与 ioctlsocket()

Winsock 的I/O操作:

 1、 两种I/O模式   

  * 阻塞模式:执行I/O操作完成前会一直进行等待,不会将控制权交给程序。套接字 默认为阻塞模式。可以通过多线程技术进行处理。    

 * 非阻塞模式:执行I/O操作时,Winsock函数会返回并交出控制权。这种模式使用 起来比较复杂,因为函数在没有运行完成就进行返回,会不断地返回 WSAEWOULDBLOCK错误。但功能强大。 为了解决这个问题,提出了进行I/O操作的一些I/O模型,下面介绍最常见的三种: 

 

2、select模型:   

通过调用select函数可以确定一个或多个套接字的状态,判断套接字上是否有数据,或者能否向一个套接字写入数据。    

   int  Select( int nfds, fd_set FAR * readfds, fd_set FAR * writefds, fd_set FAR *exceptfds, const struct timeval FAR * timeout );      

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队列初始化成空队列。  

◆先来看看涉及到的结构的定义:

<A>  fd_set结构: 

#define FD_SETSIZE 64?

typedef struct fd_set 

{
u_int fd_count; /* how many are SET? */

SOCKET fd_array[FD_SETSIZE]; /* an array of SOCKETs */
} fd_set;      

 fd_count为已设定socket的数量fd_array为socket列表,FD_SETSIZE为最大socket数量,建议不小于64。这是微软建议的。

 <B> timeval结构: 

struct timeval 
{
long tv_sec; /* seconds */
long tv_usec; /* and microseconds */
}; 
tv_sec为时间的秒值。tv_usec为时间的毫秒值。
这个结构主要是设置select()函数的等待值,如果将该结构设置为(0,0),则select()函数会立即返回。 

◆再来看看select函数各参数的作用:   
1. nfds:没有任何用处,主要用来进行系统兼容用,一般设置为0。   
2. readfds:等待可读性检查的套接字组。   
3. writefds;等待可写性检查的套接字组。   
4. exceptfds:等待错误检查的套接字组。   
5. timeout:超时时间。   
6. 函数失败的返回值:调用失败返回SOCKET_ERROR,超时返回0。 readfds、writefds、exceptfds三个变量至少有一个不为空,同时这个不为空的套接字组种至少有一个socket,道理很简单,否则要select干什么呢。 

举例:测试一个套接字是否可读: 

fd_set fdread;//FD_ZERO定义
// #define FD_ZERO(set) (((fd_set FAR *)(set))->fd_count=0)
FD_ZERO(&fdread);
FD_SET(s,&fdread);
//加入套接字,详细定义请看winsock2.h
if(select(0,%fdread,NULL,NULL,NULL)>0
{        
//成功    
    if(FD_ISSET(s,&fread) //是否存在fread中,详细定义请看winsock2.h        
     {              
               //是可读的        
      }

 

◆I/O操作函数:主要用于获取与套接字相关的操作参数。  
int  ioctlsocket(SOCKET s, long cmd, u_long FAR * argp );     
 s为I/O操作的套接字。cmd为对套接字的操作命令。argp为命令所带参数的指针。 
常见的命令: 
//确定套接字自动读入的数据量#define FIONREAD _IOR(''''f'''', 127, u_long) /* get # bytes to read */
//允许或禁止套接字的非阻塞模式,允许为非0,禁止为0#define FIONBIO _IOW(''''f'''', 126, u_long) /* set/clear non-blocking i/o */
//确定是否所有带外数据都已被读入#define SIOCATMARK _IOR(''''s'''', 7, u_long) /* at oob mark? */ 本函数可用于任一状态的任一套接口。它用于获取与套接口相关的操作参数,而与具体协议或通讯子系统无关。

支持下列命令:  
FIONBIO:允许或禁止套接口s的非阻塞模式。argp指向一个无符号长整型。如允许非阻塞模式则非零,如禁止非阻塞模式则为零。当创建一个套接口时,它就处于阻塞模式(也就是说非阻塞模式被禁止)。这与BSD套接口是一致的。WSAAsynSelect()函数将套接口自动设置为非阻塞模式。如果已对一个套接口进行了WSAAsynSelect() 操作,则任何用ioctlsocket()来把套接口重新设置成阻塞模式的试图将以WSAEINVAL失败。为了把套接口重新设置成阻塞模式,应用程序必须首先用WSAAsynSelect()调用(IEvent参数置为0)来禁至WSAAsynSelect()。  
FIONREAD:确定套接口s自动读入的数据量。argp指向一个无符号长整型,其中存有ioctlsocket()的返回值。
如果s是SOCKET_STREAM类型,则FIONREAD返回在一次recv()中所接收的所有数据量。这通常与套接口中排队的数据总量相同。
如果S是SOCK_DGRAM 型,则FIONREAD返回套接口上排队的第一个数据报大小。  
SIOCATMARK:确实是否所有的带外数据都已被读入。这个命令仅适用于SOCK_STREAM类型的套接口,且该套接口已被设置为可以在线接收带外数据(SO_OOBINLINE)。如无带外数据等待读入,则该操作返回TRUE真。否则的话返回FALSE假,下一个recv()或recvfrom()操作将检索“标记”前一些或所有数据。应用程序可用SIOCATMARK操作来确定是否有数据剩下。如果在“紧急”(带外)数据前有常规数据,则按序接收这些数据(请注意,recv()和recvfrom()操作不会在一次调用中混淆常规数据与带外数据)。argp指向一个BOOL型数,ioctlsocket()在其中存入返回值。 

兼容性:  本函数为Berkeley套接口函数ioctl()的一个子集。其中没有与FIOASYNC等价的命令,SIOCATMARK是套接口层次支持的唯一命令。 

返回值:  成功后,ioctlsocket()返回0。否则的话,返回SOCKET_ERROR错误,应用程序可通过WSAGetLastError()获取相应错误代码。

错误代码:  

WSANOTINITIALISED:在使用此API之前应首先成功地调用WSAStartup()。  

WSAENETDOWN:WINDOWS套接口实现检测到网络子系统失效。  

WSAEINVAL:cmd为非法命令,或者argp所指参数不适用于该cmd命令,或者该命令不适用于此种类型的套接口。  

WSAEINPROGRESS:一个阻塞的WINDOWS套接口调用正在运行中。  

WSAENOTSOCK:描述字不是一个套接口。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值