socket編程基礎

上一篇 --- 網絡基礎概念(下)https://blog.csdn.net/Small_entreprene/article/details/147320155?fromshare=blogdetail&sharetype=blogdetail&sharerId=147320155&sharerefer=PC&sharesource=Small_entreprene&sharefrom=from_link

理解源IP地址和目的IP地址

在我們當前的認識當中,IP地址是用來標識主機的唯一性的,后面我們會詳細的對IP進行分類。

數據傳輸到主機并不是最終目的,因為數據是給人使用的。例如,聊天是人在聊天,下載是人在下載,瀏覽網頁是人在瀏覽。那么,人是如何看到聊天信息、執行下載任務以及瀏覽網頁信息的呢?答案是通過啟動的 QQ、迅雷、瀏覽器等軟件。而這些啟動的 QQ、迅雷、瀏覽器等都是進程。換句話說,進程是人在系統中的代表,只要把數據交給進程,人就相當于拿到了數據。

因此,數據傳輸到主機只是手段,而不是目的。真正的目的是將數據傳輸到主機內部,并交給主機內的目標進程。

我們上網,其實可以概括成兩種行為:

  1. 從遠端服務器,獲取數據(刷抖音,其實就是將抖音推送到手機端)
  2. 本地數據,上傳到遠端服務器?(登入,將賬號密碼推送到遠端;上傳文件到百度網盤)

不管我們的上網行為有多么豐富多樣,在技術角度也就只有兩種情況,一種上傳,一種下載!因為我們的數據是通過進程來做的,進程又是在內存當中的,上網的時候,所有的數據都是要經過網卡的,而網卡需要將數據給網絡。(是進程和網卡之間的關系,網絡和網卡的關系)

我們將上面兩者兩者之間的關系叫做IO!!!?說白了:馮諾依曼體系結構規定,網卡只能進行IO操作,就決定了我們的應用層軟件上,只能做獲取信息和發送信息的行為。

說明了網絡通信的本質就是兩個不同主機的進程在進行數據交互,更本質就是進程間通信!

進程間通信的本質就是要看到同一份資源,那么兩個不同主機的進程要看到的同一份資源又是誰呢?就是網絡!!!?(今天只是從在同一臺主機內進行進程間通信換成了在不同的兩臺主機間進行進程間通信而已)

我們現在知道,數據傳輸到主機只是手段,而不是目的。真正的目的是將數據傳輸到主機內部,并交給主機內的目標進程。然而,在系統中,同時會存在非常多的進程。因為收到的數據是要分配給一個或多個進程的,哪些數據對應哪一個進程,那么當數據到達目標主機之后,如何將數據轉發給目標進程呢?這需要在網絡的背景下,通過某種方式在系統中標識主機的唯一性,從而確保數據能夠準確地被轉發到目標進程。

?我們主機會收到來自遠端主機發送來的各種數據,這些數據需要按照對應不同的數據分發到對應的進程當中,所以我們就必須要在系統層面上有一種辦法來標識主機的唯一性,為了能夠實現主機唯一性的標識,我們在網絡的范疇當中,我們就引入了新的概念:端口號!

認識端口號

端口號(Port)是傳輸層協議的內容。

  • 端口號是一個2字節16位的整數。

  • 端口號用來標識一個進程,告訴操作系統,當前的這個數據要交給哪一個進程來處理。(也就是說,未來寫的網絡服務,比如說QQ,這個網絡服務要進行啟動的時候,需要通過操作系統提供的一些系統調用來讓這個進行和對應的端口號(在傳輸層提取報文中的目的端口號)產生對應的關聯)

  • IP地址 + 端口號能夠標識網絡上的某一臺主機的某一個進程。

  • 一個端口號只能被一個進程占用。(就是端口號可以用來標識系統中唯一的一個網絡進程!!!)(其實反過來,一個進程是可以和多個端口號進行綁定的,因為我們要的是從端口號查進程的方向是唯一的)

