突破select的FD_SETSIZE限制

前言:

在很多比较各种网络模型的文章中,但凡提到select模型时,都会说select受限于轮询的套接字数量,这个
数量也就是系统头文件中定义的FD_SETSIZE值(例如64)。但事实上这个算不上真的限制。

C语言的偏方:

在C语言的世界里存在一个关于结构体的偏门技巧,例如:

 

typedef struct _str_type
{
   
int _len;
   
char _s[1];
}
str_type;

 

str_type用于保存字符串(我只是举例,事实上这个结构体没什么用处),乍看上去str_type只能保存长度为
1的字符串('\0')。但是,通过写下如下的代码,你将突破这个限制:

int str_len = 5;
str_type
*s = (str_type*) malloc( sizeof( str_type ) + str_len - 1 );
//
free( s );


这个技巧原理很简单,因为_s恰好在结构体尾部,所以可以为其分配一段连续的空间,只要注意指针的使用,
这个就算不上代码上的罪恶。但是这个技巧有个限制,str_type定义的变量必须是被分配在堆上,否则会破
坏堆栈。另外,需要动态增长的成员需要位于结构体的末尾。最后,一个忠告就是,这个是C语言里的技巧,
如果你的结构体包含了C++的东西,这个技巧将不再安全(<Inside the C++ object model>)。

其实select也可以这样做:

事实上,因为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;


但是,如果使用了以上技巧来增加fd_array的数量(也就是保存的套接字数量),那么关于fd_set的那些宏可
能就无法使用了,例如FD_SET。

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)


有点让人眼花缭乱,我鼓励你仔细看,其实很简单。这里有个小技巧,就是他把这些代码放到一个do...while(0)
里,为什么要这样做,我觉得应该是防止名字污染,也就是防止那个__i变量与你的代码相冲突。可以看出,
FD_SET会将fd_count与FD_SETSIZE相比较,这里主要是防止往fd_array的非法位置写数据。

因为这个宏原理不过如此,所以我们完全可以自己写一个新的版本。例如:

#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 )


没什么变化,只是为FD_SET加入一个fd_array的长度参数,宏体也只是将FD_SETSIZE换成这个长度参数。
于是,现在你可以写下这样的代码:

unsigned int count = 100;
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 );


小提下select模型:

这里我不会具体讲select模型,我只稍微提一下。一个典型的select轮询模型为:

int r = select( 0, &read_set, 0, 0, &timeout );
if( r < 0 )
{
   
// select error
}
 

if( r > 0 )
{
   
for( each sockets )
   
{
       
if( FD_ISSET( now_socket, &read_set ) )
       
{
           
// this socket can read data
        }

    }

}
 


轮询write时也差不多。在Etwork(一个超小型的基本用于练习网络编程的网络库,google yourself)中,作者
的轮询方式则有所不同:

// read_set, write_set为采用了上文所述技巧的fd_set类型的指针
int r = select( 0 , read_set, write_set, 0 , & timeout );
//   error handling
for ( int i =   0 ; i < read_set -> fd_count; ++ i )
{
   
// 轮询所有socket,这里直接采用read_set->fd_array[i] == now_socket判断,而不是FD_ISSET
}
 

for ( int i =   0 ; i < write_set -> fd_count; ++ i )
{
   
// 轮询所有socket,检查其whether can write,判断方式同上
}
 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/434840.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

袋装树和随机森林的区别

装袋法建树的时候是将所有预测变量都考虑进去&#xff0c; 而随机森林则是考虑每一个分裂点时&#xff0c;都是从所有的预测变量p中随机选取m个预测变量&#xff0c;分裂点所用的预测变量只能从这m个变量中选择。

如何导入maven源文件_如何正确导入maven项目到eclipse?

Eclipse不允许一个项目被导入不止一次,在您的情况下,来自中继线和分支.This article显示了如何通过自定义maven配置文件绕过此限制.基本上,步骤是&#xff1a;>将以下配置文件添加到您的父pom.xml中append-to-project-nameappend.to.project.namemaven-eclipse-plugin[artif…

画廊效果

http://www.no3dfx.com/polaroid/ 转载于:https://www.cnblogs.com/bearhb/archive/2011/10/12/2208162.html

python镜像

Python国内镜像地址&#xff1a; 1.阿里云&#xff1a;https://mirrors.aliyun.com/pypi/simple/ 2.豆瓣&#xff1a;https://pypi.douban.com/simple/ 3.清华大学&#xff1a;https://pypi.tuna.tsinghua.edu.cn/simple/ 4.中国科学技术大学 http://pypi.mirrors.ustc.edu.cn/…

socket 编程入门教程(一)TCP server 端:3、sockaddr与sockaddr_in

收件人地址一家化妆品公司将一批新产品的样品&#xff0c;准备发给某学校某个班的女生们免费试用。通常情况下&#xff0c;这件邮包的地址上可以这么写&#xff1a;收件人&#xff1a;全体女生。 地址&#xff1a;A省B市C学校&#xff0c;X级Y班。但是&#xff0c;如果在描述地…

python语言为什么叫python_Python为什么叫Python,Java又如何而来?

