青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

loop_in_codes

低調做技術__歡迎移步我的獨立博客 codemaro.com 微博 kevinlynx

突破select的FD_SETSIZE限制

Author : Kevin Lynx 

前言:

在很多比較各種網絡模型的文章中,但凡提到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變量與你的代碼相沖突??梢钥闯觯?br>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,判斷方式同上
}
 


兩種方式的效率從代碼上看去似乎都差不多,關鍵在于,FD_ISSET干了什么?這個宏實際上使用了__WSAFDIsSet
函數,而__WSAFDIsSet做了什么則不知道。也許它會依賴于FD_SETSIZE宏,那么這在我們這里將是不安全的,
所以相比之下,如果我們使用了這個突破FD_SETSIZE的偏方手段,那么也許第二種方式要好些。

相關下載(5.21.2008)

隨便寫了一個改進的select模型的echo服務器,放上源碼。

posted on 2008-05-20 11:20 Kevin Lynx 閱讀(22442) 評論(12)  編輯 收藏 引用 所屬分類: game developnetwork

評論

# re: 突破select的FD_SETSIZE限制 2008-05-20 11:49 2nd guest

何必搞那么復雜,叫人怎么維護呢?  回復  更多評論   

# re: 突破select的FD_SETSIZE限制 2008-05-20 13:03 Kevin Lynx

@2nd guest
我覺得這個東西不復雜,只要保持模塊對外接口的簡潔,維護這么小的模塊不會那么復雜。  回復  更多評論   

# re: 突破select的FD_SETSIZE限制 2008-05-20 13:16 eXile

可以參考 boost::asio中的detail/win_fd_set, 很簡單  回復  更多評論   

# re: 突破select的FD_SETSIZE限制 2008-05-20 14:24 Kevin Lynx

@eXile
謝謝提醒,win_fd_set_adapter.hpp確實是個方案。那估計是用__WSAFDIsSet也不是問題了。:)   回復  更多評論   

# re: 突破select的FD_SETSIZE限制 2008-05-20 16:44 hsen

__WSAFDIsSet 好像是Windows的API吧。Windows下的select有這個限制嗎?  回復  更多評論   

# re: 突破select的FD_SETSIZE限制[未登錄] 2008-05-24 20:40 christanxw

多此一舉。直接重新FD_SETSIZE不就是了,何必搞這么復雜。  回復  更多評論   

# 突破select的FD_SETSIZE限制[未登錄] 2008-05-24 20:41 christanxw

多此一舉。直接重新定義FD_SETSIZE不就是了,何必搞這么復雜。  回復  更多評論   

# re: 突破select的FD_SETSIZE限制 2008-07-03 01:47 denny

@christanxw

正因為FD_SETSIZE是系統宏,所有才有這個問題,要不你重新編譯內核,那么這種解決方案也不具有通用性  回復  更多評論   

# re: 突破select的FD_SETSIZE限制 2008-10-29 11:42 itssunny

其實沒必要這么費勁,只要在包含 winsock2.h 頭文件的前面重新define 一下 FD_SETSIZE 的值就可以修改這個限制。但為了性能考慮這樣做沒什么太大意義,最好還是用重疊io或完成端口等異步模型性能好。  回復  更多評論   

# re: 突破select的FD_SETSIZE限制[未登錄] 2010-05-14 23:58 ttylikl

do{}while(0)的解釋錯誤呢
考慮這種情況:
if(****)
FD_SET(....);
else
FD_SET(....);

這個時候do {} while(0)就很重要啦。  回復  更多評論   

# re: 突破select的FD_SETSIZE限制 2011-01-21 11:10 jmzz

直接重新定義FD_SETSIZE即可

ws2_32.dll中_WSAFDIsSet的實現

int __stdcall _WSAFDIsSet(SOCKET fd, fd_set *a2)
{
int result; // eax@1
u_int v3; // ecx@1
char *v4; // edx@2

v3 = a2->fd_count;
result = 0;
if ( a2->fd_count )
{
v4 = (char *)&a2->fd_array[v3];
do
{
v4 -= 4;
if ( *(_DWORD *)v4 == fd )
result = 1;
--v3;
}
while ( v3 );
}
return result;
}
  回復  更多評論   

# re: 突破select的FD_SETSIZE限制 2013-08-31 15:30 lkz

