1. 程式人生 > >socket網路程式設計複習筆記(三):套接字描述符背後的祕密

socket網路程式設計複習筆記(三):套接字描述符背後的祕密

1.套接字概念回顧

(1)套接字是一個識別符號;
(2)套接字是一個結構;
(3)套接字是一個包含標識、資料和操作的複合體,是服務訪問點。
我們已經知道,一個套接字描述符s實際上是一個整形資料,在winsock.h標頭檔案中,SOCKET是這樣被定義的:

typedef unsigned int u_int;
typedef u_int SOCKET;

但是,我們不得不提出一個問題,簡簡單單的一個整形資料,怎麼可能完成如此複雜的通訊功能呢?

2.套介面結構

真實的情形當然複雜一些。
我們應該已經注意到,申請套接字描述符是一個動作,申請套接字描述符所要佔用的資源是另一個動作:

s = socket(af,type,proto);

socket函式的作用就是製造s對應的套介面結構。
來看一看套介面結構的定義:

struct socket{
    short so_type;
    short so_option;
    short so_linger;
    short so_state;
    caddr_t so_pcb;
    struct protosw *so_proto;
    struct socket *so_head;
    struct socket *so_q0;
    struct socket *so_q;
    short
so_q0len; short so_qlen; short so_qlimit; short so_timeo; u_shurt so_error pid_t so_pgid; u_long so_oobmark; struct sockbuf so_rcv, so_snd; caddr_t so_tpcb; void (*so_upcall)(struct socket *so, caddr_t arg, int waitf); caddr_t so_upcallarg; }

系統通過套接字識別符號,找尋的就是這樣一個套介面結構。
不難看出,套介面結構中包含了一次通訊所需要的豐富的資源和服務。
我們可以從兩個層次去理解這樣做的用意:
一,從使用者角度來看:只需給出識別符號就能找到,具有透明性、方便性(使用者不需掌握找尋的方法);
二,從系統的角度來看,系統如何根據識別符號找到套介面,這是一個系統設計的問題。

自然而然地,接下來的問題就變成了:該如何去設計套接字識別符號和套介面結構的對應呢?系統該如何設計?

3.尊卑有別:套介面與套接字

我們可以考慮利用索引表的形式,通過套接字描述符找到對應的套介面結構。我們假設索引表是一個程序符號表,第一列是套接字描述符向量(socket_id),第二列是對應的關係對映(到的套介面結構起始地址)。
因此,套接字描述符可以看做是套介面資源的編號,那麼該如何分配套接字描述符呢?
參照埠號的分配方式,無外乎是兩種:全域性分配(統一分配)和區域性分配(本地分配)。
若是全域性分配,則系統的所有套介面資源進行統一編號,不同程序得到的套接字描述符各不相同,雖然便於管理但程序的獨立性差(要求保證各個程序套接字描述符相異,會降低效率);
若是區域性分配,則套介面資源僅在一個程序內部統一編號,且不同程序可使用相同的套接字描述符。雖然保證了程序的獨立性,但是管理上會變得混亂(給定一個套接字,不能辨別出來自哪個程序)。
在實用模型中,我們採取的方案是區域性分配,因為全域性分配對系統來說確實太過複雜(或者說低效)。

我們將套接字程式設計的關係以套接字為中心展開,上面我們討論的是從上至下的對映方式(套接字描述符到套介面資源),接下來我們從下往上的對映方式(從埠到套介面資源)再來考慮考慮。

4.另一種關係:埠與套介面

我們想問的是這樣三個問題:
第一,TCP實體依據什麼來處理接收到的報文?
第二,TCP實體如何處理報文?
第三,使用者程序如何獲取報文?
前面已經提到,一個端點地址結構中應當包含ip地址和埠號,而bind()函式(或者是隱式繫結亦然)會在套接字上繫結端點地址。因此第一個問題的答案非常容易:根據報文中的埠資訊找到對應的套介面結構。
套介面結構定義中有一個struct sockbuf so_rcv, so_snd,而sockbuf定義又如下所示:

struct sockbuf{
    u_long sb_cc;
    u_long sb_hiwat;
    u_long sb_mbcnt;
    u_long sb_mbmax;
    long sb_lowat
    struct mbuf *sb_mb;
    struct selinfo sb_sel;
    short sb_flags;
    short sb_timeo;
}

因此第二個問題也是好回答的:將報文掛在與埠繫結的套介面接收佇列上。
至於使用者如何獲取報文,當然是從套介面接收佇列中取出了。
接下來我們要探討一個更為複雜的問題:套介面、套接字描述符、埠這三者的關係該如何理解?

