socket 到底是個啥

来源:https://www.cnblogs.com/edisonfish/archive/2023/04/13/17314242.html
-Advertisement-
Play Games

哈嘍大家好,我是鹹魚 我相信大家在面試過程中或多或少都會被問到這樣一個問題:你能解釋一下什麼是 socket 嗎 我記得我當初的回答很是淺顯:socket 也叫套接字,用來負責不同主機程式之間的網路通信連接,socket 的表現方式由四元組(ip地址:埠)組成 那麼今天,鹹魚將跟大家打開 sock ...


 

哈嘍大家好,我是鹹魚

 

我相信大家在面試過程中或多或少都會被問到這樣一個問題:你能解釋一下什麼是 socket 嗎

 

我記得我當初的回答很是淺顯:socket 也叫套接字,用來負責不同主機程式之間的網路通信連接,socket 的表現方式由四元組(ip地址:埠)組成

 

那麼今天,鹹魚將跟大家打開 socket 的神秘大門,不但要搞清楚 socket 的概念,最好還能夠瞭解它的底層實現

我們首先查看一下 socket 的翻譯

 

我們看到,socket 可以翻譯成插座、插頭

 

那現在請想象這麼一個場景:給手機充電時,你將充電插頭插入電源插座裡面,是不是意味著插座與充電插頭連接起來了

 

在電腦世界中,socket 翻譯成套接字,通過 socket 我們可以與某台伺服器進行連接,而建立連接的過程,你可以腦補成將充電插頭插進插座的過程

 

 

 

 

 socket 使用場景

假設我們想要將數據從 A 電腦的某個進程傳送到 B 電腦的某個進程(比如鹹魚用微信發信息給冰冰)

 

那麼在與對方聊天的過程中,其實就是這兩臺電腦中的微信進程相互傳輸數據的過程

 

在這個過程中,兩臺電腦各自調用 socket 方法,然後會得到一個 fd 句柄(socket_fd),這個 fd 句柄就相當於 socket 的身份證號

 

得到 fd 句柄之後:

  1. 服務端執行 bind()、listen()、accept() 方法等待客戶端建立連接的請求

  2. 客戶端執行 connect() 方法向服務端發起連接

  3. 連接建立起來之後,兩端都可以執行 send()、recv() 方法來互相傳遞數據

 

PS:對於不同的傳輸層協議,上面這個過程是不一樣的,詳情可以查看我之前的文章《Python 網路編程

 

TCP 協議

 

UDP 協議

 

 socket 底層設計

我們知道了 socket 是用來實現網路傳輸功能的,它負責不同主機進程之間的網路通信連接

 

我將上面的問題改一下,把 ”socket 是什麼“ 改成 ”如果讓你來實現一個網路傳輸功能,你會怎麼設計“

 

網路傳輸功能,簡單點來講就是兩端伺服器之間進行網路通信並互相收發數據,收發數據也就是讀寫數據

 

首先我們會遇到第一個問題:茫茫互聯網中你怎麼能找到那台夢中情機

 

聰明的你肯定會想到——ip地址!我們用 ip 地址來定位電腦

 

找到了你的夢中情機之後,你會發現,一臺電腦上面這麼多進程,我怎麼才能找到與我通信的那個進程(比如說微信)

 

聰明的你很快就想到了用埠號(port)

 

可以這麼理解,ip 地址是用來定位街區的,而埠號 port 對應這個街區中的門牌號,通過 ip +port 的組合,你可以在茫茫互聯網中找到屬於你的夢中情機並且與之通信

 

所以你在設計網路傳輸功能初期,定義了一個數據結構 sock,sock 裡面包含了 ip 和 port 欄位(假設用 C 語言實現)

 

 

 在 Linux 中(以 CentOS 7舉例),在頭文件/usr/include/netinet/in.h可以看到負責套接字地址的 sock 結構體

 

sin_family 欄位為 AF_INET,sin_port 表示埠號,sin_addr 表示 IPv4 地址,是一個 struct in_addr類型的結構體

 

