一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

windows下closesocket和shutdown

 獵狐肥 2019-12-09

以下描述主要是針對windows平臺下的TCP socket而言。

首先需要區(qū)分一下關閉socket和關閉TCP連接的區(qū)別,關閉TCP連接是指TCP協(xié)議層的東西,就是兩個TCP端之間交換了一些協(xié)議包(FIN,RST等),具體的交換過程可以看TCP協(xié)議,這里不詳細描述了。而關閉socket是指關閉用戶應用程序中的socket句柄,釋放相關資源。但是當用戶關閉socket句柄時會隱含的觸發(fā)TCP連接的關閉過程。

TCP連接的關閉過程有兩種,一種是優(yōu)雅關閉(graceful close),一種是強制關閉(hard close或abortive close)。所謂優(yōu)雅關閉是指,如果發(fā)送緩存中還有數據未發(fā)出則其發(fā)出去,并且收到所有數據的ACK之后,發(fā)送FIN包,開始關閉過程。而強制關閉是指如果緩存中還有數據,則這些數據都將被丟棄,然后發(fā)送RST包,直接重置TCP連接。

下面說一下shutdown及closesocket函數。

shutdown函數的原型是:

int shutdown(

  SOCKET s,

  int how

);

該函數用于關閉TCP連接,但并不關閉socket句柄。其第二個參數可以取三個值:SD_RECEIVE,SD_SEND,SD_BOTH。

SD_RECEIVE表明關閉接收通道,在該socket上不能再接收數據,如果當前接收緩存中仍有未取出數據或者以后再有數據到達,則TCP會向發(fā)送端發(fā)送RST包,將連接重置。

SD_SEND表明關閉發(fā)送通道,TCP會將發(fā)送緩存中的數據都發(fā)送完畢并在收到所有數據的ACK后向對端發(fā)送FIN包,表明本端沒有更多數據發(fā)送。這個是一個優(yōu)雅關閉過程。

SD_BOTH則表示同時關閉接收通道和發(fā)送通道。

closesocket函數的原型是:

int closesocket(

  SOCKET s

);

該函數用于關閉socket句柄,并釋放相關資源。前面說過,關閉socket句柄時會隱含觸發(fā)TCP連接的關閉過程,那么closesocket觸發(fā)的是一個優(yōu)雅關閉過程還是強制關閉過程呢?

這個與一個socket選項有關:SO_LINGER 選項,該選項的設置值決定了closesocket的行為。該選項的參數值是linger結構,其定義是:

typedef struct linger {

  u_short l_onoff;

  u_short l_linger;

} linger;

當setsockopt函數設置了SO_LINGER時,有下列三種情況:

1、設置 l_onoff為0,則該選項關閉,l_linger的值被忽略,等于內核缺省情況,close調用會立即返回給調用者,如果可能將會傳輸任何未發(fā)送的數據;

2、設置 l_onoff為非0,l_linger為0,則套接口關閉時TCP夭折連接,TCP將丟棄保留在套接口發(fā)送緩沖區(qū)中的任何數據并發(fā)送一個RST給對方,而不是通常的四分組終止序列,這避免了TIME_WAIT狀態(tài);

3、設置 l_onoff 為非0,l_linger為非0,當套接口關閉時內核將拖延一段時間(由l_linger決定)。如果套接口緩沖區(qū)中仍殘留數據,進程將處于睡眠狀態(tài),直 到(a)所有數據發(fā)送完且被對方確認,之后進行正常的終止序列(描述字訪問計數為0)或(b)延遲時間到。此種情況下,應用程序檢查close的返回值是非常重要的,如果在數據發(fā)送完并被確認前時間到,close將返回EWOULDBLOCK錯誤且套接口發(fā)送緩沖區(qū)中的任何數據都丟失。close的成功返回僅告訴我們發(fā)送的數據(和FIN)已由對方TCP確認,它并不能告訴我們對方應用進程是否已讀了數據。如果套接口設為非阻塞的,它將不等待close完成。

 

msdn中還有一條提醒:不推薦在非阻塞套接字中使用SO_LINGER

SO_DONTLINGER 選項為TRUE或FALSE表示禁用SO_LINGER或不禁用SO_LINGER,
如果禁用(即選項為TRUE)即相當于上面的情況1

 

注意SO_LINGER和SO_DONTLINGER選項只影響closesocket的行為,而與shutdown函數無關,shutdown總是會立即返回的。