5.三方混戰:套接字、埠與套介面

套接字描述符、套介面結構和埠是相對獨立的三個概念,而且一般來說它們是一一對應的。一個套接字描述符在使用socket()後,就對應了一個特定的套介面結構,而在使用bind()之後,該套介面結構也就工作在特定的埠上了,等到connect()完成,對方的端點就也確定了。
我們再來把這三者的關係理清來說一遍:
應用程序通過套接字描述符從而找到套介面結構;
TCP實體通過埠號找到工作在其上的套介面結構;
套接字描述符與套介面結構的對映關係是通過socket()函式實現的;
埠號是在bind()函式中填寫到套介面中的。
接下來是對腦力的考驗,我們再來審視這三者所做出的不同排列組合(以下只列舉看上去不正常的組合)有何現實的意義:
版權歸段王爺

(1)一個套接字描述符對應多個套介面?
若是在一個程序內發生,則識別符號的意義被顛覆(同時指向兩種不同地通訊資源);若是不同程序的同一值描述符對應多個套介面,則是允許的,因為前面已經有所鋪墊:在實際中,套接字標識符采用區域性分配的方式。
(2)多個套接字描述符對應一個套介面?
這樣可以提供通訊資源的共享,但會在資料歸屬上出現混亂(比如recvbuf中的資料到底該提交給哪個應用程序?)。
(3)多個套介面對應一個埠?
只要兩個端點之一不一樣,就是兩個不同的通訊關係,並無衝突。實際上伺服器就是通過在一個埠上同時有多個套接字活動來提供多使用者同時接入功能的。
(4)一個套介面對應多個埠?
這一點比較難想出個所以然來,不過這種一點對多點的方式在特殊場合可能是有用的(比如想通過同一個recvbuf來接收不同伺服器的回送訊息)。

6.結論

一個全相關包含五個要素,以確定一次通訊:A的埠號+A的IP地址+B的埠號+B的IP地址+協議。兩個裝置只要任一要素不同都應該被認為是不同的通訊。
在套介面結構裡,記錄了全相關的全部要素因此通過兩個套接字就能夠確定一次通訊。對於其中一方,一個套接字描述符對應於一個套接字結構,就能對應於一次通訊,具體就表現在recv()和send()等函式中不再需要目的地址資訊。

相關推薦

socket網路程式設計複習筆記描述背後祕密

1.套接字概念回顧 (1)套接字是一個識別符號; (2)套接字是一個結構; (3)套接字是一個包含標識、資料和操作的複合體,是服務訪問點。 我們已經知道,一個套接字描述符s實際上是一個整形資料,在winsock.h標頭檔案中,SOCKET是這樣被定義的:

Unix網路程式設計讀書筆記

這一章正式開始網路程式設計的內容,先將書中的示例編寫如下: 首先是伺服器端: #include <sys/socket.h> #include <netinet/in.h> #include <unistd.h> #include &l

Windows Socket-MFC程式設計

同步:指傳送方發出資料後,等收到接收方發回的響應,才發下一個數據包的通訊方式 非同步:指的是傳送方不等接收方響應,便接著發下個數據包的通訊方式; 阻塞:指呼叫某函式時,直到該函式完成操作,才返回;否則一直阻塞在該呼叫上 非阻塞:指呼叫某操作時,不管操作是否成功都立即返回,而不

Java高併發程式設計學習筆記Java記憶體模型和執行緒安全

文章目錄 原子性 有序性 可見性 – 編譯器優化 – 硬體優化(如寫吸收,批操作) Java虛擬機器層面的可見性 Happen-Before規則(先行發生) 程式順序原則: volat

C語言網路程式設計建立通訊TCP

為了實現伺服器與客戶機的通訊,伺服器和客戶機都必須建立套接字。伺服器與客戶機的工作原理可以用下面的過程來描述。 (1)伺服器先用socket函式來建立一個套接字,用這個套接字完成通訊的監聽。 (2)用bind函式來繫結一個埠號和IP地址。因為本地計算機可能有多個網絡卡和IP

C#學習筆記邏輯關系運算和if語句

同學 判斷 請問 登陸 tasks 不同 入學 根據 重要 條件語句 分支語句和循環語句是程序裏最重要的邏輯。 IF語句、分支語句、循環語句 using System; using System.Collections.Generic; using System

TCP/IP網路程式設計 學習筆記_8 --優雅地斷開連線