sin6_family 欄位為 AF_INET6,sin6_port 表示埠號,sin6_addr 表示 IPv6 地址,是一個 struct in6_addr 類型的結構體

 

解決了定位問題之後,我們知道在電腦網路中有很多協議,這些協議規定了電腦之間的通信方式

 

比如你是選用可靠的 TCP 協議去進行網路通信,還是相對不可靠的 UDP 協議

 

不同的網路協議還對應著不同的網路通信場景,如果你選擇了 TCP協議,你還得考慮例如滑動視窗、超時重傳這些場景

 

所以有了 ip 和 port 還不行,你還需要定義新的數據結構用來維護網路協議以及對應的網路場景

 

又因為不同的網路協議中有一些功能相似的方法(例如收發數據),於是你決定將不同協議中公共的部分提取出來,通過”繼承“的方式來實現功能復用

 

所以可以先定義一個名為 sock 的數據結構,然後定義”繼承“ sock 的各類 sock

 

PS:Linux 內核是用 C 語言實現的,在 C 語言中沒有繼承這個概念,你可以簡單將這個繼承理解成 xx_sock 基於 sock 進行了擴展,xx_sock 是 sock 的進階版

 

  • sock:最基礎的結構,用來維護任何網路協議都會用到的收發數據緩衝區(公用部分)

  • inet_sock:負責網路傳輸功能的 sock,在 sock 基礎上加了 TTL(網路生存時間)、ip 和 port 這些跟網路傳輸相關的欄位信息

  • inet_connection_sock:面向連接的 sock,在 inet_sock 基礎上添加了面向連接的協議里相關欄位,比如 accept 隊列,數據包分片大小,握手失敗,重試次數等;雖然我們現在提到面向連接的協議就是指 TCP,但從設計上 Linux 需要支持擴展其他面向連接的新協議,比如 SCTP 協議,所以說 tcp_sock 則是在這個基礎上實現的真正的 TCP 協議專用 sock 結構

 

上面例子中的這些 sock 都可以在系統上直接找到,以 CentOS 7 為例

 

 

現在你用代碼實現了這一堆數據結構——sock,不同的 sock 分別實現自己職責內的功能(負責面向連接的數據結構 inet_connection_sock、負責 UDP 協議的數據結構 udp_sock 等等)

 

但是你需要這些 sock 去跟硬體網卡交互才能實現網路傳輸的功能,既然需要跟硬體交互,那就說明需要比較高的操作系統許可權

 

同時考慮到性能和安全,這套數據結構不能放在用戶態,需要給它放到系統內核裡面

 

既然這套數據結構在內核里,處在用戶態的程式想要用這套數據結構來實現網路傳輸功能該怎麼辦呢?

 

除此之外,處在用戶態的程式並不關心也不知道你這套數據結構在底層內核是怎麼操作的,功能是怎麼實現的,它只關心結果

 

於是你想到了用介面調用的方式——你將一個個功能抽象一個個介面,以後別人只需要調用這些介面,就可以讓內核中這一大堆複雜的數據結構去實現指定功能

 

又因為在 Linux 中一切皆文件,你索性將這些 sock 封裝成文件,當用戶態的程式去調用你提供的介面時,需要先創建一個 sock 文件

 

這個新生成的 sock 文件有一個文件句柄 fd,用戶態的程式只需要拿著這個 fd 就可以對內核中的 sock 進行操作

 

 

 

上面有說到,你將不同的數據結構(inet_socktcp_sock 等等)抽象成一個個 API 介面,以後別人只需要調用這些 API 介面就可以驅動我們寫好的這一大堆複雜的數據結構去進行網路傳輸

 

下麵列出了一些常見的介面:

  • send

  • recv

  • bind

  • listen

  • connect

 

到這裡,整個網路傳輸功能就已經基本實現了。上面列舉出來的這些方法,其實就是 socket 提供出來的介面

 