網絡通信的本質是全網范圍內唯二的兩個進程在進行進程間通信!!!我們用對方的IP和Port標識對方的唯一性。我們將IP+Port稱為Socket(套接字)

不過,端口號端口號可以用來標識系統中唯一的一個網絡進程,但是我們學習過,pid也是進程的唯一標識,那為什么不直接用進程pid呢?

不是所有的進程都需要進行網絡通信,不過我們從技術角度上來說,使用pid不使用端口號,這是可行的,但是pid是一個系統的概念,如果未來pid這個概念變化了,伴隨著網絡就需要變,這就是耦合性差,使用端口號就可以進行解耦!!!


端口號的范圍劃分是【0,65535】,因為是一個兩字節(16比特位)的整數

  • 0 - 1023:知名端口號,HTTP、FTP、SSH 等這些廣為使用的應用層協議,它們的端口號都是固定的。
  • 1024 - 65535:操作系統動態分配的端口號。客戶端程序的端口號,就是由操作系統從這個范圍分配的。

傳輸層協議(TCP 和 UDP)的數據段中有兩個端口號,分別叫做源端口號和目的端口號,就是在描述“數據是哪臺主機的哪一個進程發的,要發給哪臺主機上的哪一個進程”。


理解socket

綜上,IP 地址用來標識互聯網中唯一的一臺主機,port 用來標識該主機上唯一的一個網絡進程。

  • IP + Port 就能表示互聯網中唯一的一個進程。

  • 所以,通信的時候,本質是兩個互聯網進程代表人來進行通信,{srcIp,srcPort,dstIp,dstPort}這樣的 4 元組就能標識互聯網中唯二的兩個進程。

  • 所以,網絡通信的本質,也是進程間通信。

  • 我們把 ip + port 叫做套接字 socket。


傳輸層的典型代表

如果我們了解了系統,也了解了網絡協議棧,我們就會清楚,傳輸層是屬于內核的。那么我們要通過網絡協議棧進行通信,必定調用的是傳輸層提供的系統調用,來進行網絡通信。

傳輸層有兩個重要協議:TCB和UDP。?

認識 TCP 協議

此處我們先對 TCP(Transmission Control Protocol 傳輸控制協議)有一個直觀的認識;后面我們再詳細討論 TCP 的一些細節問題。

  • 傳輸層協議

  • 有連接:在數據傳輸之前,需要先建立連接。(打電話,你喂我喂的過程就是建立連接的過程)

  • 可靠傳輸:保證數據的完整性和順序性,通過確認和重傳機制確保數據可靠傳輸。

  • 面向字節流:數據以字節流的形式傳輸,不保留消息邊界。(自來水,怎么接,接多少,都是自己自主決定的;文件打開也叫文件流,字節流和文件流沒有區別,都是流式的;學習完自定義協議后我們就能理解了)

認識 UDP 協議

此處我們也是對 UDP(User Datagram Protocol 用戶數據報協議)有一個直觀的認識;后面再詳細討論。

  • 傳輸層協議

  • 無連接:不需要建立連接,直接發送數據。(對講機)

  • 不可靠傳輸:不保證數據的完整性和順序性,數據可能丟失或亂序到達。

  • 面向數據報:數據以數據報的形式傳輸,保留消息邊界。(發快遞,發幾個就只能幾個)

TCP是可靠的,丟包了可以再發,但是UDP不可靠,那為什么還要保留UDP呢?(屬于同層協議,但是還保留一個不可靠的???)

我們要注意,這里的可靠和不可靠不可以將其視為貶義詞,而是一種中性詞,是一種特點。TCP保證可靠性,意味著他一定要做更多的工作,也就是意味著TCP協議會更加復雜一些,復雜帶來的就是占有資源會比較多。UDP協議就會很簡單,簡單的話就是代表開發周期短,可維護性好。

因為我們暫時還沒有深入了解 TCP 和 UDP 協議,此處只做了解即可。


網絡字節序

我們以前學過,計算機在存儲數據的時候,是有大端和小端的,大小端是按照字節為單位的。

