天天看點

socket網絡程式設計

- 網絡程式設計

socket網絡程式設計

在講網絡程式設計之前,首先要了解下網絡的架構。

我們都知道TCP/IP網絡模型共有7層:

第一層網絡接口層:将osi的實體層和資料鍊路層合二為一。實體層 是網絡的傳輸媒體層,處于網絡的最低層,是網絡的載體。利用實體媒體對上次網絡提供實體連接配接。常用的裝置喲網卡、集線器、中繼器、數據機、網線等。資料鍊路層:在這層,将資料進行分幀,并進行流的控制,屏蔽實體層,為上層(網絡層)提供資料鍊路的連接配接。本層進行硬體尋址(MAC位址,ARP協定)。

第三層網絡層:本層通過尋址來建立兩個節點之間的連接配接,為上層(運輸層)提供鍊路傳輸功能。負責建立和維護連接配接,擁塞控制等。(IP協定)

第四層傳輸層:面向連接配接和無連接配接的傳輸。(tcp,udp,端口)

第五層應用層:不多說

兩個在不同網絡的主機程式程序進行通信的流程為:

S(Server):傳輸層打開一個端口,綁定socket套接字,進行監聽端口,等待外部的連接配接。

如果外部有連接配接,則Accept,

A(client):先建立一個socket套接字,連接配接到伺服器

- 設定TIME_WAIT的原因

可靠地實作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狀态

允許老的重複分節在網絡中消逝

TCP分節可能由于路由器異常而“迷途“,在迷途期間,TCP發送端可能因确認逾時而重發這個分節,迷途的分節在路由器修複後也會被送到最終目的地,這個遲到的迷途分節到達時可能會引起問題。在關閉“前一個連接配接”之後,馬上又重建立立起一個相同的IP和端口之間的“新連接配接”,“前一個連接配接”的迷途重複分組在“前一個連接配接”終止後到達,而被“新連接配接”收到了。為了避免這個情況,TCP協定不允許處于TIME_WAIT狀态的連接配接啟動一個新的可用連接配接,因為TIME_WAIT狀态持續2MSL,就可以保證當成功建立一個新TCP連接配接的時候,來自舊連接配接重複分組已經在網絡中消逝。

socket網絡程式設計
- 并發伺服器
socket網絡程式設計

pid_t pid;
int listenfd,connfd;
listenfd = socket(...);
bind(listenfd...);
listen(listenfd,LISTENQ);
for( ; ; ){
    connfd = accept(listenfd,...);
    if( (pid = Fork()) == 0){
        close(listenfd);   // child closes listening socket
        doit(connfd);     // process the request
        close(connfd);    // done with this client
        exit(0);
    }
    close(connfd);   // parent closes connected socket
}           

針對一個TCP套接字調用close會導緻發送一個FIN,随後是正常的TCP連接配接終止序列。但是在上面福程序首先調用close(connfd),會什麼沒有終止連接配接呢。

我們必須知道每個檔案或者套接字都有一個引用計數。引用計數在檔案表象中維護着。在建立listenfd的時候,引用計數為1,當複制到子程序的時候,引用計數為2,這麼一來,當父程序關閉connfd的時候,他隻是把相應的引用計數減為1.該套接字的真正清理應該等引用計數變為0才會發生。

參考: 兔子哥哥