到這裡,我們對 socket 有了一個更深地瞭解——socket 其實相當於一個介面層,它處在內核態和用戶態之間:

  • 向上用戶態

    • 為處在用戶態的程式提供 API 介面,方便用戶態程式實現網路傳輸功能

  • 向下內核態

    • 對網卡進行操作,負責網路傳輸工作

 

或者你也可以這麼理解,處在用戶態的程式通過 socket 提供的介面,將網路傳輸的這部分工作外包給了 Linux 內核

 

我們以 tcp 協議為例子來看下 python 中是如何操作 socket 的

 

在客戶端中,程式首先調用 socket 提供的 socket 方法創建一個 socket 文件來獲得 socket 句柄,然後調用 connect 方法,這時候內核會根據 socket_fd 找到對應的 sock 文件

 

再根據文件里的信息找到處在內核的 sock 結構,通過 sock 結構與服務端進行三次握手建立連接

 

連接建立好之後,客戶端調用 send 方法來進行數據傳輸,sock 中定義了一個發送緩衝區和接收緩衝區,其實就是一個鏈表,鏈表上面放著一個個等待發送或接收的數據

總結

我們再次回到那個問題——socket 是什麼?

 

sock(或 socket)是操作系統內核提供的一種數據結構,用於實現網路傳輸功能

 

基於不同的網路協議以及應用場景,衍生了各種類型的 sock

 

每個網路層協議都有相應的 sock 結構體來管理該層協議的連接狀態和數據傳輸。各類 sock 操作硬體網卡,就實現了網路傳輸的功能

 

為了將這些功能讓處在用戶態的應用程式使用,不但引入了 socket 層,還將各類功能的實現方式抽象成了 API 介面,供應用程式調用

 

同時將 sock 封裝成文件,應用程式就可以在用戶層通過文件句柄(socket fd)來操作內核中 sock 的網路傳輸功能

 

這個 socket fd 是一個 int 類型的數字,而 socket 中文翻譯叫做套接字,結合這個 socket fd,你是不是可以將其理解成:一套用於連接的數字

 

而 socket 分 Internet socket 和 UNIX Domain socket,兩者都可以用於不同主機進程間的通信和本機進程間的通信

 

只是前者採用的是基於 IP 協議的網路通信方式,而後者採用的是基於本地文件系統的通信方式

 

關於 UNIX Domain socket,可以通過 netstat -x 查看

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、前提 pId需要傳入用來確認第一級的父節點,而且pId可以為null。 樹實體類必須實現:TreeNode介面 MyTreeVo必須有這三個屬性:id、pId、children 可以根據不同需求,配置TreeNode和MyTreeVo中固定的屬性 二、代碼 定義TreeNode介面 public ...
  • 使用java 11添加的HttpClient新API發送Http(Https)請求 HTTP客戶端是在Java 11中添加的。它可以用於通過網路請求HTTP資源。它支持 HTTP / 1.1和HTTP / 2(同步和非同步編程模型),將請求和響應主體作為反應流處理,並遵循熟悉的構建器模式。 參考文章: ...
  • 引入相關的依賴 <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> ​ <!--引⼊springb ...
  • 我最近幾次被問到關於 ExecutionContext 和 SynchronizationContext 的各種問題,例如它們之間的區別是什麼,“傳播”它們意味著什麼,以及它們與 C# 和 Visual Basic 中新的 async/await 關鍵字的關係。我想我會嘗試在這裡解決其中的一些問題。 ...
  • 前言 HttpClient 是 .NET Framework、.NET Core 或 .NET 5以上版本中的一個類,用於向 Web API 發送 HTTP 請求並接收響應。它提供了一些簡單易用的方法,如 GET、POST、PUT 和 DELETE,可以很容易地構造和發送 HTTP 請求,並處理響應 ...
  • 1、下載redis源碼包,併進行解壓縮操作 https://download.redis.io/releases/ [root@Redis-Ubuntu-1804-p21:~]# wget https://download.redis.io/releases/redis-5.0.14.tar.gz ...
  • 原文: https://www.cnblogs.com/xiao987334176/p/9930517.html 一、介紹Prometheus Prometheus(普羅米修斯)是一套開源的監控&報警&時間序列資料庫的組合,起始是由SoundCloud公司開發的。隨著發展,越來越多公司和組織接受採用 ...
  • 筆記本開啟熱點代理 筆者因為最近在使用rk3588做開發,在編譯opencv的時候需要連網下載一些文件,但是很多時候都以失敗告終,筆者也嘗試過在rk3588上部署clash,但都太過複雜而且耗時,後來嘗試發現可以開啟筆記本的熱點,然後打開筆記本(win10)上的代理,連接的所有設備就都能上網了,今天 ...
