UNIX網絡編程中的須要注意的問題

  • 字節流套接字上調用read或write,輸入或輸出的字節數可能比請求的數量少,這個現象的緣由在於內核中用於套接字的緩衝區可能已經達到了極限。此時所須要的是調用者再次調用read或write函數。這個現象在read()一個字節流套接字時很常見,可是在write()一個字節流套接字時只能在該套接字爲非阻塞的前提下才出現。算法

  • connect()函數
    1)若客戶沒有收到SYN分節的響應,則返回ETIMEDOUT錯誤;
    2)若對客戶的SYN響應是RST,則代表服務器在指定的端口上沒有進程在等待與之鏈接,客戶一接收到RST就立刻返回ECONNREFUSED錯誤;
    3)若客戶發出的SYN在中間的路由器上引起了一個ICMP目的不可達錯誤,則間隔必定時間從新發送,若未收到響應,則返回EHOSTUNREACH或ENETUNREACH錯誤;
    4)若connect()失敗則該套接字再也不可用,必須關閉,不能再對該套接字再次調用connect()函數。編程

  • listen()函數
    內核爲任何一個給定的監聽套接字維護兩個隊列:未完成鏈接隊列,已完成鏈接隊列。當一個客戶SYN到達時,若這些隊列是滿的,TCP就忽略該分節,也就是不發送RST。服務器

  • accept()函數
    已完成鏈接隊列中的隊頭項將返回給進程,或者若是該列隊爲空,那麼進程將被投入睡眠,直到TCP在該隊列中放入一項才喚醒它。網絡

  • close()函數
    close()一個TCP套接字的默認行爲是把該套接字標記成已關閉,而後當即返回到調用進程,該套接字描述符不能再由調用進程使用,然而TCP將嘗試發送已排隊等待發送到對端的任何數據,發送完畢後發生的是正常的TCP鏈接終止序列。異步

  • 當fork子進程時,必須捕獲SIGCHLD信號。在Linux中,每一個信號都有一個預約義的默認行爲,它們是下面的一種:進程忽略該信號、進程終止、進程終止並轉儲存儲器、進程中止直到被SIGCONT信號重啓。而最好的處理SIGCHLD信號的方式是在信號處理函數中調用while((pid = waitpid(-1, &status, WNOHANG)) > 0);,而不是調用wait()。函數

  • 當信號是在父進程阻塞於慢系統調用時由父進程捕獲的,內核就會使系統調用返回一個EINTR錯誤,咱們必須判斷並處理該錯誤,如當父進程調用accept()時,子進程發送SIGCHLD信號。code

  • 當執行kill命令殺死服務器進程時,服務器進程會向客戶發送一個FIN,而客戶響應一個ACK,這就是TCP鏈接終止工做的前半部分。當客戶再向服務器發送數據時,服務器會響應一個RST,當客戶再向這個響應RST的套接字執行寫操做時,內核向該進程發送一個SIGPIPE信號。隊列

  • 當服務器主機崩潰,即服務器忽然從網絡上斷開,這時向服務器發送數據,服務器對客戶的數據分節根本沒有響應,返回的錯誤將是ETIMEDOUT,若是某個中間路由器返回ICMP目的不可達信息,返回的錯誤將是EHOSTUNREACH或ENETUNREACH錯誤。進程

  • 當服務器主機崩潰後重啓,即斷開服務器網絡,再從新啓動,最後再把它接入網絡,服務器會對全部收到來自客戶的數據分節響應一個RST。路由

  • 當服務器主機關機時,init進程一般先給全部進程發送SIGTERM信號,等待一段固定時間,而後給全部仍在運行的進程發送SIGKILL信號,服務器上全部打開着的描述符都被關閉。

  • 檢測各類TCP條件的方法

  • close()有兩個限制可使用shutdown()來避免。close()僅在引用計數變爲0時才關閉套接字,而使用shutdown()能夠無論引用計數就激發TCP的正常鏈接終止序列;close()終止讀寫兩個方向的數據傳送,而shutdown()能夠根據參數選擇終止。

  • SO_KEEPALIVE套接字選項
    若是2小時內在該套接字的任一方向上都沒有數據交換,TCP就自動給對端發送一個保持存活探測分節。
    對端可能發生的動做有3種,1)響應ACK;2)響應RST(套接字的待處理錯誤被置爲ECONNRESET,套接字自己被關閉);3)無任何響應(共發送8個探測分節,若是根本沒有對TCP的探測分節的響應,該套接字的待處理錯誤就被置爲ETIMEDOUT,套接字自己被關閉)。

  • SO_LINGER套接字選項
    指定close()對面向鏈接的協議如何操做。shutdown和SO_LINGER各類狀況總結以下。

  • SO_REUSEADDR套接字選項
    1)容許啓動一個監聽服務器並捆綁其衆所周知的端口,即便之前創建的將該端口用做它們的本地端口鏈接仍存在;
    2)容許在同一個端口上啓動同一個服務器的多個實例,只要每一個實例捆綁一個不一樣的本地IP地址便可;
    3)容許單個進程捆綁同一端口到多個套接字上,只要每次捆綁指定不一樣的本地IP地址便可,TCP服務器一般不使用這種方法;
    4)容許徹底重複的捆綁,一樣的IP地址和端口還能夠捆綁到另外一個套接字上,通常來講本特性僅支持UDP套接字。

  • TCP_NODELAY套接字選項
    開啓本選項將禁止TCP的Nagle算法,Nagle算法經常與ACK延滯算法聯合使用。該算法是指發送端即便還有應該發送的數據,但若是這部分數據不多的話,則進行延遲發送的一種處理機制。具體來講,就是公在下列任意一種條件下才能發送數據,若是兩個條件都不知足,那麼暫時等待一段時間之後再進行數據發送。
    1)已發送的數據都已經收到確認應答時;
    2)能夠發送最大長度(MSS)的數據時。

  • UDP的connect()函數
    對於已鏈接UDP套接字,與默認的示鏈接UDP套接字相比,發生了三個變化:
    1)不能給輸出操做指定目的IP地址和端口號,不使用sendto(),改用write()或send();
    2)沒必要使用recvfrom()以獲悉數據報的發送者,而改用read()、recv()或recvmsg();
    3)由已鏈接UDP套接字引起的異步錯誤會返回給它們所在的進程,而未鏈接UDP套接字不接收任何異步錯誤。

參考:《UNIX網絡編程》。

相關文章
相關標籤/搜索