select的套接字数量的限制

select模型时,被轮训的套接字的数量收到宏FD_SETSIZE的限制(linux下默认是1024,windows是64)。可以使用技巧绕过这个限制(因为select模型的轮训特性,不推荐把轮训套接字的数量设置很大)。


1、数组长度的拓展

在C语言的一个技巧来拓展结构体中的最后一个成员数组的长度,代码如下:
typedef struct _str_type
{
    int _len;
    char _s[1];
}str_type;
 
int str_len = 100;//要把_s拓展成100字节
str_type *s = (str_type*) malloc( sizeof( str_type ) + str_len - 1 );
free( s ); 


要求:
1)需要动态增长的成员必须位于结构体的末尾。_s恰好在结构体尾部,所以可以为其分配一段连续的空间。
2)str_type定义的变量需要分配在足够长的堆或者栈内存上。
3)结构体内不可含有c++的东西,否则不安全。实际上应该是不能包含虚表。(参考<Inside the C++ object model>)


2、select的应用例子

(1)fd_set结构

select涉及到的fd_set是一个完全满拓展要求的结构体:
winsock2.h : 
typedef struct fd_set {
        u_int fd_count;               /* how many are SET? */
        SOCKET  fd_array[FD_SETSIZE];   /* an array of SOCKETs */
} fd_set; 


(2)自定义的宏

需要使用自定义的宏来加入数组。
因为c库版本的添加描述符到数组的宏如下,是包含库的宏FD_SETSIZE
winsock2.h : 
#define FD_SET(fd, set) do { \
    u_int __i; \
    for (__i = 0; __i < ((fd_set FAR *)(set))->fd_count; __i++) { \
        if (((fd_set FAR *)(set))->fd_array[__i] == (fd)) { \
            break; \
        } \
    } \
    if (__i == ((fd_set FAR *)(set))->fd_count) { \
        if (((fd_set FAR *)(set))->fd_count < FD_SETSIZE) { \
            ((fd_set FAR *)(set))->fd_array[__i] = (fd); \
            ((fd_set FAR *)(set))->fd_count++; \
        } \
    } \
} while(0) 




写一个自己版本的添加描述符到数组的宏
#define MY_FD_SET( fd, set, size ) do { \
    unsigned int i = 0; \
    for( i = 0; i < ((fd_set*) set)->fd_count; ++ i ) { \
        if( ((fd_set*)set)->fd_array[i] == (fd) ) { \
            break; \
        } \
    } \
    if( i == ((fd_set*)set)->fd_count ) { \
        if( ((fd_set*)set)->fd_count < (size) ) { \
            ((fd_set*)set)->fd_array[i] = (fd); \
            ((fd_set*)set)->fd_count ++; \
        } \
    } \
} while( 0 ) 


(3)加入描述符到数组

unsigned int count = 2000;
//修改成了自己指定的2000个套接字的限制了(个数可以自定定)
fd_set *read_set = (fd_set*) malloc( sizeof( fd_set ) + sizeof(SOCKET) * (count - FD_SETSIZE ) );
SOCKET s = socket( AF_INET, SOCK_STREAM, 0 );
MY_FD_SET( s, read_set, count );
free( read_set );
closesocket( s ); 

(4)select实例代码

1)轮询read
int r = select( 0, &read_set, 0, 0, &timeout );
if( r < 0 )
{
    // select error
} 
else if( r > 0 )
{
    for( each sockets )
    {
        if( FD_ISSET( now_socket, &read_set ) ) 
        {
            // this socket can read data
        }
    }
} 


2)轮询write 和read
// read_set, write_set使用了上文所述技巧的fd_set类型的指针
int r = select( 0, read_set, write_set, 0, &timeout );
if( r < 0 )
{
    // select error
}  
for( int i = 0; i < read_set->fd_count; ++ i )
{
    // 轮询socket(不使用FD_ISSET)
    if(read_set->fd_array[i] == now_socket)
    {
    //do reading 
    }
} 


for( int i = 0; i < write_set->fd_count; ++ i )
{
    // 轮询socket
    if(write_set->fd_array[i] == now_socket)
    {
    //do writing 
    }
} 


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值