一周排行
    -Advertisement-
    Play Games
  • 前言 本文介紹一款使用 C# 與 WPF 開發的音頻播放器,其界面簡潔大方,操作體驗流暢。該播放器支持多種音頻格式(如 MP4、WMA、OGG、FLAC 等),並具備標記、實時歌詞顯示等功能。 另外,還支持換膚及多語言(中英文)切換。核心音頻處理採用 FFmpeg 組件,獲得了廣泛認可,目前 Git ...
  • OAuth2.0授權驗證-gitee授權碼模式 本文主要介紹如何筆者自己是如何使用gitee提供的OAuth2.0協議完成授權驗證並登錄到自己的系統,完整模式如圖 1、創建應用 打開gitee個人中心->第三方應用->創建應用 創建應用後在我的應用界面,查看已創建應用的Client ID和Clien ...
  • 解決了這個問題:《winForm下,fastReport.net 從.net framework 升級到.net5遇到的錯誤“Operation is not supported on this platform.”》 本文內容轉載自:https://www.fcnsoft.com/Home/Sho ...
  • 國內文章 WPF 從裸 Win 32 的 WM_Pointer 消息獲取觸摸點繪製筆跡 https://www.cnblogs.com/lindexi/p/18390983 本文將告訴大家如何在 WPF 裡面,接收裸 Win 32 的 WM_Pointer 消息,從消息裡面獲取觸摸點信息,使用觸摸點 ...
  • 前言 給大家推薦一個專為新零售快消行業打造了一套高效的進銷存管理系統。 系統不僅具備強大的庫存管理功能,還集成了高性能的輕量級 POS 解決方案,確保頁面載入速度極快,提供良好的用戶體驗。 項目介紹 Dorisoy.POS 是一款基於 .NET 7 和 Angular 4 開發的新零售快消進銷存管理 ...
  • ABP CLI常用的代碼分享 一、確保環境配置正確 安裝.NET CLI: ABP CLI是基於.NET Core或.NET 5/6/7等更高版本構建的,因此首先需要在你的開發環境中安裝.NET CLI。這可以通過訪問Microsoft官網下載並安裝相應版本的.NET SDK來實現。 安裝ABP ...
  • 問題 問題是這樣的:第三方的webapi,需要先調用登陸介面獲取Cookie,訪問其它介面時攜帶Cookie信息。 但使用HttpClient類調用登陸介面,返回的Headers中沒有找到Cookie信息。 分析 首先,使用Postman測試該登陸介面,正常返回Cookie信息,說明是HttpCli ...
  • 國內文章 關於.NET在中國為什麼工資低的分析 https://www.cnblogs.com/thinkingmore/p/18406244 .NET在中國開發者的薪資偏低,主要因市場需求、技術棧選擇和企業文化等因素所致。歷史上,.NET曾因微軟的閉源策略發展受限,儘管後來推出了跨平臺的.NET ...
  • 在WPF開發應用中,動畫不僅可以引起用戶的註意與興趣,而且還使軟體更加便於使用。前面幾篇文章講解了畫筆(Brush),形狀(Shape),幾何圖形(Geometry),變換(Transform)等相關內容,今天繼續講解動畫相關內容和知識點,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 什麼是委托? 委托可以說是把一個方法代入另一個方法執行,相當於指向函數的指針;事件就相當於保存委托的數組; 1.實例化委托的方式: 方式1:通過new創建實例: public delegate void ShowDelegate(); 或者 public delegate string ShowDe ...