MSDN說了,在include頭文件前重新定義FD_SETSIZE即可……  回復  更多評論   

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            影音先锋久久| 老司机精品久久| 一区二区日韩免费看| 久久aⅴ国产欧美74aaa| 亚洲理论在线| 麻豆九一精品爱看视频在线观看免费| 欧美承认网站| 亚洲精品男同| 国产欧美 在线欧美| 亚洲最黄网站| 欧美凹凸一区二区三区视频| 欧美一区二区高清| 国产欧美韩日| 久久精品人人爽| 亚洲色图综合久久| 国产精品免费视频xxxx| 午夜在线视频观看日韩17c| 一本色道久久加勒比88综合| 欧美精选一区| 亚洲视频狠狠| 亚洲视频免费在线观看| 欧美午夜大胆人体| 亚洲一区视频在线观看视频| 夜夜夜久久久| 欧美天天视频| 亚洲一区二区三区免费在线观看| 亚洲美女在线看| 国产精品久久久久天堂| 久久av一区二区三区漫画| 亚洲欧美日韩一区二区三区在线| 国产精品欧美日韩一区| 尤物网精品视频| 欧美国产一区二区在线观看| 欧美成人午夜激情视频| 欧美大片一区| 欧美日韩国产综合久久| 亚洲午夜精品久久| 午夜精品久久久久影视| 在线看国产日韩| 欧美成人亚洲成人日韩成人| 欧美日韩黄色大片| 欧美一级二级三级蜜桃| 久久精品国产69国产精品亚洲 | 欧美日韩在线免费观看| 亚洲电影免费观看高清完整版| 老司机亚洲精品| 欧美激情精品久久久久久变态| 亚洲手机视频| 欧美一区二区三区视频免费播放 | 欧美色视频日本高清在线观看| 午夜久久资源| 欧美顶级大胆免费视频| 久久精品国产第一区二区三区最新章节 | 一本色道久久综合一区| 国产亚洲美州欧州综合国| 欧美大片在线观看一区二区| 欧美午夜精品理论片a级大开眼界| 久久精品国产综合精品| 欧美美女操人视频| 另类天堂av| 国产精品视频在线观看| 亚洲精品国产拍免费91在线| 国模套图日韩精品一区二区| 亚洲精品一级| 伊人一区二区三区久久精品| 亚洲一区bb| 亚洲精品国产精品乱码不99 | 亚洲片在线观看| 亚洲综合色激情五月| 91久久夜色精品国产九色| 一本色道久久综合狠狠躁篇的优点| 国产精品草草| 亚洲国产日韩在线| 在线免费观看日韩欧美| 一本色道久久综合亚洲精品不卡 | 久久欧美肥婆一二区| 欧美极品一区二区三区| 免费久久99精品国产| 久久精品在线观看| 欧美一区二区观看视频| 欧美日韩一区二区高清| 蜜臀av在线播放一区二区三区| 香蕉国产精品偷在线观看不卡| 久久嫩草精品久久久精品| 久久成人精品无人区| 国产精品福利av| 99亚洲伊人久久精品影院红桃| 亚洲人在线视频| 看欧美日韩国产| 欧美电影在线观看| 亚洲欧洲精品一区二区精品久久久| 欧美自拍丝袜亚洲| 久久久天天操| 激情另类综合| 久久久久综合网| 媚黑女一区二区| 亚洲高清视频中文字幕| 裸体歌舞表演一区二区| 欧美99在线视频观看| 亚洲国产日韩欧美在线图片| 麻豆91精品91久久久的内涵| 欧美激情精品久久久久久蜜臀 | 老司机免费视频久久| 久久综合一区二区| 亚洲国产一区二区a毛片| 浪潮色综合久久天堂| 亚洲国产另类 国产精品国产免费| 亚洲欧洲在线看| 欧美激情 亚洲a∨综合| 一区二区三区视频免费在线观看| 亚洲一区二区在线免费观看视频 | 久久久国产91| 亚洲国产精品毛片| 欧美成在线视频| 一区电影在线观看| 久久精品国产亚洲5555| 在线日韩av片| 欧美精品一区二区三区在线播放 | 欧美电影美腿模特1979在线看| 亚洲人成小说网站色在线| 欧美区日韩区| 日韩一级黄色大片| 久久精品国产综合| 亚洲精品一区在线| 国产精品黄色| 久久综合色天天久久综合图片| 欧美77777| 亚洲视频在线一区观看| 亚洲国产免费| 美女久久一区| 一区二区三区日韩精品| 国产一区二区按摩在线观看| 加勒比av一区二区| 久久精品30| 一区二区冒白浆视频| 午夜日韩在线观看| 国产精品入口尤物| 欧美特黄一区| 欧美高清在线一区二区| 亚洲欧美日本国产专区一区| 国产在线精品二区| 欧美日韩精品| 亚洲最新在线视频| 国产有码在线一区二区视频| 亚洲国产欧美日韩另类综合| 国产精品国产三级国产专播精品人 | 亚洲一区在线播放| 亚洲午夜羞羞片| 蜜桃av一区二区在线观看| 久久久久九九九| 一区二区三区.www| 欧美成人亚洲| 久久av一区二区三区| 欧美吻胸吃奶大尺度电影| 99热精品在线观看| 亚洲精品自在在线观看| 欧美日韩精品系列| 亚洲国产精品999| 香蕉久久久久久久av网站| 夜夜嗨av一区二区三区网页| 免费不卡欧美自拍视频| 亚洲精选中文字幕| 99成人免费视频| 欧美全黄视频| 在线视频日韩| 樱桃成人精品视频在线播放| 免费亚洲视频| 国产精品美腿一区在线看| 亚洲国产综合在线| 国产精品色网| 国产精品青草综合久久久久99| 99精品国产高清一区二区| 91久久久精品| 久久精品二区| 亚洲欧美日韩国产综合在线| 久久久亚洲精品一区二区三区| 亚洲欧美日韩在线综合| 欧美成人精品一区| 欧美成人四级电影| 久久久精品免费视频| 美女久久一区| 久久蜜臀精品av| 麻豆精品网站| 久久久99国产精品免费| 香蕉久久久久久久av网站| 国产精品黄视频| 99精品欧美一区| 亚洲青色在线| 亚洲国内自拍| 在线精品福利| 久久精品91久久久久久再现| 9l视频自拍蝌蚪9l视频成人| 亚洲精品久久久久久久久久久| 亚洲国产精品电影| 裸体女人亚洲精品一区| 亚洲国产成人在线| 国产精品丝袜91| 欧美一区二区三区久久精品| 另类综合日韩欧美亚洲| 久久精品av麻豆的观看方式|