深入學習TCP套介面

2021-10-10 15:56:05 字數 4497 閱讀 7660

基本tcp套介面編( 網路i/o)

雖然都知道套介面可以完成兩個主機之間的網路通訊,但也就只是知道,有很多已經寫好的**,我們直接copy一些就可以用了,但是!!你理解他為何這樣用麼?tcp/udp又到底是啥?tcp/udp又是怎麼和socket聯絡在一起的?tcp三次握手又是如何產生的???

今天我們就先來談談tcp套介面好好學習吧 好嘛? 少看zhibo

***********************************===正經分界線,現在開始嚴肅!!進入學霸角色

老生常談tcp client 建立tcp sockect 通訊步驟分別是: socket->connet->write->read->close (劃重點client在呼叫connect前不必非得bind!!!!!因為如果需要的話核心會確定乙個源ip位址,並選擇乙個臨時埠作為源埠)

竟然剛開始就呼叫了socket函式怎們就下來看看它!整明白

#include

int socket(int family,int type,int protocal)//socket在返回成功時返回乙個最小的非負整數(後面你會看到只要是返回描述符都是返回當前最小的未用的描述符),失敗時返回-1,因為這是套介面返回的所以我們叫他「套介面表述符」 簡稱「套接字」

為了執行網路i/o,乙個程序必須做的第一件事就是呼叫socket函式,指定期望的通訊協議(你是要建立tcp連線還是udp連線呀?你是要使用ipv6還是ipv4呀?你得自己先搞清楚你要建立啥樣的連線吧!這些就是通過這三個引數指定的)

familyaf_inetipv4協議af_inte6ipv6協議af_localunix域協議af_route路由套介面協議af_key

金鑰套介面

typesock_stream位元組流套介面sock_dgram資料報套介面sock_seqpacket有序分組套介面sock_raw原始套介面

protocal

ipproto_tcp 

tcp傳輸協議

ipproto_udp

udp傳輸協議

ipproto_scp

sctp傳輸協議 (注意該引數如果設定為0就預設選擇系統預設值)

family 和 type 對應的protocal預設如下:(註並不是所有的組合都有意義,空白部分組合無效)

af_inet    af_inet6    af_local    af_route      af_key

tcp|sctp

tcp|sctp

yesudp

udpyes

sctp

sctp

yesipv4

ipv6

yesyes

sock_stream

sock_dgram

sock_seqpacket

sock_raw

af_*** 與 pf_***

有的時候你看code會發現上面的family使用了pf_inet這和上面指定的不同呀!這啥意思?搞得腦子特別胡亂!那麼讓我現在告訴你

af_***字首表示位址族,pf_***字首表示協議族。在很久很久以前有這樣乙個想法:單個協議族可以支援多個位址族,pf_用來建立套介面,af_用來建立套介面位址,但實際上支援多個位址族的協議族從來就未實現過(純屬扯犢子呢),而且裡給定協議定義的pf_值總是等於af_值,所以後面我們會都用af_常值,雖然我們會遇到使用pf_值的code。

int connect(int sockfd, const struct sockafddr *servaddr, socklen_t addrlen);

sockfd 就是socket()返回的套接字,servaddr是乙個指向套介面位址結構的指標(必須包含伺服器的ip位址和埠號),如果是tcp套介面,呼叫connect函式並激發tcp三路握手過程!!!而且在建立成功或出錯時才返回!

錯誤返回有以下幾種情況:

1.tcp客戶端沒有收到syn響應,則返回etimedout,可以理解為client已經進行超時重傳了但是還沒有等到server 的 ack,就會這個鴨子!

2.tcp客戶端收到的響應是rst(表示復位),則表示該伺服器在我們指定的埠上沒有程序在等待與之連線(例如伺服器程序沒有執行)。這是一種硬錯誤,客戶端一旦收到rst就馬上返回econnrefused錯誤。(產生rst的三個條件:目的地為某埠的syn到達,但是埠上沒有要監聽的服務;tcp想取消乙個已有的連線;tcp連線到乙個根本不存在連線的分節上)

