Unix 網絡編程 讀書筆記1

第一章:java

C/C++語言提供兩種不一樣的編程模式:IPL32和PL64。
► IPL32
● 表示integer/pointer/long三種數據類型是32位(4個字節),在這種模式下,提供32
位的地址空間,理論的內存使用限制爲4G。
► PL64
● 表示pointer/long兩種數據類型是64位(8個字節),提供64位地址空間,使用內存超
過4G(達2^60bytes=1EB)。編程

 more infoabout IPL32 and PL64, please refer to http://www-31.ibm.com/cn/downloadfiles/tsc/faq/cyberclass/aixmig/aixmig.pdf服務器

 第二章:cookie

TCP 鏈接創建過程:網絡

TCP 鏈接解除過程:併發

TCP 狀態和socket 函數調用對應關係:app

深刻理解 listen 和accept 函數socket

1 #include<sys/socket.h>
2 int listen(int sockfd, int backlog);

 

listen函數僅由TCP服務器調用,它作兩件事情:tcp

一、當socket函數建立一個套接口時,它被假設爲一個主動套裝口,也就是說,它是一個將調用connet發起鏈接的客戶套接口。listen函數把一個未鏈接的套接口轉換成一個被動套接口,指示內核應接受指向該套接口的鏈接請求。根據TCP狀態轉換圖,調用listen致使套接口從CLOSED狀態轉換到LISTEN狀態。函數

二、本函數的第二個參數規定了內核應該爲相應套接口排隊的最大鏈接個數。

    爲了更好的理解backlog參數,咱們必須認識到內核爲任何一個給定的監聽套接口維護兩個隊列:

