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
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...