存檔

‘網絡編程’ 分類的存檔

TCP連接建立的三次握手與連接斷開四次揮手

2017年9月4日 沒有評論

TCP三次握手

一、什么是三次握手

三次握手(Three-way Handshake),是指建立一個TCP連接時,需要客戶端和服務器總共發送3個包。

二、三次握手的目的

三次握手的目的是連接服務器指定端口,建立TCP連接,并同步連接雙方的序列號和確認號并交換 TCP 窗口大小信息。客戶端執行連接請求時。將觸發三次握手。

三、三次握手過程

第一次握手:
客戶端發送一個TCP的SYN標志位置1的包指明客戶打算連接的服務器的端口,以及初始序號X,保存在包頭的序列號(Sequence Number)字段里。
第二次握手:
服務器發回確認包(ACK)應答。即SYN標志位和ACK標志位均為1同時,將確認序號(Acknowledgement Number)設置為客戶的ISN加1以.即X+1。
第三次握手.
客戶端再次發送確認包(ACK) SYN標志位為0,ACK標志位為1。如果正確則連接建立成功,客戶端和服務器進入ESTABLISHED狀態,完成三次握手,隨后客戶端與服務器之間可以開始傳輸數據了。把服務器發來ACK的序號字段+1,放在確定字段中發送給對方.并且在數據段放寫ISN的+1。

TCP四次揮手

一、什么是四次揮手

TCP的連接的拆除需要發送四個包,因此稱為四次揮手(four-way handshake)。客戶端或服務器均可主動發起揮手動作,任何一方執行close操作即可產生揮手操作。

二、四次揮手過程

第一次揮手:

客戶端發送一個FIN,用來關閉客戶端到服務器的數據傳送,客戶機進入FIN_WAIT_1狀態。
第二次揮手:

服務器收到FIN后,發送一個ACK給客戶端,確認序號為收到序號+1(與SYN相同,一個FIN占用一個序號),服務器進入CLOSE_WAIT狀態。
第三次揮手:

服務器發送一個FIN,用來關閉服務器到客戶端的數據傳送,服務器進入LAST_ACK狀態。
第四次揮手:

客戶端收到FIN后,客戶端進入TIME_WAIT狀態,接著發送一個ACK給服務器,確認序號為收到序號+1,服務器進入CLOSED狀態,完成四次揮手。

有限狀態機FSM:Finite State Machine
1、CLOSED 沒有任何連接狀態
2、LISTEN 偵聽狀態,等待來自遠方TCP端口的連接請求
3 、SYN-SENT 在發送連接請求后,等待對方確認
4、SYN-RECEIVED 在收到和發送一個連接請求后,等待對方確認
5、ESTABLISHED 代表傳輸連接建立,雙方進入數據傳送狀態
6、FIN-WAIT-1 主動關閉,主機已發送關閉連接請求,等待對方確認
7 、FIN-WAIT-2 主動關閉,主機已收到對方關閉傳輸連接確認,等待對方發送關閉傳輸連接請求
8、 TIME-WAIT 完成雙向傳輸連接關閉,等待所有分組消失
9、CLOSE-WAIT 被動關閉,收到對方發來的關閉連接請求,并已確認
10、LAST-ACK 被動關閉,等待最后一個關閉傳輸連接確認,并等待所有分組消失

11、CLOSING 雙方同時嘗試關閉傳輸連接,等待對方確認

附加問題:

【問題1】為什么連接的時候是三次握手,關閉的時候卻是四次揮手?
答:因為當服務器收到客戶端的SYN連接請求報文后,可以直接發送SYN+ACK報文。其中ACK報文是用來回應的,SYN報文是用來同步的。但是關閉連接時,當服務器收到FIN報文時,很可能并不會立即關閉SOCKET,所以只能先回復一個ACK報文,告訴客戶端,”發送的FIN報文已經收到”。只有等到客戶端所有的報文都發送完了,客戶端才能發送FIN報文,因此不能一起發送。故需要四步揮手。
【問題2】為什么TIME_WAIT狀態需要經過2MSL(最大報文段生存時間)才能返回到CLOSE狀態?
答:四個報文都發送完畢,客戶端和服務器可以直接進入CLOSE狀態了,但有可能最后一個ACK丟失。所以TIME_WAIT狀態就是用來重發可能丟失的ACK報文,確保之前的數據不會丟失后再進入close狀態。

原文:http://www.178linux.com/85976

分類: 網絡編程 標簽:

epoll入門實例

2016年4月10日 沒有評論

epoll是目前進行服務器端編程的普遍選擇,好處很多,這里不再贅述,本文主要描述如何在c語言中使用epoll的完整樣例程序。
首先介紹用到的數據結構和三個api說明,然后通過編寫一個打印所有輸入到socket的字符輸出到終端的服務器端的程序來完成整個例子。

epoll_event是用來對要監控的socket描述, 它包括epoll_data_t和要監控的事件類型的(一個__uint32_t類型的events)。epoll_data_t里的fd是用來存儲要監控的文件描述符。