大端(Big-Endian)

定義:大端字節序是指高位字節存放在內存的低地址端,低位字節存放在內存的高地址端。

?假設有一個32位的整數 0x12345678,在大端字節序下,它在內存中的存儲順序如下:

內存地址: 0x00  0x01  0x02  0x03
存儲內容: 12    34    56    78
  • 0x12 存儲在最低地址 0x00

  • 0x78 存儲在最高地址 0x03

小端(Little-Endian)(小-小-小)

定義:小端字節序是指低位字節存放在內存的低地址端,高位字節存放在內存的高地址端。

假設有一個32位的整數 0x12345678,在小端字節序下,它在內存中的存儲順序如下:

內存地址: 0x00  0x01  0x02  0x03
存儲內容: 78    56    34    12
  • 0x78?(低權值位:就是16的幾次方)存儲在最低地址 0x00

  • 0x12 存儲在最高地址 0x03

#include <stdio.h>// 函數:將整數從當前字節序轉換為網絡字節序(大端)
unsigned int htonl(unsigned int hostlong) {unsigned char *bytes = (unsigned char*)&hostlong;return ((unsigned int)(bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3]);
}int main() {unsigned int x = 1;if (*((char *)&x) == 0) {printf("大端(Big-Endian)\n");} else {printf("小端(Little-Endian)\n");printf("轉換前的值:%u\n", x);// 調用 htonl 函數將整數轉換為大端字節序x = htonl(x);printf("轉換后(大端)的值:%u\n", x);}return 0;
}

如果今天主機A是小端存儲,主機B是大端存儲,兩臺主機間要進行網絡通信,A將數據發送給B的話,主機B就解釋反了。所以在網絡當中,兩臺主機,如果主機間的存儲序列不同的話,經過網絡通信,會導致對方將接收到的數據解釋錯了!

所以在網絡中就有規定:凡是將數據發送到網絡當中的話,一定是要按照大端的形式發送!

發送主機通常將發送緩沖區中的數據按內存地址從低到高的順序發出。接收主機把從網絡上接到的字節依次保存在接收緩沖區中,也是按內存地址從低到高的順序保存。因此,網絡數據流的地址應這樣規定:先發出的數據是低地址,后發出的數據是高地址。TCP/IP 協議規定,網絡數據流應采用大端字節序,即低地址高字節。不管這臺主機是大端機還是小端機,都會按照這個 TCP/IP 規定的網絡字節序來發送/接收數據。如果當前發送主機是小端,就需要先將數據轉成大端;否則就忽略,直接發送即可。

為使網絡程序具有可移植性,使同樣的 C 代碼在大端和小端計算機上編譯后都能正常運行,可以調用以下庫函數做網絡字節序和主機字節序的轉換。

  • 這些函數名很好記,h 表示 host,n 表示 network,l 表示 32 位長整數,s 表示 16 位短整數。

  • 例如,htonl 表示將 32 位的長整數從主機字節序轉換為網絡字節序,例如將 IP 地址轉換后準備發送。

  • 如果主機是小端字節序,這些函數將參數做相應的大小端轉換然后返回。

  • 如果主機是大端字節序,這些函數不做轉換,將參數原封不動地返回。

注意:所有發送到網絡上的數據,都必須是大端的!

socket編程接口

socket常見API

// 創建 socket 文件描述符 (TCP/UDP, 客戶端 + 服務器)
int socket(int domain, int type, int protocol);// 綁定端口號 (TCP/UDP, 服務器)
int bind(int socket, const struct sockaddr *address, socklen_t address_len);// 開始監聽 socket (TCP, 服務器)
int listen(int socket, int backlog);// 接收請求 (TCP, 服務器)
int accept(int socket, struct sockaddr* address, socklen_t* address_len);// 建立連接 (TCP, 客戶端)
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

這些API的詳細細節我們會在后續寫代碼的時候進行說明。

我們發現大部分的接口參數中都有const struct sockaddr*的結構體指針(其他暫時不關心)

下面,我們來聊一聊這個sockaddr這個結構體。

sockaddr結構體

我們現在清楚,網絡通信的本質其實是進程間通信,我們之前學習的system V這個標準屬于本地之間進行進程間通信,我們后面還會見到的POSIX標準,這個是主要用于網絡通信的,網絡通信也是進程通信,也能進行本地通信的,也就是為什么我們之前說System V版本的進程間通信被淘汰了,因為POSIX這套標準,我們直接就可以進行了,還順帶了網絡通信。

socket套接字會有許多不同的種類來滿足各種各樣的不同的應用場景--網絡socket/本地socket(unix域間通信)/原始socket,原始socket我們不需要考慮,未來我們只需要學懂網絡socket,本地socket我們自然而然也就清楚了。也是正因為有不同的場景的socket,我們socket未來的接口,也是會有不同的通信接口規范(網絡的一套,本地的一套......)但是socket的設計者并不想這么干,只想要提供一套通信接口!!!(這一套既可以做網絡通信,也可以做本地通信)

所以就需要對接口進行設計,為了能夠支持設計出來的接口可以進行不同種類的通信,就設計了一個結構體---sockaddr結構體!

  • 通用性struct sockaddr 提供了一個通用的接口,適用于各種網絡協議。

  • 專用性struct sockaddr_instruct sockaddr_un 分別針對IPv4網絡通信和本地通信進行了優化,提供了必要的信息和靈活性。

在網絡編程中,sockaddr 結構體及其相關的結構體如 sockaddr_insockaddr_un 經常需要進行強制類型轉換。這是因為 sockaddr 是一個通用的地址結構體,設計用來支持多種不同的網絡協議和地址類型。而 sockaddr_insockaddr_un 是針對特定協議(如IPv4、IPv6和UNIX域套接字)的具體實現。

當你需要將 sockaddr_insockaddr_un 結構體傳遞給需要 sockaddr 類型參數的函數時,通常需要進行強制類型轉換。例如,在調用 bind()connect() 函數時,你需要將 sockaddr_in 結構體的地址轉換為 sockaddr 類型的指針。

這樣做的原因是因為 sockaddr 結構體定義了一個通用的接口,它包含了一個地址族字段(sa_family),用于指示地址的具體類型。sockaddr_insockaddr_un 結構體都以這個地址族字段開始,但它們包含的地址信息不同。通過將它們轉換為 sockaddr 類型,你可以確保函數能夠正確識別和處理不同類型的地址。

至于為什么不將參數設置為 void*,原因在于 void* 類型雖然可以指向任何類型的數據,但它不提供足夠的信息來處理不同協議的地址。使用 sockaddr 類型及其派生的結構體可以提供必要的語義信息,使函數能夠根據地址類型字段來正確處理地址數據。此外,原始套接字API是在1983年發布的,早于1989年的ANSI C標準,其前身——K&R C——根本沒有 void *,所以您無論如何都必須將其轉換為某個東西。

其實本質就是繼承和多態:(C語言實現的)



本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/80669.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/80669.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/80669.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

CSS 解決手機瀏覽器默認行為(點擊出現藍色背景)

最近寫了一個 Web 應用&#xff0c;可以兼容手機端和PC端&#xff0c;在PC端調試的時候沒有發現這個問題&#xff0c;但是在手機上或者PC瀏覽器改成手機模式進行調試的時候就會出現下面這個場景&#xff1a; 這是兩個 div&#xff0c;點擊的時候&#xff0c;會出現一個藍色的背…

多模態大語言模型arxiv論文略讀(三十八)

Tables as Texts or Images: Evaluating the Table Reasoning Ability of LLMs and MLLMs ?? 論文標題&#xff1a;Tables as Texts or Images: Evaluating the Table Reasoning Ability of LLMs and MLLMs ?? 論文作者&#xff1a;Naihao Deng, Zhenjie Sun, Ruiqi He, A…

聊聊Spring AI Alibaba的YuQueDocumentReader

序 本文主要研究一下Spring AI Alibaba的YuQueDocumentReader YuQueDocumentReader community/document-readers/spring-ai-alibaba-starter-document-reader-yuque/src/main/java/com/alibaba/cloud/ai/reader/yuque/YuQueDocumentReader.java public class YuQueDocument…

OCR定制識別:解鎖文字識別的無限可能

OCR 定制識別是什么&#xff1f; OCR&#xff0c;即光學字符識別&#xff08;Optical Character Recognition&#xff09; &#xff0c;它就像是一個神奇的 “文字翻譯器”&#xff0c;能把圖片里的文字轉化成計算機可編輯的文本。比如&#xff0c;你掃描一份紙質文檔成圖片&am…

麒麟系統(基于Ubuntu)上使用Qt編譯時遇到“type_traits文件未找到”的錯誤

在麒麟系統&#xff08;基于Ubuntu&#xff09;上使用Qt編譯時遇到“type_traits文件未找到”的錯誤&#xff0c;通常是由于C標準庫頭文件缺失或項目配置問題導致的。以下是逐步解決方案&#xff1a; 1. 安裝C標準庫和開發工具 確保系統已安裝完整的開發工具鏈和標準庫&#…

服務器上安裝node

1.安裝 下載安裝包 https://nodejs.org/en/download 解壓安裝包 將安裝包上傳到/opt/software目錄下 cd /opt/software tar -xzvf node-v16.14.2-linux-x64.tar.gz 將解壓的文件夾移動到安裝目錄(/opt/nodejs)下 mv /opt/software/node-v16.14.2-linux-x64 /opt/nodejs …

Vue3 + Vite + TS,使用 ExcelJS導出excel文檔,生成水印,添加背景水印,dom轉圖片,插入圖片,全部代碼

Vue3 Vite TS,使用 ExcelJS導出excel文檔&#xff0c;生成水印&#xff0c;添加背景水印&#xff0c;dom轉圖片&#xff0c;插入圖片&#xff0c;全部代碼 ExcelJS生成文檔并導出導出表頭其他函數 生成水印設置文檔的背景水印dom 轉圖片插入圖片全部代碼 ExcelJS 讀取&#…

devops自動化容器化部署

devops 一、簡單案例體驗gitlabrunner部署靜態文件二、devops企業級部署方案1、流程圖2、依賴工具3、流程圖4、主機規劃5、安裝工具軟件1、安裝git2、安裝gitlab3、安裝jenkins-server4、安裝harbor5、安裝web-server&#xff0c;也就是部署服務的機子&#xff0c;需要安裝dock…

高級 SQL 技巧:提升數據處理能力的實用方法

在數據驅動的時代,SQL 作為操作和管理關系型數據庫的標準語言,其重要性不言而喻。基礎的 SQL 語句能滿足日常的數據查詢需求,但在處理復雜業務邏輯、進行數據分析和優化數據庫性能時,就需要掌握一些高級 SQL 技巧。這些技巧不僅能提高查詢效率,還能實現復雜的數據處理任務…

21.disql命令登錄達夢數據庫,查詢并操作數據庫

目錄 1.連接達夢數據庫 1.1 windows或linux系統 步驟&#xff08;1&#xff09;&#xff1a;打開終端窗口 步驟&#xff08;2&#xff09;&#xff1a;進入夢數據庫安裝目錄下的 bin 文件夾 步驟&#xff08;3&#xff09;&#xff1a;用disql命令進行登錄 1.2 docker部署…

N8N MACOS本地部署流程避坑指南

最近n8n很火&#xff0c;就想在本地部署一個&#xff0c;嘗嘗鮮&#xff0c;看說明n8n是開源軟件&#xff0c;可以在本地部署&#xff0c;于是就嘗試部署了下&#xff0c;大概用了1個多小時&#xff0c;把相關的過程記錄一下&#xff1a; 1、基礎軟件包 abcXu-MacBook-m2-Air…

qt之開發大恒usb3.0相機一

1.在大恒相機給的sample里沒有看見qt開發的demo. 第一步先運行c sdk中中的demo&#xff0c;看了下代碼&#xff0c;大恒使用的UI框架是MFC.然后 vs2022編譯。運行結果 第一步&#xff0c;先用qt進行坐下頁面布局&#xff0c;如下圖&#xff08;保存圖片的地方做了些更改&#…

leetcode-枚舉

枚舉 3200. 三角形的最大高度 題目 給你兩個整數 red 和 blue&#xff0c;分別表示紅色球和藍色球的數量。你需要使用這些球來組成一個三角形&#xff0c;滿足第 1 行有 1 個球&#xff0c;第 2 行有 2 個球&#xff0c;第 3 行有 3 個球&#xff0c;依此類推。 每一行的球必…

DeepSeek智能時空數據分析(三):專業級地理數據可視化賞析-《杭州市國土空間總體規劃(2021-2035年)》

序言&#xff1a;時空數據分析很有用&#xff0c;但是GIS/時空數據庫技術門檻太高 時空數據分析在優化業務運營中至關重要&#xff0c;然而&#xff0c;三大挑戰仍制約其發展&#xff1a;技術門檻高&#xff0c;需融合GIS理論、SQL開發與時空數據庫等多領域知識&#xff1b;空…

如何用WordPress AI插件自動生成SEO文章,提升網站流量?

1. 為什么你需要一個WordPress AI文章生成插件&#xff1f; 每天手動寫文章太耗時&#xff1f;SEO優化總是不達標&#xff1f;WordPress AI插件能幫你24小時自動生成原創內容&#xff0c;從關鍵詞挖掘到智能排版&#xff0c;全程無需人工干預。 痛點&#xff1a;手動寫作效率低…

鼠標指定范圍內隨機點擊

鼠標指定范圍內隨機點擊 點贊神器 將鼠標移動到相應位置后按F5 F6鍵&#xff0c;設置點擊范圍&#xff0c; F8開始&#xff0c;ESC中止。 有些直播有點贊限制&#xff0c;例如某音&#xff0c;每小時限制3千次&#xff0c;可以設置1200毫秒&#xff0c;3000次。 軟件截圖&#…

數據庫設置外鍵的作用

數據庫外鍵&#xff08;Foreign Key&#xff09;是關系型數據庫中用于建立表與表之間關聯關系的重要約束&#xff0c;其核心作用是確保數據的一致性、完整性和關聯性。以下是外鍵的主要作用及相關說明&#xff1a; 1. 建立表間關聯關系 外鍵通過引用另一張表的主鍵&#xff0…

發幣流程是什么,需要多少成本?

這是一個專注于Web3相關開發的賬號&#xff0c;具體會講解步驟以及開發方案 偶爾會有科普&#xff0c;有興趣的可以點右上角關注一下 發幣&#xff08;發行數字貨幣&#xff09;的流程通常涉及技術實現、法律合規、經濟模型設計等多個環節&#xff0c;以下是關鍵步驟的簡要說明…

測試常用的Linux系統指令詳解

為什么測試工程師需要掌握Linux命令&#xff1f; 在現代軟件測試領域&#xff0c;約75%的服務端應用運行在Linux環境中&#xff0c;能夠熟練使用Linux命令的測試工程師&#xff0c;其工作效率比僅依賴GUI工具的測試人員高出40%以上。本文將系統介紹測試工作中最實用的Linux命令…

Java學習手冊:Web 安全基礎

一、常見 Web 安全威脅 在 Web 開發中&#xff0c;安全問題至關重要。以下是一些常見的 Web 安全威脅&#xff1a; 1. SQL 注入 SQL 注入是一種攻擊方式&#xff0c;攻擊者通過在輸入字段中插入惡意的 SQL 代碼&#xff0c;從而操縱數據庫。例如&#xff0c;假設有一個登錄表…