基於TCP的半關閉 TCP中的斷開連線過程比建立連線過程更重要,因為建立連線過程一般不會出現什麼大的變數,但斷開過程就有可能發生預想不到的情況,因此要準確的掌控。 單方面斷開連線帶來的問題 Linux的close函式和Windows的closesocke

python複習筆記

此筆記摘錄於廖雪峰先生的教程,感謝廖先生的無私分享,特此致敬! 資料型別和變數 資料型別 計算機能處理的遠不止數值,還可以處理文字、圖形、音訊、視訊、網頁等各種各樣的資料,不同的資料,需要定義不同的資料型別。 在Python中,能夠直接處理的資料型

Java複習筆記

程式控制語句         if條件語句         只要滿足條件就處理,不完全是順序結構,可以跳著執行。     (1)if&nbs

JavaScript複習筆記陣列及陣列API

一、陣列 分為兩種  關聯陣列:可以自己定義下標名稱的陣列           索引陣列:自動生成下標的陣列都是索引陣列 1、建立、賦值和取值 ①建立:4種:  

Excel中VBA程式設計學習筆記

  12、使用InputBox函式進行輸入 語法如下: InputBox(prompt [,title] [,default] [,xpos] [,ypos] [,helpfile,context]) 引數說明: prompt為提示內容,必選; title對

Javascript高階程式設計學習筆記—— JS中的資料型別1

 前一段時間由於事情比較多,所以筆記耽擱了一段時間,從這一篇開始我會盡快寫完這個系列。 文章中有什麼不足之處,還望各位大佬指出。 JS中的資料型別 上一篇中我寫了有關JS引入的Script標籤相關的東西。 那麼這一篇,我們可以正式進入JS的世界了,emmm 前面的東西應該比較基礎,大佬們不

Linux 網路程式設計 全解--------TCP次握手、資料傳輸、四次揮手、滑動視窗

寫在前面:今天中秋佳節,首先祝大家佳節快樂,身體健康,恭喜發財。吃也吃了,喝也喝了,玩也玩了,乾點正事吧。 說一下寫這個系列的目的,隨著對物聯網開發的深入,越來越覺得自己網路基礎知識的薄弱,雖然開發過程中不需要對網路基礎有很深入的瞭解照樣能進行,但有一些問題仍然是不知其因,

python 程式設計語言 筆記

第三週 分支與迴圈       3.1 程式基本結構 1. 程式流程圖 — 用規定的一系列圖形、流程線和文字說明演算法中的基本操作和控制流程。     流程圖的基本元素包括: (1)表示相應操作的框 (2)帶箭頭的流程線 (3)框內外必要的文字說明      

Java程式設計規範筆記

(四) OOP規約     避免通過一個類的物件引用訪問此類的靜態變數或靜態方法,無謂增加編譯器解析成本,直接用類名來訪問即可     所有的覆寫方法,必須加@Override註解     相同引數型別,相同業務含義,才可以使用Java的可變引數,避免使用Object(

描述網路程式設計Linux_C -> 筆記

套接字與套接字描述符 什麼是套接字?   套接字是一種通訊機制,是支援TCP/IP網路通訊的基本單元。在之前得知套接字可以實現跨越網路的程序通訊(或者說位於不同計算機的程序通訊),但它最初是伯克利UNIX的一部分,用於的是同一主機上程序的通訊。由於它最初是伯克

linux網路程式設計學習筆記

目錄 1. 獲取系統呼叫錯誤資訊:errno   strerror()     perror(); 他跟c語言中的fopen()有什麼區別呢?  他也呼叫的是這個open(); 2.常規檔案操作之建立、讀、寫

Linux網路程式設計學習筆記7---5種I/O模型及select輪詢

本文主要介紹5種I/O模型,select函式以及利用select實現C/S模型。 1、5種I/O模型 (1)阻塞I/O: 一直等到資料到來,才會將資料從核心中拷貝到使用者空間中。 (2)非阻塞I/O: 每過一段時

Python複習筆記函式進階

問題 1:在函式內部,針對引數使用 賦值語句,會不會影響呼叫函式時傳遞的 實參變數? —— 不會! 無論傳遞的引數是 可變 還是 不可變 只要 針對引數 使用 賦值語句,會在 函式內部 修改 區域性變數的引用,不會影響到  外部變數的引用 問題 2:如果傳遞的引數是 可

NetWork Science網路科學學習筆記隨機網路

本次筆記內容為Network Science Book的第三章節:隨機網路 相關的內容 這次的第二張圖片有部分公式在轉jpg的時候丟掉了減號,不知道是什麼原因,因為目前要加數學公式,要添截圖直接用Ma