所以建議的最好的關閉方式是這樣的:

發(fā)送完了所有數據后:

(1)調用shutdown(s, SD_SEND),如果本端同時也接收數據時則執(zhí)行第二步,否則跳到第4步。

(2)繼續(xù)接收數據,

(3)收到FD_CLOSE事件后,調用recv函數直到recv返回0或-1(保證收到所有數據),

(4)調用closesocket,關閉socket句柄。

在實際編程中,我們經常也不調用shutdown,而是直接調用closesocket,利用closesocket隱含觸發(fā)TCP連接關閉過程的特性。此時的過程就是:

當發(fā)送完所有數據后:

(1)如果本端同時也接受數據則執(zhí)行第二步,否則跳到第4步。

(2)繼續(xù)接收數據,

(3)收到FD_CLOSE事件后,調用recv函數直到recv返回0或-1(保證收到所有數據),

(4)調用closesocket,關閉socket句柄。

但是此時為了保證數據不丟失,則需要設置SO_DONTLINGER選項,不過windows平臺下這個也是默認設置。

經過實驗發(fā)現,發(fā)送端應用程序即便是異常退出或被kill掉進程,操作系統(tǒng)也不會丟棄發(fā)送緩沖區(qū)中的未發(fā)送數據,而是會在后臺將這些數據發(fā)送出去。但是這是在socket的發(fā)送緩存不為0的前提下,當socket的發(fā)送緩存設置為0(通過SO_SNDBUF選項)時比較特殊,此時不論socket是否是阻塞的,send函數都會被阻塞直到傳入的用戶緩存中的數據都被發(fā)送出去并被確認,因為此時在驅動層沒有分配緩存存放用戶數據,而是直接使用的應用層的用戶緩存,所以必須阻塞直到數據都發(fā)出,否則可能會造成系統(tǒng)崩潰。

另外,如果是接收端的應用程序異常退出或被kill掉進程,并且接收緩存中還有數據沒有取出的話,那么接收端的TCP會向發(fā)送端發(fā)送RST包,重置連接,因為后續(xù)數據已經無法被提交應用層了。

最后這里說一個感覺是windows的bug,就是做這樣的一個測試:

在一端線listen一個socket,然后在另一端connect,connect成功后,listen端會檢測到網絡事件觸發(fā),在listen端accept之前,將connect端kill掉,然后繼續(xù)運行l(wèi)isten端,listen端任然會accept成功,且在accept出來的socket發(fā)送數據也能成功。發(fā)送完之后在等網絡事件,此時又會等待成功,但是調用WSAEnumNetworkEvents得出的事件標識卻是0。之后再也不會等到網絡事件。

    本站是提供個人知識管理的網絡存儲空間,所有內容均由用戶發(fā)布,不代表本站觀點。請注意甄別內容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現有害或侵權內容,請點擊一鍵舉報。
    轉藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    99久久精品午夜一区| 日韩成人动作片在线观看| 91麻豆精品欧美视频| 久久福利视频视频一区二区 | 东京不热免费观看日本| 偷自拍亚洲欧美一区二页| 国产精品成人一区二区在线| 在线播放欧美精品一区| 亚洲国产精品无遮挡羞羞| 欧美精品一区二区水蜜桃| 日韩一区欧美二区国产| 亚洲美女国产精品久久| 麻豆tv传媒在线观看| 色婷婷国产精品视频一区二区保健 | 午夜福利黄片免费观看| 污污黄黄的成年亚洲毛片| 99久久精品一区二区国产| 国产欧美一区二区三区精品视| 手机在线不卡国产视频| 99久久人妻中文字幕| 免费精品国产日韩热久久| 日韩精品一区二区亚洲| 亚洲国产一区精品一区二区三区色| 男人和女人干逼的视频| 日韩一级毛一欧美一级乱| 日本在线视频播放91| 日韩中文高清在线专区| 国产亚洲欧美自拍中文自拍| 国产精品久久熟女吞精| 极品熟女一区二区三区| 日本加勒比中文在线观看| 久久99精品日韩人妻| 日本高清二区视频久二区| 国产精品免费无遮挡不卡视频| av在线免费播放一区二区| 亚洲av又爽又色又色| 亚洲精品国产第一区二区多人| 欧美老太太性生活大片| 精品国产成人av一区二区三区| 日本深夜福利视频在线| 91精品日本在线视频|