你可能听过这样一种说法&#xff1a;在计算机科学领域&#xff0c;只有两件困难的事情&#xff0c;其中一件是给事物命名。有些编程语言的名字很有意义&#xff0c;比如谷歌(Google)将它的编程语言命名为Go(lang)&#xff0c;而其他的名字——比如Python和Java——为什么要这么…

arcgis中的SetNull(,)函数使用

SetNull(设置条件&#xff0c;将条件之内的值变为nodata,条件之外的值处理) 例如&#xff1a; 1.setnull("DEM"500,"DEM"),将DEM中值为500的数据赋为空&#xff0c;其他保留原值 2.setnull("DEM">500,"DEM"),将DEM中值大于500的…

pyqt5设置dialog的标题_PyQt5快速上手基础篇7-弹出dialog

前言本节我们学习QDialog的使用&#xff0c;在主页面点击按钮弹出一个新的Dialog。一、基础知识1. dialog简介窗口是GUI设计中不可获取的一部分&#xff0c;方便用户和程序直接交互&#xff0c;简化使用&#xff1b;Qdialog主要包含QInputDialog、QColorDialog、QFontDialog、Q…

67、ulimit的使用

1、ulimit set or get the shells resource usage limits ulimit [OPTIONS] [LIMIT] 2、option ① -a 显示当前所有的资源限制。 ② -c size:设置core文件的最大值。单位:blocks ③ -n size 指定同一时间最多可开启的文件数 ④ -l size:设置在内存中锁定进程的最大值。单位:KB…

如何处理MODIS蒸散数据(ET)中的填充值(仅作参考)

该处理过程是个人想法&#xff0c;仅做参考&#xff0c;如果想要等到比精确的蒸散数据请参考《京津唐地区城市扩张对地表蒸散发的影响》中蒸散的计算过程。 MOD16A3 第 6 版蒸发蒸腾/潜热通量产品是按 500 米 (m) 像素分辨率生成的年度复合数据集。 根据《京津唐地区城市扩张对…

winform定义数据源名称_winform ComboBox自定义数据源实现用户输入时出现与用户输入匹配的项...

ComboBox自定义数据源实现用户输入时出现与用户输入匹配的项using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Windows.Forms;namespace _2012_11_15Pra…

如何计算栅格有效值范围内的统计值(最大值,最小值,平均值,方差)

大致思路&#xff1a; 1.将无效值设置为空(nodata) 2.对栅格进行计算 使用数据为&#xff1a;modis的蒸散数据&#xff08;有效值范围为0 至 65500&#xff0c;填充值范围为65529 至 65535&#xff09; 步骤 1&#xff0c;利用栅格计算器将填充值进行设置为空 结果 2计算栅…

RMAN 备份报错 RMAN-06207 RMAN-06208 解决方法

新搭建的环境&#xff0c;还没上线&#xff0c;今天在部署脚本&#xff0c;RMAN 备份中有一个警告&#xff0c;内容如下&#xff1a;RMAN-06207: WARNING: 1 objects could not bedeleted for DISK channel(s) dueRMAN-06208: to mismatched status. Use CROSSCHECK …

用python画明星_用python画一只可爱的皮卡丘实例

效果图片# !\/usr\/bin\/env python # - * -编码:utf - 8 - *\u2014\u2014从龟进口*\u201C画皮卡丘的头\u201Cdef的脸(x, y):\u201D\u201C画脸\u201D\u201Cbegin_fill () penup () # goto乌龟移动到指定的坐标(x, y) pendown() #设置的方向龟setheading(40)圆(-150、69)fillcol…

socket 编程入门教程(一)TCP server 端:1、建模

绝大部分关于socket编程的教程总是从socket的概念开始讲起的。要知道&#xff0c;socket的初衷是个庞大的体系&#xff0c;TCP/IP只是这个庞大体系下一个很小的子集&#xff0c;而我们真正能用上的更是这个子集中的一小部分&#xff1a;运输层&#xff08;Host-to-Host Transpo…

socket 编程入门教程(一)TCP server 端:2、socket与文件描述符

UNIX中的一切事物都是文件&#xff08; everything in Unix is a file!&#xff09;当我在这篇教程中提到UNIX的时候&#xff0c;其意思专指符合UNIX标准的所谓“正统”UNIX的衍生系统&#xff08;其实我就用来带指那些买了最初UNIX源代码的商业系统&#xff09;操作系统和类似…

linux 故障注入_用软件中断实现的Linux内核故障注入方法

用软件中断实现的Linux内核故障注入方法郭庆伟;杨麦顺;张影;张兴军【期刊名称】《计算机应用》【年(卷),期】2014(000)0z2【摘要】针对容错操作系统的可靠性评测问题&#xff0c;提出一种向Linux内核注入“单个位”故障的方法。基于x86体系结构中的软件中断机制&#xff0c;首先…

arcgis将一个字段里的文字按上下标进行显示

示例 代码如下 def FindLabel ( [分区代号] ):a [分区代号]ba[0:1]<sub>a[1:2]</sub>return b

【转载】我对研发工作的一点感悟

一、现有状况分析不 觉新人来到我们研发已近一年&#xff0c;这一年里&#xff0c;同一批人员&#xff0c;有的已经很快适应了环境&#xff0c;经过自己的努力和付出&#xff0c;能为研发工作独挡一面&#xff0c;成为某一方面的小专家&#xff1b;有的 尽管前期不太适应&#…