3.客戶發出的syn在中間路由上引發了"destination unreachable」,客戶主機儲存改訊息,繼續發syn就像第一種情況一樣(75秒沒有回),則把儲存的訊息作為ehostunreachenetunreach錯誤返回給程序。

注意:connect()函式會導致tcp狀態從close狀態轉換到syn_sent狀態,若建立成功再轉移到established狀態,若失敗就需要關閉該套介面。

bind函式把乙個本地協議位址賦予乙個套介面。對於網際協議,協議位址是32位ipv4位址或128位ipv6位址與16位tcp或udp埠的組合.

int bind(int sockfd,const struct sockaddr *myaddr, socklen_t addrlen); //成功返回0 失敗返回-1

在伺服器測我們可以使用bind也可以不使用bind,如果使用bind我們也可以指定埠或不指定埠,對於沒有指定的部分核心會選擇乙個臨時的埠,如果沒有指定ip那麼核心等到套介面已連線或在套介面發出資料的時候才分配乙個位址。

inaddr_any通配位址,一般為0。

使用方法:

struct sockaddr_in servaddr;

servaddr.sin_addr.s_addr =  htol(inaddr_any);

bind函式常見的錯誤就是eaddrinuse(address already in use)

int listen(int sockfd, int backlog); //成功返回0 出錯返回 -1

僅tcp伺服器可以使用,他做了兩件事

1.socket函式建立乙個套介面時,他被設定成乙個主動套介面,也就是說她是乙個將呼叫connect的客戶套介面。listen函式把乙個未連線的套介面轉換成乙個被動套介面,指示核心應該接受指向該套介面的連線請求。listen導致套介面從close狀態轉換到listen狀態。

2.第二個引數規定了核心為套介面排隊的最大已完成連線數;

為了更好地理解backlog 我們必須認識到核心為每乙個監聽套介面維護著兩個佇列:

(1)未完成連線佇列:那些處於syn_rcvd狀態的套介面

(2)已完成連線佇列:那些處於established狀態的套介面

int accept(int sockfd, struct sockaddr *cliaddr,socklen_t *addrlen); //成功返回0 失敗返回-1

針對該函式的返回值我們叫他是已連線的套介面(核心為每乙個由伺服器程序接受的客戶連線建立了乙個已連線套介面),第乙個引數稱作監聽套介面(該程式生命週期內一直存在)

cliaddr 和 addrlen 用來返回對端(客戶)的協議位址,addrlen是值結果引數,呼叫前,我們將*addrlen 所引用的整數值設定為cliaddr所指向的套介面的位址長度;返回時,即為由核心存在的該套介面位址結構的確切位元組數。

該函式有三個返回值

(1)既可能是新套介面描述字,也可能是出錯指示整數

(2)客戶程序的協議位址

(3)客戶位址的大小

int close(int sockfd); //成功返回0 失敗返回 -1

使用close以後的套介面不能做read 和 write 的第乙個引數,然而tcp嘗試傳送已排隊等待傳送到對端的任何資料,傳送完畢後發生的是tcp連終止序列。

TCP套介面程式設計 Socket

tcp套介面程式設計 socket socket起源於unix,而unix linux基本哲學之一就是 一切皆檔案 都可以用 開啟open 讀寫write read 關閉close 模式來操作。我的理解就是socket就是該模式的乙個實現,socket即是一種特殊的檔案,一些socket函式就是對其...

Map深入學習 一 Map介面簡介

map使用鍵值對來儲存資料。map是乙個介面,定義了對資料的增刪改查,替換和比較等等基本的操作。map內部定義了乙個內部介面entry,可以通過map的 set entryset 來獲取entry物件。map怎麼判斷鍵值 key 是否存在呢?看看原始碼的實現 default v putifabsen...

UIApplication深入學習

新建乙個任意型別的ios應用工程,加入我們在class prefix輸入是tc,我們可以看到工程中生成乙個類 在main函式中,autoreleasepool 函式中 說明 當應用程式將要入非活動狀態執行,在此期間,應用程式不接收訊息或事件。比如來 了。說明 當應用程式入活動狀態執行,這個剛好跟上面...