socket 的通訊過程

2021-09-07 16:19:57 字數 3308 閱讀 7954

1.建立套接字

linux在利用socket()系統呼叫建立新的套接字時,需要傳遞套接字的位址族識別符號、套接字型別以及協議,其函式定義於net/socket.c中:

asmlinkage long sys_socket(int family, int type, int protocol)

實際上,套接字對於使用者程式而言就是特殊的已開啟的檔案。核心中為套接字定義了一種特殊的檔案型別,形成一種特殊的檔案系統sockfs,其定義於net/socket.c:

static struct vfsmount *sock_mnt;

static declare_fstype(sock_fs_type, "sockfs", sockfs_read_super, fs_nomount);

在系統初始化時,要通過kern_mount()安裝這個檔案系統。安裝時有個作為連線件的vfsmount資料結構,這個結構的位址就儲存在乙個全域性的指標sock_mnt中。所謂建立乙個套接字,就是在sockfs檔案系統中建立乙個特殊檔案,或者說乙個節點,並建立起為實現套接字功能所需的一整套資料結構。所以,函式sock_create()首先是建立乙個socket資料結構,然後將其「對映」到乙個已開啟的檔案中,進行socket結構和sock結構的分配和初始化。

新建立的 bsd socket 資料結構包含有指向位址族專有的套接字例程的指標,這一指標實際就是 proto_ops 資料結構的位址。

bsd 套接字的套接字型別設定為所請求的 sock_stream 或 sock_dgram 等。然後,核心利用 proto_ops 資料結構中的資訊呼叫位址族專有的建立例程。

之後,核心從當前程序的 fd 向量中分配空閒的檔案描述符,該描述符指向的 file 資料結構被初始化。初始化過程包括將檔案操作集指標指向由 bsd 套接字介面支援的 bsd 檔案操作集。所有隨後的套接字(檔案)操作都將定向到該套接字介面,而套接字介面則會進一步呼叫位址族的操作例程,從而將操作傳遞到底層位址族

實際上,socket結構與sock結構是同一事物的兩個方面。如果說socket結構是面向程序和系統呼叫介面的,那麼sock結構就是面向底層驅動程式的。可是,為什麼不把這兩個資料結構合併成乙個呢?

我們說套接字是一種特殊的檔案系統,因此,inode結構內部的union的乙個成分就用作socket結構,其定義如下:

struct inode {

…union

}由於套接字操作的特殊性,這個結構中需要大量的結構成分。可是,如果把這些結構成分全都放在socket結構中,則inode結構中的這個union就會變得很大,從而inode結構也會變得很大,而對於其他檔案系統,這個union成分並不需要那麼龐大。因此,就把套接字所需的這些結構成分拆成兩部分,把與檔案系統關係比較密切的那一部分放在socket結構中,把與通訊關係比較密切的那一部分則單獨組成乙個資料結構,即sock結構。由於這兩部分資料在邏輯上本來就是一體的,所以要通過指標互相指向對方,形成一對一的關係。

2.在 inet bsd 套接字上繫結(bind)位址

為了監聽傳入的 internet 連線請求,每個伺服器都需要建立乙個 inet bsd 套接字,並且將自己的位址繫結到該套接字。繫結操作主要在 inet 套接字層中進行,還需要底層 tcp 層和 ip 層的某些支援。將位址繫結到某個套接字上之後,該套接字就不能用來進行任何其他的通訊,因此,該 socket資料結構的狀態必須為 tcp_close。傳遞到繫結操作的 sockaddr 資料結構中包含要繫結的 ip位址,以及乙個可選的埠位址。通常而言,要繫結的位址應該是賦予某個網路裝置的 ip 位址,而該網路裝置應該支援 inet 位址族,並且該裝置是可用的。利用 ifconfig 命令可檢視當前活動的網路介面。被繫結的 ip 位址儲存在 sock 資料結構的rcv_saddr 和 saddr 域中,這兩個域分別用於雜湊查詢和傳送用的 ip 位址。埠位址是可選的,如果沒有指定,底層的支援網路會選擇乙個空閒的埠。

