博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
select模式
阅读量:6324 次
发布时间:2019-06-22

本文共 3221 字,大约阅读时间需要 10 分钟。

在很多比较各种网络模型的文章中,但凡提到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++的东西,这个技巧将不再安全(
)。其实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 handlingfor( 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,判断方式同上} 两种方式的效率从代码上看去似乎都差不多,关键在于,FD_ISSET干了什么?这个宏实际上使用了__WSAFDIsSet函数,而__WSAFDIsSet做了什么则不知道。也许它会依赖于FD_SETSIZE宏,那么这在我们这里将是不安全的,所以相比之下,如果我们使用了这个突破FD_SETSIZE的偏方手段,那么也许第二种方式要好些。

其实我就是想看看select模式到底是啥,不知libeventwindows下用的是select还是iocp,select模式怎么突破64啊

转载地址:http://tslaa.baihongyu.com/

你可能感兴趣的文章
Spring 反射注入+全注解注入
查看>>
FreeMarker中文API手冊(完整)
查看>>
LINQ to SQL 建立实体类
查看>>
不必仰望他人,用自己的方式活着就好
查看>>
java中接口的定义与实现
查看>>
如何成为伟大的程序员
查看>>
ASP.NET中的KRE是什么?
查看>>
UIButton 一个控件 实现 左图标右文本的效果
查看>>
Android应用程序窗口(Activity)的测量(Measure)、布局(Layout)和绘制(Draw)过程分析...
查看>>
Oracle的DML语言必备基础知识
查看>>
ArcGIS10.2最新全套下载地址
查看>>
UVa 1593 - Alignment of Code
查看>>
VS2013启动项目调试的时候会启动本地IIS
查看>>
Unity3D移动平台动态读取外部文件全解析
查看>>
七参数计算正确性验证——Coord软件使用
查看>>
Wince 中的图形编程
查看>>
Sql Server内置函数实现MD5加密
查看>>
给想跨专业考研的学生——消除顾虑,做好安排
查看>>
Android tab_Host页面跳转,传值,刷新等问题汇总
查看>>
QTP之web常用对象
查看>>