1,ioctlsocket()算法
#include <winsock.h>服務器
This function controls the I/O mode of a socket.網絡
int ioctlsocket( SOCKET s, long cmd, u_long FAR* argp );
s異步
[in] Descriptor identifying a socket.socket
cmdide
[in] Command to perform on socket s.函數
argp性能
[in, out] Pointer to a parameter for cmd.this
If no error occurs, this function returns zero. If an error occurs, a value of SOCKET_ERROR is returned, and a specific error code can be retrieved by calling WSAGetLastError.spa
The following table shows a list of possible error codes.
u_long mode = 0;
ioctlsocket(s,FIONBIO,&mode);
控制爲阻塞方式。
u_long mode = 1;
ioctlsocket(s,FIONBIO,&mode);
控制爲非阻塞方式。
本函數可用於任一狀態的任一套接口。它用於獲取與套接口相關的操做參數,而與具體協議或通信子系統無關。支持下列命令:
FIONBIO:容許或禁止套接口s的非阻塞模式。argp指向一個無符號長整型。如容許非阻塞模式則非零,如禁止非阻塞模式則爲零。當建立一個套接口時,它就處於阻塞模式(也就是說非阻塞模式被禁止)。這與BSD套接口是一致的。WSAAsynSelect()函數將套接口自動設置爲非阻塞模式。若是已對一個套接口進行了WSAAsynSelect() 操做,則任何用ioctlsocket()來把套接口從新設置成阻塞模式的試圖將以WSAEINVAL失敗。爲了把套接口從新設置成阻塞模式,應用程序必須首先用WSAAsynSelect()調用(IEvent參數置爲0)來禁至WSAAsynSelect()。
FIONREAD:肯定套接口s自動讀入的數據量。argp指向一個無符號長整型,其中存有ioctlsocket()的返回值。若是s是SOCKET_STREAM類型,則FIONREAD返回在一次recv()中所接收的全部數據量。這一般與套接口中排隊的數據總量相同。若是S是SOCK_DGRAM 型,則FIONREAD返回套接口上排隊的第一個數據報大小。
SIOCATMARK:確實是否全部的帶外數據都已被讀入。這個命令僅適用於SOCK_STREAM類型的套接口,且該套接口已被設置爲能夠在線接收帶外數據(SO_OOBINLINE)。如無帶外數據等待讀入,則該操做返回TRUE真。不然的話返回FALSE假,下一個recv()或recvfrom()操做將檢索「標記」前一些或全部數據。應用程序可用SIOCATMARK操做來肯定是否有數據剩下。若是在「緊急」(帶外)數據前有常規數據,則按序接收這些數據(請注意,recv()和recvfrom()操做不會在一次調用中混淆常規數據與帶外數據)。argp指向一個BOOL型數,ioctlsocket()在其中存入返回值。
2,setsockopt() 簡述:
Call this member function to set a socket option.
BOOL SetSockOpt( int nOptionName, const void* lpOptionValue, int nOptionLen, int nLevel = SOL_SOCKET );
nOptionName
The socket option for which the value is to be set.
lpOptionValue
A pointer to the buffer in which the value for the requested option is supplied.
nOptionLen
The size of the lpOptionValue buffer in bytes.
nLevel
The level at which the option is defined; the only supported levels are SOL_SOCKET and IPPROTO_TCP.
setsockopt() 簡述: 設置套接口的選項。 #include <winsock.h> int PASCAL FAR setsockopt( SOCKET s, int level, int optname, const char FAR* optval, int optlen); s:標識一個套接口的描述字。 level:選項定義的層次;目前僅支持SOL_SOCKET和IPPROTO_TCP層次。 optname:需設置的選項。 optval:指針,指向存放選項值的緩衝區。 optlen:optval緩衝區的長度。 註釋: setsockopt()函數用於任意類型、任意狀態套接口的設置選項值。儘管在不一樣協議層上存在選項,但本函數僅定義了最高的「套接口」層次上的選項。選項影響套接口的操做,諸如加急數據是否在普通數據流中接收,廣播數據是否能夠從套接口發送等等。 有兩種套接口的選項:一種是布爾型選項,容許或禁止一種特性;另外一種是整形或結構選項。容許一個布爾型選項,則將optval指向非零整形數;禁止一個選項optval指向一個等於零的整形數。對於布爾型選項,optlen應等於sizeof(int);對其餘選項,optval指向包含所需選項的整形數或結構,而optlen則爲整形數或結構的長度。SO_LINGER選項用於控制下述狀況的行動:套接口上有排隊的待發送數據,且closesocket()調用已執行。參見closesocket()函數中關於SO_LINGER選項對closesocket()語義的影響。應用程序經過建立一個linger結構來設置相應的操做特性: struct linger { int l_onoff; int l_linger; }; 爲了容許SO_LINGER,應用程序應將l_onoff設爲非零,將l_linger設爲零或須要的超時值(以秒爲單位),而後調用setsockopt()。爲了容許SO_DONTLINGER(亦即禁止SO_LINGER),l_onoff應設爲零,而後調用setsockopt()。 缺省條件下,一個套接口不能與一個已在使用中的本地地址捆綁(參見bind())。但有時會須要「重用」地址。由於每個鏈接都由本地地址和遠端地址的組合惟一肯定,因此只要遠端地址不一樣,兩個套接口與一個地址捆綁並沒有大礙。爲了通知WINDOWS套接口實現不要由於一個地址已被一個套接口使用就不讓它與另外一個套接口捆綁,應用程序可在bind()調用前先設置SO_REUSEADDR選項。請注意僅在bind()調用時該選項才被解釋;故此無需(但也無害)將一個不會共用地址的套接口設置該選項,或者在bind()對這個或其餘套接口無影響狀況下設置或清除這一選項。 一個應用程序能夠經過打開SO_KEEPALIVE選項,使得WINDOWS套接口實如今TCP鏈接狀況下容許使用「保持活動」包。一個WINDOWS套接口實現並非必需支持「保持活動」,可是若是支持的話,具體的語義將與實現有關,應遵照RFC1122「Internet主機要求-通信層」中第4.2.3.6節的規範。若是有關鏈接因爲「保持活動」而失效,則進行中的任何對該套接口的調用都將以WSAENETRESET錯誤返回,後續的任何調用將以WSAENOTCONN錯誤返回。 TCP_NODELAY選項禁止Nagle算法。Nagle算法經過將未確認的數據存入緩衝區直到蓄足一個包一塊兒發送的方法,來減小主機發送的零碎小數據包的數目。但對於某些應用來講,這種算法將下降系統性能。因此TCP_NODELAY可用來將此算法關閉。應用程序編寫者只有在確切瞭解它的效果並確實須要的狀況下,才設置TCP_NODELAY選項,由於設置後對網絡性能有明顯的負面影響。TCP_NODELAY是惟一使用IPPROTO_TCP層的選項,其餘全部選項都使用SOL_SOCKET層。 若是設置了SO_DEBUG選項,WINDOWS套接口供應商被鼓勵(但不是必需)提供輸出相應的調試信息。但產生調試信息的機制以及調試信息的形式已超出本規範的討論範圍。 setsockopt()支持下列選項。其中「類型」代表optval所指數據的類型。 選項 類型 意義 SO_BROADCAST BOOL 容許套接口傳送廣播信息。 SO_DEBUG BOOL 記錄調試信息。 SO_DONTLINER BOOL 不要由於數據未發送就阻塞關閉操做。設置本選項至關於將SO_LINGER的l_onoff元素置爲零。 SO_DONTROUTE BOOL 禁止選徑;直接傳送。 SO_KEEPALIVE BOOL 發送「保持活動」包。 SO_LINGER struct linger FAR* 如關閉時有未發送數據,則逗留。 SO_OOBINLINE BOOL 在常規數據流中接收帶外數據。 SO_RCVBUF int 爲接收肯定緩衝區大小。 SO_REUSEADDR BOOL 容許套接口和一個已在使用中的地址捆綁(參見bind())。 SO_SNDBUF int 指定發送緩衝區大小。 TCP_NODELAY BOOL 禁止發送合併的Nagle算法。 setsockopt()不支持的BSD選項有: 選項名 類型 意義 SO_ACCEPTCONN BOOL 套接口在監聽。 SO_ERROR int 獲取錯誤狀態並清除。 SO_RCVLOWAT int 接收低級水印。 SO_RCVTIMEO int 接收超時。 SO_SNDLOWAT int 發送低級水印。 SO_SNDTIMEO int 發送超時。 SO_TYPE int 套接口類型。 IP_OPTIONS 在IP頭中設置選項。 返回值: 若無錯誤發生,setsockopt()返回0。不然的話,返回SOCKET_ERROR錯誤,應用程序可經過WSAGetLastError()獲取相應錯誤代碼。 錯誤代碼: WSANOTINITIALISED:在使用此API以前應首先成功地調用WSAStartup()。 WSAENETDOWN:WINDOWS套接口實現檢測到網絡子系統失效。 WSAEFAULT:optval不是進程地址空間中的一個有效部分。 WSAEINPROGRESS:一個阻塞的WINDOWS套接口調用正在運行中。 WSAEINVAL:level值非法,或optval中的信息非法。 WSAENETRESET:當SO_KEEPALIVE設置後鏈接超時。 WSAENOPROTOOPT:未知或不支持選項。其中,SOCK_STREAM類型的套接口不支持SO_BROADCAST選項,SOCK_DGRAM類型的套接口不支持SO_DONTLINGER 、SO_KEEPALIVE、SO_LINGER和SO_OOBINLINE選項。 WSAENOTCONN:當設置SO_KEEPALIVE後鏈接被複位。 WSAENOTSOCK:描述字不是一個套接口。 用法 1.設置調用closesocket()後,仍可繼續重用該socket。調用closesocket()通常不會當即關閉socket,而經歷TIME_WAIT的過程。 BOOL bReuseaddr = TRUE; setsockopt( s, SOL_SOCKET, SO_REUSEADDR, ( const char* )&bReuseaddr, sizeof( BOOL ) ); 2. 若是要已經處於鏈接狀態的soket在調用closesocket()後強制關閉,不經歷TIME_WAIT的過程: BOOL bDontLinger = FALSE; setsockopt( s, SOL_SOCKET, SO_DONTLINGER, ( const char* )&bDontLinger, sizeof( BOOL ) ); 3.在send(),recv()過程當中有時因爲網絡情況等緣由,收發不能預期進行,能夠設置收發時限: int nNetTimeout = 1000; //1秒 //發送時限 setsockopt( socket, SOL_S0CKET, SO_SNDTIMEO, ( char * )&nNetTimeout, sizeof( int ) ); //接收時限 setsockopt( socket, SOL_S0CKET, SO_RCVTIMEO, ( char * )&nNetTimeout, sizeof( int ) ); 4.在send()的時候,返回的是實際發送出去的字節(同步)或發送到socket緩衝區的字節(異步);系統默認的狀態發送和接收一次爲8688字節(約 爲8.5K);在實際的過程當中若是發送或是接收的數據量比較大,能夠設置socket緩衝區,避免send(),recv()不斷的循環收發: // 接收緩衝區 int nRecvBuf = 32 * 1024; //設置爲32K setsockopt( s, SOL_SOCKET, SO_RCVBUF, ( const char* )&nRecvBuf, sizeof( int ) ); //發送緩衝區 int nSendBuf = 32*1024; //設置爲32K setsockopt( s, SOL_SOCKET, SO_SNDBUF, ( const char* )&nSendBuf, sizeof( int ) ); 5.在發送數據的時,不執行由系統緩衝區到socket緩衝區的拷貝,以提升程序的性能: int nZero = 0; setsockopt( socket, SOL_S0CKET, SO_SNDBUF, ( char * )&nZero, sizeof( nZero ) ); 6.在接收數據時,不執行將socket緩衝區的內容拷貝到系統緩衝區: int nZero = 0; setsockopt( s, SOL_S0CKET, SO_RCVBUF, ( char * )&nZero, sizeof( int ) ); 7.通常在發送UDP數據報的時候,但願該socket發送的數據具備廣播特性: BOOL bBroadcast = TRUE; setsockopt( s, SOL_SOCKET, SO_BROADCAST, ( const char* )&bBroadcast, sizeof( BOOL ) ); 8.在client鏈接服務器過程當中,若是處於非阻塞模式下的socket在connect()的過程當中能夠設置connect()延時,直到accpet()被調用(此設置只 有在非阻塞的過程當中有顯著的做用,在阻塞的函數調用中做用不大) BOOL bConditionalAccept = TRUE; setsockopt( s, SOL_SOCKET, SO_CONDITIONAL_ACCEPT, ( const char* )&bConditionalAccept, sizeof( BOOL ) ); 9.若是在發送數據的過程當中send()沒有完成,還有數據沒發送,而調用了closesocket(),之前通常採起的措施是shutdown(s,SD_BOTH),可是數 據將會丟失。 某些具體程序要求待未發送完的數據發送出去後再關閉socket,可經過設置讓程序知足要求: struct linger { u_short l_onoff; u_short l_linger; }; linger m_sLinger; m_sLinger.l_onoff = 1; //在調用closesocket()時還有數據未發送完,容許等待 // 若m_sLinger.l_onoff=0;則調用closesocket()後強制關閉 m_sLinger.l_linger = 5; //設置等待時間爲5秒 setsockopt( s, SOL_SOCKET, SO_LINGER, ( const char* )&m_sLinger, sizeof( linger ) );