events 結構體中第一個參數支持的事件類型

– EPOLLIN,讀事件

– EPOLLOUT,寫事件

– EPOLLPRI,帶外數據,與select的異常事件集合對應

– EPOLLRDHUP,TCP連接對端至少寫寫半關閉

– EPOLLERR,錯誤事件

– EPOLLET,設置事件為邊沿觸發

– EPOLLONESHOT,只觸發一次,事件自動被刪除

epoll在一個文件描述符上只能有一個事件,在一個描述符上添加多個事件,會產生EEXIST的錯誤。同樣,刪除epoll的事件,只需描述符就夠了

使用epoll的三個api
頭文件 /usr/include/sys/epoll.h
1. 生成一個epoll專用的文件描述符
如果調用成功返回0,不成功返回-1

epoll_create返回的是一個文件描述符,也就是說epoll是以特殊文件的方式體現給用戶
__size提示操作系統,用戶可能要使用多少個文件描述符,該參數已經廢棄,填寫一個大于0的正整數

2.用于控制某個文件描述符上的事件,可以注冊事件,修改事件,刪除事件。
如果調用成功返回0,不成功返回-1

3.用于輪詢I/O事件的發生,返回發生事件數

epoll的api使用方式
1.epoll_create 生成的epoll專用的文件描述符
2.使用epoll_ctl注冊事件,修改事件,刪除事件對應的文件描述符到epollfd指定的epoll內核事件表中
3.使用epoll_wait阻塞等待注冊的文件描述符上可讀事件的發生
4.當有新客戶端的連接或者客戶端的數據寫入,返回需要處理的事件數目

epoll的兩種模式

1. 水平觸發(LT):使用此種模式,當數據可讀的時候,epoll_wait()將會一直返回就緒事件。如果你沒有處理完全部數據,并且再次在該epoll實例上調用epoll_wait()才監聽描述符的時候,它將會再次返回就緒事件,因為有數據可讀。ET只支持非阻塞socket。

2. 邊緣觸發(ET):使用此種模式,只能獲取一次就緒通知,如果沒有處理完全部數據,并且再次調用epoll_wait()的時候,它將會阻塞,因為就緒事件已經釋放出來了。

ET的效能更高,但是對程序員的要求也更高。在ET模式下,我們必須一次干凈而徹底地處理完所有事件。LT兩種模式的socket都支持。

實例代碼

1.創建并綁定服務器端socket
采用一種可移植的方式來生產socket,getaddrinfo返回對應的網卡信息,遍歷對應的網絡接口生成socket
成功返回socket文件描述符,失敗返回-1

2.設置socket為非阻塞模式
通過在文件描述符上設置 O_NONBLOCK 表識來實現非阻塞socket

3.event 循環處理

main函數的流程是
1. create_and_bind創建服務器端的socket描述符
2. 設置描述符為非阻塞
3. 監聽描述符
4. 創建epoll文件描述符efd
5. 使用邊緣觸發的方式添加sfd輸入監聽事件

最外層的while循環時主事件循環(event loop)。調用epoll_wait阻塞等待事件發生,當事件到達epoll_wait返回事件在事件參數中,一批epoll_event結構體。
epoll事件循環中epoll實例在建立新連接時候添加事件和當斷開連接的時候刪除事件。

當事件發生時,有如下幾種方式
錯誤:當發生錯誤,或者不是可讀事件通知時,簡單關閉文件描述符,關閉文件描述符會自動從efd的監控集中刪除。
新連接:當監聽描述符可讀時,表示有新的連接到達,accept()新連接,設置新連接描述符為非阻塞并添加到efd監控集中。
客戶端數據:當任何一個客戶端文件描述符可讀,使用read()每次讀區512字節循環讀取。 因為我們需要讀取當前所有可讀區數據 ,當邊緣觸發的情況下不會再次通知可讀。 讀取到的數據調用write寫到標準輸出stdout (fd=1)。如果read(2)返回0,表示EOF并切可以關閉客戶端連接。如果返回-1并且 errno設置為EAGAIN表示這個事件所有可讀的數據讀取完畢可以返回進入主事件循環。

就這樣不斷的循環,添加和刪除文件描述符到efd的監控集中。
https://banu.com/blog/2/how-to-use-epoll-a-complete-example-in-c/

分類: 網絡編程 標簽:

區分同步 異步 阻塞 非阻塞

2016年1月18日 沒有評論

同步/異步
首先來解釋同步和異步的概念,這兩個概念與消息的通知機制有關.
舉個例子,比如我去銀行辦理業務,可以自己去排隊辦理,也可以叫人代辦,等他幫忙處理完了直接給我結果,對于要辦理這個銀行業務的人而言,自己去辦理是同步方式,而別人代辦完畢則是異步方式.區別在于,同步的方式下,操作者主動完成了這件事情.異步方式下,調用指令發出之后,操作馬上就返回了,操作者并不能馬上就知道結果了,而是等待所調用的異步過程(在這個例子中是幫忙代辦的人)處理完畢之后,通過通知手段(在代碼中通常是回調函數)來告訴操作者結果.
異步IO
在上圖的異步IO模型中,應用程序調用完aio_read之后,不論是否有數據可讀,這個操作都會馬上返回,這個過程相當于這個例子中委托另一個人去幫忙代辦銀行業務的過程,當數據讀完拷貝到用戶內存之后,會發一個信號通知原進程告訴讀數據操作已經完成(而不僅僅是有數據可讀).

