標籤:好的 tab win 問題 迴圈 blocking 上下 width str
阻塞模型
int recv( SOCKET s, char* buf, int len, int flags ); |
int send( SOCKET s, const char* buf, int len, int flags ); |
這種方式最為大家熟悉,Socket預設的就是阻塞模式。
在recv的時候,Socket會阻塞在那裡,直到串連上有資料可讀,把資料讀到buffer裡後recv函數才會返回,不然就會一直阻塞在那裡。
如果在主線程中被阻塞,而資料遲遲沒有過來,那麼程式就會被鎖死。這樣的問題可以用多線程解決,但是在有多個通訊端串連的情況下,這不是一個好的選擇,擴充性很差,而且也容易有鎖的問題。線程過多,也導致環境切換過於頻繁,導致系統變慢,而且大部分線程是處於非使用中的話,這就大大浪費了系統的資源。
設定為非阻塞:
int ioctlsocket( IN SOCKET s, IN long cmd, IN OUT u_long FAR * argp ); #define FIONBIO /* set/clear non-blocking i/o */ |
調用ioctlsocket函數設定FIONBIO為1就轉為非阻塞模式。
當recv和send函數沒有準備好資料時,函數不會阻塞,立即返回錯誤值,用GetLastError返回的錯誤碼為WSAEWOULDBLOCK,中文解釋為“無法立即完成一個非阻擋性通訊端的操作”。
當然,這裡你可以用非阻塞類比阻塞模式,就是用while迴圈不停調用recv,直到recv返回成功為止。這樣的效率也不高,但好處在於你能在沒接收到資料時,有空進行其他動作,或者直接Sleep。
把通訊端設定為非阻塞模式,即告訴系統:在調用Windows socket API時,不讓主調線程睡眠,而讓函數立即返回。比如在調用recv函數時,即使此時接受緩衝區沒有資料,也不會導致線程在recv處等待,recv函數會立即返回。如果沒有調用成功函數會返回WSAEROULDBLOCK錯誤碼。為了接收到資料必須迴圈調用recv,這也是非阻塞與阻塞模式的主要區別。
unsigned long ul=1; int ret; s=socket(AF_INET,SOCK_STREAM,0); ret=ioctlsocket(s,FIONBIO,(unsigned long *)&ul);//設定成非阻塞模式。 if(ret==SOCKET_ERROR)//設定失敗。 { }
windows下的6種IO模型