一、未完成鏈接隊列(incomplete connection queue,每一個這樣的SYN分節對應其中一項:已由某個客戶發出併到達服務器,而服務器正在等待完成相應的TCP三路握手過程。這些套接口處於SYN_RCVD狀態。

二、已完成鏈接隊列(completed connection queue,每一個已完成TCP三路握手過程的客戶對應其中一項。這些套接口處於ESTABLISHED狀態。

      當來自客戶的SYN到達時,TCP在未完成鏈接隊列中建立一個新項,而後響應以三路握手的第二個分節:服務器的SYN響應,其中稍帶對客戶SYN的ACK(即SYN+ACK)。這一項一直保留在未完成鏈接隊列中,直到三路握手的第三個分節(客戶對服務器SYN的ACK)到達或者該項超時爲止(曾經源自Berkeley的實現爲這些未完成鏈接的項設置的超時值爲75秒)。若是三路握手正常完成,該項就從未完成鏈接隊列移到已完成鏈接隊列的隊尾。當進程調用accept時,已完成鏈接隊列中的隊頭項將返回給進程,或者若是該隊列爲空,那麼進程將被投入睡眠,直到TCP在該隊列中放入一項才喚醒它。

3次握手發生在客戶端 connect 時 而服務器accept 只是從內核取出能夠已完成握手的隊列中取出一個。

man listen

 

[root@localhost httpSever]# man listen
LISTEN(2)                  Linux Programmer’s Manual                 LISTEN(2)

 

NAME
       listen - listen for connections on a socket

 

SYNOPSIS
       #include <sys/socket.h>

 

       int listen(int sockfd, int backlog);

 

DESCRIPTION
       To  accept  connections, a socket is first created with socket(2), a willingness to accept incoming connections
       and a queue limit for incoming connections are specified with listen(), and then the connections  are  accepted
       with accept(2).  The listen() call applies only to sockets of type SOCK_STREAM or SOCK_SEQPACKET.

 

       The backlog parameter defines the maximum length the queue of pending connections may grow to.  If a connection
       request arrives with the queue full the client may receive an error with an indication of ECONNREFUSED  or,  if
       the underlying protocol supports retransmission, the request may be ignored so that retries succeed.

 

NOTES
       The  behaviour  of  the  backlog  parameter  on TCP sockets changed with Linux 2.2.  Now it specifies the queue
       length for completely established sockets waiting to be accepted, instead of the number of  incomplete  connec-
       tion  requests. The maximum length of the queue for incomplete sockets can be set using the tcp_max_syn_backlog
       sysctl.  When syncookies are enabled there is no logical maximum length and this  sysctl  setting  is  ignored.
       See tcp(7) for more information.

 

RETURN VALUE
       On success, zero is returned.  On error, -1 is returned, and errno is set appropriately.

 

ERRORS
       EADDRINUSE
              Another socket is already listening on the same port.

 

       EBADF  The argument sockfd is not a valid descriptor.

 

       ENOTSOCK
              The argument sockfd is not a socket.

 

       EOPNOTSUPP
              The socket is not of a type that supports the listen() operation.

 

CONFORMING TO
       4.4BSD, POSIX.1-2001.  The listen() function call first appeared in 4.2BSD.

 

BUGS
       If the socket is of type AF_INET, and the backlog argument is greater than the constant SOMAXCONN (128 in Linux
       2.0 & 2.2), it is silently truncated to SOMAXCONN.

 

SEE ALSO
       accept(2), bind(2), connect(2), socket(2)

 

BSD Man Page                      1993-07-23                         LISTEN(2)  

 轉一篇文章http://blog.163.com/xychenbaihu@yeah/blog/static/13222965520118139252103/

 

在咱們學習網絡基礎時,傳輸層的協議有TCP和UDP;

在Linux網絡編程中,咱們使用socket API,實現網絡通訊。

那麼:

        socket API 和 TCP 協議中各個狀態是如何對應的呢?咱們能夠經過下圖來看:

          

在socket系統調用中,如何完成三次握手和四次揮手:

        SOCK_DGRAM,即UDP中的connect操做知識在內核中註冊對方機器的IP和PORT信息,並無創建連接的過程,即沒有發包,close也不發包)。

       而SOCK_STREAM對應以下:

        connect會完成TCP的三次握手,客戶端調用connect後,由內核中的TCP協議完成TCP的三次握手;

        close操做會完成四次揮手。

 

三次握手對應的Berkeley Socket API:

          從圖中,能夠看出和鏈接創建相關的API有:connect, listen, accept   3個,connect用在客戶端,另外2個用在服務端。

          對於TCP/IP protocol stack來講,TCP層的tcp_in&tcp_out也參與這個過程。咱們這裏只討論這3個應用層的API幹了什麼事情。

         (1) connect

                     發送了一個SYN,收到Server的SYN+ACK後,表明鏈接完成。發送最後一個ACK是protocol stack,tcp_out完成的。

         (2)listen

                    在server這端,準備了一個未完成的鏈接隊列,保存只收到SYN_C的socket結構;

                    還準備了已完成的鏈接隊列,即保存了收到了最後一個ACK的socket結構。

        (3)accept

                   應用進程調用accept的時候,就是去檢查上面說的已完成的鏈接隊列,若是隊列裏有鏈接,就返回這個鏈接;

                   若是沒有,即空的,blocking方試調用,就睡眠等待;

                                                   nonblocking方式調用,就直接返回,通常一"EWOULDBLOCK「 errno告訴調用者,鏈接隊列是空的。 

 注意:

        在上面的socket API和TCP STATE的對應關係中,TCP協議中,客戶端收到Server響應時,可能會有會延遲確認。

        即客戶端收到數據後,會阻塞給Server端確認。

        能夠在每次收到數據後:

               調用setsockopt(fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){1}, sizeof(int));  快速給Server端確認。

                    

 

 

咱們如何判斷有一個創建連接請求或一個關閉連接請求:

      創建連接請求:

一、connect將完成三次握手,accept所監聽的fd上,產生讀事件,表示有新的連接請求;           

關閉連接請求:

一、close將完成四次揮手,若是有一方關閉sockfd,對方將感知到有讀事件,

      若是read讀取數據時,返回0,即讀取到0個數據,表示有斷開連接請求。(在操做系統中已經這麼定義) 

    

 

  

關閉連接過程當中的TCP狀態和SOCKET處理,及可能出現的問題:

1. TIME_WAIT

 TIME_WAIT 是主動關閉 TCP 鏈接的那一方出現的狀態,系統會在 TIME_WAIT 狀態下等待 2MSL(maximum segment lifetime  )後才能釋放鏈接(端口)。一般約合 4 分鐘之內。

 進入 TIME_WAIT 狀態等待 2MSL 的目的:

          一、確保鏈接可靠地關閉; 即防止最後一個ACK丟失。

          二、避免產生套接字混淆(同一個端口對應多個套接字)。