當底層網路裝置接受到資料報時,它必須將資料報傳遞到正確的 inet 和 bsd 套接字以便進行處理,因此,tcp維護多個雜湊表,用來查詢傳入 ip 訊息的位址,並將它們定向到正確的socket/sock 對。tcp 並不在繫結過程中將繫結的 sock 資料結構新增到雜湊表中,在這一過程中,它僅僅判斷所請求的埠號當前是否正在使用。在監聽操作中,該 sock 結構才被新增到 tcp 的雜湊表中。

3.在 inet bsd 套接字上建立連線(connect)

建立乙個套接字之後,該套接字不僅可以用於監聽入站的連線請求,也可以用於建立出站的連線請求。不論怎樣都涉及到乙個重要的過程:建立兩個應用程式之間的虛擬電路。出站連線只能建立在處於正確狀態的 inet bsd 套接字上,因此,不能建立於已建立連線的套接字,也不能建立於用於監聽入站連線的套接字。也就是說,該 bsd socket 資料結構的狀態必須為 ss_unconnected。

在建立連線過程中,雙方 tcp 要進行三次「握手」,具體過程在 本章第二節——網路協議一文中有詳細介紹。如果 tcp sock 正在等待傳入訊息,則該 sock 結構新增到 tcp_listening_hash 表中,這樣,傳入的 tcp 訊息就可以定向到該 sock 資料結構。

4.監聽(listen) inet bsd 套接字 

當某個套接字被繫結了位址之後,該套接字就可以用來監聽專屬於該繫結位址的傳入連線。網路應用程式也可以在未繫結位址之前監聽套接字,這時,inet 套接字層將利用空閒的埠編號並自動繫結到該套接字。套接字的監聽函式將 socket 的狀態改變為 tcp_listen。

當接收到某個傳入的 tcp 連線請求時,tcp 建立乙個新的 sock 資料結構來描述該連線。當該連線最終被接受時,新的 sock 資料結構將變成該 tcp 連線的核心bottom_half部分,這時,它要轉殖包含連線請求的傳入 sk_buff 中的資訊,並在監聽 sock 資料結構的 receive_queue 佇列中將轉殖的資訊排隊。轉殖的 sk_buff 中包含有指向新 sock 資料結構的指標。

5.接受連線請求 (accept)

接受操作在監聽套接字上進行,從監聽 socket 中轉殖乙個新的 socket 資料結構。其過程如下:接受操作首先傳遞到支援協議層,即 inet 中,以便接受任何傳入的連線請求。相反,接受操作進一步傳遞到實際的協議,例如 tcp 上。接受操作可以是阻塞的,也可以是非阻塞的。接受操作為非阻塞的情況下,如果沒有可接受的傳入連線,則接受操作將失敗,而新建立的 socket 資料結構被拋棄。接受操作為阻塞的情況下,執行阻塞操作的網路應用程式將新增到等待佇列中,並保持掛起直到接收到乙個 tcp 連線請求為至。當連線請求到達之後,包含連線請求的 sk_buff 被丟棄,而由 tcp 建立的新 sock 資料結構返回到 inet 套接字層,在這裡,sock 資料結構和先前建立的新 socket 資料結構建立鏈結。而新 socket 的檔案描述符(fd)被返回到網路應用程式,此後,應用程式就可以利用該檔案描述符在新建立的 inet bsd 套接字上進行套接字操作。

Socket通訊過程

伺服器端 accept 以同步方式從偵聽套接字的連線請求佇列中提取第乙個掛起的連線請求,然後建立並返回新的socket。不能使用返回的這個 socket 接受連線佇列中的任何附加連線。然而,可以呼叫返回的 socket 的remoteendpoint 方法來標識遠端主機的網路位址和埠號。在阻止模式中...

socket通訊過程

一 網路位元組序與主機位元組序 1 主機位元組序 就是自己的主機內部,記憶體中資料的儲存順序,可以分為兩種 2 網路位元組序 大端位元組序即網路位元組序 3 資料傳輸過程 a的固有資料儲存 標準化 轉化成b的固有格式 iia的主機位元組序 網路位元組序 b的主機位元組序 標準化原因 不同的cpu有不...

通訊過程Socket程式設計

c s模式 瀏覽器 browser 伺服器 server 模式。只需在一端部署伺服器,而另外一端使用每台pc都預設配置的瀏覽器即可完成資料的傳輸。優缺點 簡單的c s模型通訊 server端 listen函式 func listen network,address string listener,e...