阻塞/非阻塞
接著解釋阻塞/非阻塞的概念,這兩個概念與程序處理事務時的狀態有關.
同樣是前面的例子,當真正執行辦理業務的人去辦理銀行業務時,前面可能已經有人排隊等候了.如果這個人一直從排隊到辦理完畢,中間都沒有做過其他的事情,那么這個過程就是阻塞的,這個人當前只在做這么一件事情.
阻塞IO
在上圖中,應用程序發起recvfrom操作之后,要等待數據拷貝成功才能返回,這一整個過程中,不能做其它的操作,這個就是典型的阻塞IO.

反之,如果這個人發現前面排隊的人不少,于是選擇了出去逛逛,過了一會再回來看看有沒有輪到他的號被叫到,如果沒有又繼續出去逛過一陣再回來看看,如此以往,這個過程就是非阻塞的,因為處理這個事情的人,在這整個過程中,并沒有做到除了這件事之外不能再做別的事情,他的做法是反復的過來嘗試,如果沒有完成就下一次再次嘗試完成這件事情.
非阻塞IO
上圖與前面阻塞IO圖示的區別在于,當沒有數據可讀時,同樣的recvfrom操作返回了錯誤碼,表示當前沒有可讀數據,換言之,即使沒有數據也不會一直讓這個應用阻塞在這個調用上,這就是非阻塞IO.

到了這里,可以先簡單的小結一下這兩組概念了:

阻塞/非阻塞:區別在于完成一件事情時,是不是當事情還沒有完成時,處理這件事情的人除此之外不能再做別的事情.
同步/異步:是自己去做這件事情,還是等別人做好了來通知你做好了,然后自己去拿結果.注意,這里說的是拿結果.如果只是別人告訴你可以做某事,然后自己去操作,這種情況下也是同步的操作,在后面多路復用I/O中會進行闡述.

可見,兩組概念不是一個維度的概念.我們把需要辦理銀行業務的人稱為A,把代辦理的人稱為B,那么在A委托B辦理業務的情況下,假設A在交代B幫忙辦事之后,A就去做別的事情了,那么A并不存在針對辦理銀行業務這件事情而言是阻塞還是非阻塞,辦理事務時阻塞與否是針對真正需要辦理這件事情的人,也就是這個例子里的B.

與多路復用I/O的聯系
前幾年寫上一篇文章的時候,將多路復用I/O類的select/poll等和異步操作混為一談,在這里需要特別做一些補充說明.在以前的說明中,就這個例子而言,我列舉了一個情況,當去辦理業務的人,需要排隊時通常都會先去叫號拿到一個紙條上面寫了號碼,然后等待銀行叫號,在那個例子里面,我將銀行叫號比作select操作,把紙條比作向select注冊的回調函數,一旦可以進行操作的條件滿足,就會根據這個回調函數來通知辦理人,然后辦理人再去完成工作,因此select等多路復用操作是異步的行為.

上面那個例子,最大的錯誤在于,沒有意識到,同步與異步的區別在于是不是要求辦理者自己來完成,所有需要自己去完成操作的都是同步操作,不管是注冊了一個回調(這里的叫號小紙條)等待別人回調你,還是自己一直阻塞等待.在上面的例子中,雖然對需要辦理業務的人而言,通過叫號小紙條,他可以等待銀行的辦理通知,等待的同時可以去做點別的事情,比如看看手機什么的,但是只要可以辦理該業務的條件滿足,真正叫到了你的號可以辦理業務時,辦理者是需要自己去完成辦理的.

換言之,在完成一件事情時,這里需要區分處理兩種狀態:一是這個事情是不是可以做了(條件滿足的消息,如select告訴你某個文件描述符可讀),一是完成了這件事情(如調用read/write完成IO操作).多路復用IO做的,是它可以記錄下來有哪些人在等待消息的通知,在條件滿足時負責通知辦理者,而完成這件事情還是需要辦理者自己去完成.只要是自己去完成的操作,都是同步的操作.

UNP的6.2節中,最后對異步/同步做的總結是最準確的了:

POSIX defines these two terms as follows:

A synchronous I/O operation causes the requesting process to be blocked until that I/O operation completes.
An asynchronous I/O operation does not cause the requesting process to be blocked.
Using these definitions, the first four I/O models—blocking, nonblocking, I/O multiplexing, and signal-driven I/O—are all synchronous because the actual I/O operation (recvfrom) blocks the process. Only the asynchronous I/O model matches the asynchronous I/O definition.

http://www.codedump.info/?p=515

分類: 網絡編程 標簽:
极速快乐十分助手