(

    意思是,一方close發送了關閉連接請求,對方的應答遲遲到不了(例如網絡緣由),致使TIME_WAIT超時,此時這個端口又可用了,

咱們在這個端口上又創建了另一個socket連接。

    若是此時對方的應答到了,怎麼處理呢?

            其實這個在TCP層已經處理了,因爲有TCP序列號,因此內核TCP層,就會將包丟掉,並給對方發包,讓對方將sockfd關閉。

    因此應用層是沒有關係的。即咱們用socket API編寫程序,就不用處理。

)

注意::

         TIME_WAIT是指操做系統的定時器會等2MSL,而主動關閉sockfd的一方,並不會阻塞。(即應用程序在close時,並不會阻塞)。

         當主動方關閉sockfd後,對方可能不知道這個事件。那麼當對方(被動方)寫數據,即send時,將會產生錯誤,即errno爲: ECONNRESET。

 

 服務器產生大量 TIME_WAIT 的緣由:(通常咱們不這樣開發Server)

  服務器存在大量的主動關閉操做,需關注程序什麼時候會執行主動關閉(如批量清理長期空閒的套接字等操做)。

  通常咱們本身寫的服務器進行主動斷開鏈接的很少,除非作了空閒超時之類的管理。(TCP短連接是指,客戶端發送請求給服務器,客戶端收到服務器端的響應後,關閉連接)。

 

 

2. CLOSE_WAIT

 CLOSE_WAIT 是被動關閉 TCP 鏈接時產生的,

若是收到另外一端關閉鏈接的請求後,本地(Server端)不關閉相應套接字就會致使本地套接字進入這一狀態。

(若是對方關閉了,沒有收到關閉連接請求,就是下面的不正常狀況)

 

按狀態機,我方收到FIN,則由TCP實現發送ACK,所以進入CLOSE_WAIT狀態。但若是我方不執行close(),就不能由CLOSE_WAIT遷移到LAST_ACK,則系統中會存在不少CLOSE_WAIT狀態的鏈接。

 

若是存在大量的 CLOSE_WAIT,則說明客戶端併發量大,且服務器未能正常感知客戶端的退出,也並未及時 close 這些套接字。(若是不及時處理,將會出現沒有可用的socket描述符的問題,產生問題的緣由,沒有及時close)。

 

正常狀況下,一方關閉sockfd,另一方將會有讀事件產生, 當recv數據時,若是返回值爲0,表示對端已經關閉。此時咱們應該調用close,將對應的sockfd也關閉掉。

 

不正常狀況下,一方關閉sockfd,另一方並不知道,(好比在close時,本身斷網了,對方就收不到發送的數據包)。此時,若是另一方再向對應的sockfd上寫send或讀recv數據。

recv時,將會返回0,表示連接已經斷開。

send時, 將會產生錯誤,errno爲ECONNRESET。

 

TIME_WAIT狀態存在的理由

----------------------------

TCP/IP協議就是這樣設計的,是不可避免的。主要有兩個緣由:

1)可靠地實現TCP全雙工鏈接的終止

TCP協議在關閉鏈接的四次握手過程當中,最終的ACK是由主動關閉鏈接的一端(後面統稱A端)發出的,若是這個ACK丟失,對方(後面統稱B端)將重發出最終的FIN,所以A端必須維護狀態信息(TIME_WAIT)容許它重發最終的ACK。若是A端不維持TIME_WAIT狀態,而是處於CLOSED 狀態,那麼A端將響應RST分節,B端收到後將此分節解釋成一個錯誤(在java中會拋出connection reset的SocketException)。

於是,要實現TCP全雙工鏈接的正常終止,必須處理終止過程當中四個分節任何一個分節的丟失狀況,主動關閉鏈接的A端必須維持TIME_WAIT狀態 。

 

2)容許老的重複分節在網絡中消逝 

TCP分節可能因爲路由器異常而「迷途」,在迷途期間,TCP發送端可能因確認超時而重發這個分節,迷途的分節在路由器修復後也會被送到最終目的地,這個遲到的迷途分節到達時可能會引發問題。在關閉「前一個鏈接」以後,立刻又從新創建起一個相同的IP和端口之間的「新鏈接」,「前一個鏈接」的迷途重複分組在「前一個鏈接」終止後到達,而被「新鏈接」收到了。爲了不這個狀況,TCP協議不容許處於TIME_WAIT狀態的鏈接啓動一個新的可用鏈接,由於TIME_WAIT狀態持續2MSL,就能夠保證當成功創建一個新TCP鏈接的時候,來自舊鏈接重複分組已經在網絡中消逝。

 

 

 

