• <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>

            對一個奇怪SOCKET問題的研究

               今天測試網絡服務程序時發現這樣一個現象:客戶端登錄到服務器,服務器如果驗證發現用戶名不存在,就返回客戶端錯誤信息,并斷開與客戶端的連接。但是實際測試時卻發現客戶端并沒有接收到用戶名不存在的錯誤信息,并且明明服務器端關閉了連接,甚至停止了服務,但是客戶端仍然顯示是連接狀態。

               調試,發現在斷開連接操作之前(即CLOSE SOCKET之前),加斷點或者寫LOG或者SLEEP幾毫秒后,客戶端都可接收到錯誤信息,并成功斷開。于是分析覺得問題可能出在SOCKET的IO處理上,可能SOCKET IO中的數據沒有足夠的時間完全發送,SOCKET就被關閉了。

               仔細檢查代碼發現CLOSE SOCKET前做了這樣的操作:

            LINGER lingerStruct;
            lingerStruct.l_onoff  = 1;    
            lingerStruct.l_linger = 0;
            setsockopt( IoSocket, SOL_SOCKET, SO_LINGER,    (char *)&lingerStruct, sizeof(lingerStruct) );
            CancelIo((HANDLE) IoSocket);
            closesocket( IoSocket );
               
               在MSDN中查找setsockeopt關于LINGER的解釋如下:

            Setting the SO_DONTLINGER option prevents blocking on member function Close while waiting for unsent data to be sent. Setting this option is equivalent to setting SO_LINGER with l_onoff set to 0.

                若設置了SO_LINGER,并設置了零超時間隔,則closesocket()不被阻塞立即執行,不論是否有排隊數據未發送或未被確認。這種關閉方式稱為“強制”或“失效”關閉,因為套接口的虛電路立即被復位,且丟失了未發送的數據。在遠端的recv()調用將以WSAECONNRESET出錯。
               若設置了SO_LINGER并確定了非零的超時間隔,則closesocket()調用阻塞進程,直到所剩數據發送完畢或超時。這種關閉稱為“優雅的”關閉。請注意如果套接口置為非阻塞且SO_LINGER設為非零超時,則closesocket()調用將以WSAEWOULDBLOCK錯誤返回。
               若在一個流類套接口上設置了SO_DONTLINGER,則closesocket()調用立即返回。但是,如果可能,排隊的數據將在套接口關閉前發送。請注意,在這種情況下WINDOWS套接口實現將在一段不確定的時間內保留套接口以及其他資源,這對于想用所以套接口的應用程序來說有一定影響。
              簡言之,setsockeopt函數使用SO_LINGER規定了斷開SOCKET時處理未發送完的數據的動作。


               查詢UNIX文檔中關于SO_LINGER參數的解釋更加詳細:

               SO_LINGER
               此選項指定函數close對面向連接的協議如何操作(如TCP)。缺省close操作是立即返回,如果有數據殘留在套接口緩沖區中則系統將試著將這些數據發送給對方。

            SO_LINGER選項用來改變此缺省設置。使用如下結構:
            struct linger {
                 int l_onoff; /* 0 = off, nozero = on */
                 int l_linger; /* linger time */
            };

            有下列三種情況:

            1. l_onoff為0,則該選項關閉,l_linger的值被忽略,等于缺省情況,close立即返回;
            2. l_onoff為非0,l_linger為0,則套接口關閉時TCP夭折連接,TCP將丟棄保留在套接口發送緩沖區中的任何數據并發送一個RST給對方,而不是通常的四分組終止序列,這避免了TIME_WAIT狀態;
            3. l_onoff 為非0,l_linger為非0,當套接口關閉時內核將拖延一段時間(由l_linger決定)。如果套接口緩沖區中仍殘留數據,進程將處于睡眠狀態,直 到(a)所有數據發送完且被對方確認,之后進行正常的終止序列(描述字訪問計數為0)或(b)延遲時間到。此種情況下,應用程序檢查close的返回值是 非常重要的,如果在數據發送完并被確認前時間到,close將返回EWOULDBLOCK錯誤且套接口發送緩沖區中的任何數據都丟失。close的成功返 回僅告訴我們發送的數據(和FIN)已由對方TCP確認,它并不能告訴我們對方應用進程是否已讀了數據。如果套接口設為非阻塞的,它將不等待close完 成。
            l_linger的單位依賴于實現,4.4BSD假設其單位是時鐘滴答(百分之一秒),但Posix.1g規定單位為秒。

               在了解了原理之后,將代碼中的lingerStruct.l_linger 設置為非零值,問題立即被解決。

               這里把這個問題寫出來,希望能夠給大家帶來點啟示。

            posted on 2007-11-14 11:45 迷宮の未來 閱讀(3137) 評論(6)  編輯 收藏 引用

            評論

            # re: 關閉SOCKET時需注意的問題[未登錄] 2007-11-14 15:45 heroboy

            shutdown(...) first.  回復  更多評論   

            # re: 關閉SOCKET時需注意的問題 2007-11-14 16:12 追夢時代

            @heroboy
            謝謝,剛測試了shutdown也可以解決問題  回復  更多評論   

            # re: 關閉SOCKET時需注意的問題 2007-11-14 16:21 追夢時代

            這里貼上MSDN對于shutdown的注意事項,shutdown不管SO_LINGER如何設置都不會堵塞。

            The shutdown function is used on all types of sockets to disable reception, transmission, or both.

            If the how parameter is SD_RECEIVE, subsequent calls to the recv function on the socket will be disallowed. This has no effect on the lower protocol layers. For TCP sockets, if there is still data queued on the socket waiting to be received, or data arrives subsequently, the connection is reset, since the data cannot be delivered to the user. For UDP sockets, incoming datagrams are accepted and queued. In no case will an ICMP error packet be generated.

            If the how parameter is SD_SEND, subsequent calls to the send function are disallowed. For TCP sockets, a FIN will be sent after all data is sent and acknowledged by the receiver.

            Setting how to SD_BOTH disables both sends and receives as described above.

            The shutdown function does not close the socket. Any resources attached to the socket will not be freed until closesocket is invoked.

            To assure that all data is sent and received on a connected socket before it is closed, an application should use shutdown to close connection before calling closesocket. For example, to initiate a graceful disconnect:
            1. Call WSAAsyncSelect to register for FD_CLOSE notification.
            2. Call shutdown with how=SD_SEND.
            When FD_CLOSE received, call recv until zero returned, or SOCKET_ERROR.
            3. Call closesocket.

            Note The shutdown function does not block regardless of the SO_LINGER setting on the socket.

            An application should not rely on being able to reuse a socket after it has been shut down. In particular, a Windows Sockets provider is not required to support the use of connect on a socket that has been shut down.
              回復  更多評論   

            # re: 關閉SOCKET時需注意的問題 2007-11-14 16:34 追夢時代

            http://hi.baidu.com/developer_chen/blog/item/53208b4594f4bf25cefca322.html
            這篇文章描述了如何安全的關閉SOCKET  回復  更多評論   

            # re: 對一個奇怪SOCKET問題的研究 2007-12-23 17:21 秦歌

            shutdown管用  回復  更多評論   

            # re: 對一個奇怪SOCKET問題的研究 2008-01-31 22:00 abettor

            默認情況下,linger是保持TIME_WAIT狀態的。
            如果設置了linger選項,closesocket的時候就會以粗暴的形式實現。也就是,在斷開連接的三次握手時,一旦接受到了對方的ACK后,發送一個RST就立即清理資源,而并不等待TCP/IP協議棧真的將全部數據發出,更不會等上兩個MSL的TIME_WAIT狀態。這樣的話,也許RST根本就還沒有發送出去,所以對等端意識不到連接已經中斷。  回復  更多評論   

            <2007年11月>
            28293031123
            45678910
            11121314151617
            18192021222324
            2526272829301
            2345678

            導航

            統計

            常用鏈接

            留言簿(10)

            隨筆檔案

            文章檔案

            最新隨筆

            搜索

            積分與排名

            最新隨筆

            最新評論

            閱讀排行榜

            評論排行榜

            久久久久人妻精品一区三寸蜜桃| 国产V亚洲V天堂无码久久久| 国产成人久久久精品二区三区 | 久久99精品久久久久久秒播| 精品久久久久久久久久中文字幕| 一本久久a久久精品综合香蕉| 久久99热这里只有精品66| A狠狠久久蜜臀婷色中文网| 久久www免费人成看国产片| 久久久久亚洲精品日久生情| 日本久久久久久中文字幕| 天天综合久久一二三区| 久久国产乱子伦精品免费强| 久久久精品国产| 91久久成人免费| 精品久久久久久久久午夜福利 | 久久天天躁夜夜躁狠狠| 办公室久久精品| 7777久久亚洲中文字幕| 久久精品国产乱子伦| 亚洲精品国产自在久久| 91性高湖久久久久| 久久99精品久久只有精品| 性欧美大战久久久久久久久| 伊人久久大香线蕉AV一区二区 | 久久久一本精品99久久精品66| 无夜精品久久久久久| 精品久久久久久久中文字幕| 久久精品国产亚洲沈樵| 精品久久久久久中文字幕人妻最新| 欧美日韩精品久久久免费观看| 久久精品无码专区免费| 国产精品午夜久久| 久久久国产精品网站| 久久精品免费一区二区三区| 狠狠色丁香久久婷婷综合五月| 色婷婷综合久久久久中文| 午夜人妻久久久久久久久| 久久精品毛片免费观看| 一级做a爱片久久毛片| 激情久久久久久久久久|