轉   http://blog.csdn.net/whuslei/article/details/6667471

 

 

創建TCP須要三次握手才能創建,而斷開鏈接則須要四次握手。整個過程以下圖所示:

先來看看如何創建鏈接的。

首先Client端發送鏈接請求報文,Server段接受鏈接後回覆ACK報文,併爲此次鏈接分配資源。Client端接收到ACK報文後也向Server段發生ACK報文,並分配資源,這樣TCP鏈接就創建了。

那如何斷開鏈接呢?簡單的過程以下:

【注意】中斷鏈接端能夠是Client端,也能夠是Server端。

假設Client端發起中斷鏈接請求,也就是發送FIN報文。Server端接到FIN報文後,意思是說"我Client端沒有數據要發給你了",可是若是你還有數據沒有發送完成,則沒必要急着關閉Socket,能夠繼續發送數據。因此你先發送ACK,"告訴Client端,你的請求我收到了,可是我還沒準備好,請繼續你等個人消息"。這個時候Client端就進入FIN_WAIT狀態,繼續等待Server端的FIN報文。當Server端肯定數據已發送完成,則向Client端發送FIN報文,"告訴Client端,好了,我這邊數據發完了,準備好關閉鏈接了"。Client端收到FIN報文後,"就知道能夠關閉鏈接了,可是他仍是不相信網絡,怕Server端不知道要關閉,因此發送ACK後進入TIME_WAIT狀態,若是Server端沒有收到ACK則能夠重傳。「,Server端收到ACK後,"就知道能夠斷開鏈接了"。Client端等待了2MSL後依然沒有收到回覆,則證實Server端已正常關閉,那好,我Client端也能夠關閉鏈接了。Ok,TCP鏈接就這樣關閉了!

整個過程Client端所經歷的狀態以下:

而Server端所經歷的過程以下:轉載請註明:blog.csdn.net/whuslei

【注意】 在TIME_WAIT狀態中,若是TCP client端最後一次發送的ACK丟失了,它將從新發送。TIME_WAIT狀態中所須要的時間是依賴於實現方法的。典型的值爲30秒、1分鐘和2分鐘。等待以後鏈接正式關閉,而且全部的資源(包括端口號)都被釋放。

【問題1】爲何鏈接的時候是三次握手,關閉的時候倒是四次握手?
答:由於當Server端收到Client端的SYN鏈接請求報文後,能夠直接發送SYN+ACK報文。其中ACK報文是用來應答的,SYN報文是用來同步的。可是關閉鏈接時,當Server端收到FIN報文時,極可能並不會當即關閉SOCKET,因此只能先回復一個ACK報文,告訴Client端,"你發的FIN報文我收到了"。只有等到我Server端全部的報文都發送完了,我才能發送FIN報文,所以不能一塊兒發送。故須要四步握手。

【問題2】爲何TIME_WAIT狀態須要通過2MSL(最大報文段生存時間)才能返回到CLOSE狀態?

答:雖然按道理,四個報文都發送完畢,咱們能夠直接進入CLOSE狀態了,可是咱們必須假象網絡是不可靠的,有能夠最後一個ACK丟失。因此TIME_WAIT狀態就是用來重發可能丟失的ACK報文。

 

 

 

 

 

 

 

 

  不少人會問,爲何建連接要3次握手,斷連接須要4次揮手?

  • 對於建連接的3次握手,主要是要初始化Sequence Number 的初始值。通訊的雙方要互相通知對方本身的初始化的Sequence Number(縮寫爲ISN:Inital Sequence Number)——因此叫SYN,全稱Synchronize Sequence Numbers。也就上圖中的 x 和 y。這個號要做爲之後的數據通訊的序號,以保證應用層接收到的數據不會由於網絡上的傳輸的問題而亂序(TCP會用這個序號來拼接數據)。
    • 對於4次揮手,其實你仔細看是2次,由於TCP是全雙工的,因此,發送方和接收方都須要Fin和Ack。只不過,有一方是被動的,因此看上去就成了所謂的4次揮手。若是兩邊同時斷鏈接,那就會就進入到CLOSING狀態,而後到達TIME_WAIT狀態。下圖是雙方同時斷鏈接的示意圖(你一樣能夠對照着TCP狀態機看):

相關文章
相關標籤/搜索