TCP 全連接隊列 內核層理解socket

TCP 全連接隊列

理解 listen 的第二個參數

int listen(int sockfd, int backlog);

backlog 參數表示 全連接隊列(accept 隊列)的最大長度

那什么是全連接隊列呢?

三次握手 & accept() 處理流程

  1. 客戶端發送 SYN,服務器收到并放入半連接隊列
  2. 服務器回 SYN+ACK,客戶端收到后發送 ACK
  3. 服務器收到 ACK,握手完成,連接進入全連接隊列等待 accept() 處理。
  4. 服務器調用 accept() 取出連接,建立 TCP 連接。

也就是說我們訪問服務器會由內核自動進行3次握手,完成后會連入全連接隊列中,服務端再調用accept(),從隊列中獲取連接進行處理。而listen的第二個參數就是全連接隊列的最大連接長度,如果服務器來不及調用accept()處理連接,連接會堆積在全連接隊列。超過最大連接長度,再進行連接就會三次握手失敗。

所以全連接隊列本質就是一種生產消費者模型backlog 不能太長也不能太短。

1.太短,可能丟失大量連接(客戶端需要重試,增加網絡負擔)。

2.太長,一方面會讓用戶等待過長的時間,另一方面會占用大量內存

Linux 內核?TCP socket

先看一下從進程的文件描述符到 TCP socket的整體結構

1. 任務(task_struct)到文件描述符表

  • 進程的 task_struct 結構體包含 files_struct,用于管理進程的文件表。
  • files_struct 中有一個 fd_array[](文件描述符數組),存儲著所有打開的文件(struct file 指針)。

2. 文件結構(struct file)

  • struct file 代表進程打開的一個文件,可能是普通文件、設備文件或者套接字(socket)。
  • 其中 private_data 用于存儲 socket 相關信息。
  • 當文件描述符指向 socket 時,它的 private_data 指向 struct socket 結構體。

3. socket 結構(struct socket)

  • struct socket 代表一個高層的 socket 抽象,內部包含:
    • struct file *file:指向與 socket 關聯的文件結構。
    • struct sock *sk:指向具體的 sock 結構體,代表底層協議相關的數據結構。
    • struct socket {socket_state state;       // socket 當前狀態,如 SS_CONNECTEDshort type;               // socket 類型,如 SOCK_STREAM(TCP)或 SOCK_DGRAM(UDP)unsigned long flags;      // socket 標志struct file *file;        // 關聯的 struct file 結構體struct sock *sk;          // 關聯的 struct sock 結構體(底層協議數據)const struct proto_ops *ops; // 指向 socket 操作函數
      };
      


4. sock 結構(struct sock)

  • struct sock 是底層 socket 內部的核心結構,存儲協議無關的信息。
  • struct sock 可以指向不同的協議(如 TCP、UDP、RAW)擴展成更具體的協議結構。

5. TCP Socket結構

  • 從高層到底層,TCP socket 主要涉及以下結構:

    • struct sock(通用 socket 結構)
    • struct inet_sock(IP 層 socket)
    • struct inet_connection_sock(面向連接的 socket)
    • struct tcp_sock(TCP 連接的具體實現)

1 struct sock(核心 socket 結構)

struct sock 是 Linux 內核中最基礎的 socket 結構,幾乎所有的協議(TCP、UDP、RAW)都會用到它。它存儲了 socket 相關的通用數據,例如:

struct sock {struct socket *sk_socket;  // 關聯的 socket 結構struct sock_common __sk_common; // 存放通用的網絡信息,如 IP、端口等atomic_t sk_refcnt;  // 引用計數struct sk_buff_head sk_receive_queue; // 接收緩沖隊列struct sk_buff_head sk_write_queue; // 發送緩沖隊列struct proto *sk_prot; // 指向協議處理函數(TCP、UDP等)
};

關鍵字段解析

  • sk_socket:指向 struct socket,用于在高層 socket 結構和底層 sock 結構之間建立關聯。
  • sk_receive_queue:存儲接收到但尚未被應用層讀取的數據包。
  • sk_write_queue:存儲尚未發送的數據包。
  • sk_prot指向協議處理函數,例如 TCP 或 UDP 的操作集合。struct socket中type是TCP就調用TCP的函數

作用

  • struct sock 作為所有協議(TCP/UDP)的基類,包含通用 socket 操作。
  • struct socket 通過 sk 字段關聯。
  • sk_prot 用于決定 socket 的具體協議操作,例如 tcp_prot(TCP 協議處理)。

2 struct inet_sock(IP 層 socket)

struct inet_sock 繼承自 struct sock,用于 IPv4 相關的 socket 操作。這個結構體增加了 IP 層的字段,例如源 IP、目的 IP、端口號等。

struct inet_sock {struct sock sk; // 繼承 struct sock__be32 inet_saddr; // 本地 IP 地址__be32 inet_rcv_saddr; // 綁定的本地 IP 地址(可能是 0.0.0.0)__be16 inet_sport; // 本地端口(主機字節序)__be16 inet_dport; // 遠程端口(主機字節序)__be32 inet_daddr; // 遠程 IP 地址struct ip_options *inet_opt; // 額外的 IP 選項(如 IP 選路)
};

關鍵字段解析

  • inet_saddr:本地 IP 地址。
  • inet_daddr:目標 IP 地址。
  • inet_sport:本地端口號。
  • inet_dport:遠程端口號。
  • inet_opt:可選的 IP 頭部選項。

作用

  • 增加 IP 層信息,使得 struct sock 能夠支持 IPv4 協議。
  • 存儲 socket 關聯的 IP 地址和端口號。
  • 供 TCP 和 UDP 繼承,并擴展額外功能。

3 struct inet_connection_sock(面向連接的 socket)

struct inet_connection_sock 繼承 struct inet_sock,用于 面向連接的協議(如 TCP)。它增加了 TCP 連接管理所需的數據,例如超時控制、連接狀態等。

struct inet_connection_sock {struct inet_sock icsk_inet; // 繼承 struct inet_sockstruct request_sock_queue icsk_accept_queue; // 半連接隊列struct list_head icsk_ack_list; // TCP Fast Open 相關struct timer_list icsk_retransmit_timer; // 重傳定時器struct request_sock *icsk_accept_head; // 指向全連接隊列的頭部
};

關鍵字段解析

字段作用
icsk_inet繼承 struct inet_sock,包含 IP 地址、端口信息
icsk_accept_queue半連接隊列,存放 SYN-RECEIVED 連接
icsk_ack_listTCP Fast Open 機制,加快 SYN 建立連接
icsk_retransmit_timerTCP 重傳定時器,用于 SYN+ACK 超時重傳
icsk_accept_head全連接隊列,存放 ESTABLISHED 連接,等待 accept()

作用

  • 維護 TCP 連接狀態(如 SYN、ESTABLISHED)。
  • 控制 TCP 連接的超時機制。
  • 監聽 socket 維護 accept() 所需的連接隊列。

4 struct tcp_sock(TCP 連接的實現)

struct tcp_sock 繼承 struct inet_connection_sock,專門用于 TCP 連接,存儲 TCP 專有的數據,例如 TCP 窗口大小、擁塞控制狀態等。

struct tcp_sock {struct inet_connection_sock inet_conn; // 繼承 struct inet_connection_socku32 snd_nxt; // 發送窗口的下一個序列號u32 rcv_nxt; // 接收窗口的下一個序列號u32 snd_una; // 發送窗口的最早未確認序列號u32 snd_wnd; // 發送窗口大小u32 rcv_wnd; // 接收窗口大小struct sk_buff *retransmit_skb_hint; // 指向要重傳的數據struct tcp_congestion_ops *cong_control; // 擁塞控制算法
};

關鍵字段解析

  • snd_nxt:下一個要發送的 TCP 序列號。
  • rcv_nxt:期望接收的下一個 TCP 序列號。
  • snd_una:最早未被確認的 TCP 序列號(累計確認)。
  • snd_wnd / rcv_wnd:TCP 窗口大小,決定流量控制。
  • retransmit_skb_hint:指向當前需要重傳的 TCP 報文。
  • cong_control:TCP 擁塞控制算法(如 Reno、CUBIC)。

作用

  • 維護 TCP 發送、接收窗口,實現流量控制。
  • 管理 TCP 擁塞控制機制,影響 TCP 傳輸速率。
  • 控制 TCP 數據包重傳,保證可靠傳輸。

結構體關系總結

  • struct sock(核心 socket 結構,通用于所有協議)。
  • struct inet_sock(增加 IP 地址、端口等)。
  • struct inet_connection_sock(增加 TCP 連接管理功能)。
  • struct tcp_sock(TCP 特有字段,如序列號、窗口大小等)

UDP Socket 結構層次

UDP(User Datagram Protocol)是無連接的傳輸協議,與 TCP 相比,它沒有連接管理、流量控制和可靠性機制,因此在 Linux 內核中的實現相對簡單。UDP 的 socket 仍然依賴于 struct sock,但不需要像 TCP 那樣擴展 struct inet_connection_sockstruct tcp_sock

UDP 在內核中的數據結構層級如下:

  1. struct sock(核心 socket 結構)
  2. struct inet_sock(IP 層 socket,增加源/目標 IP、端口等信息)
  3. struct udp_sock(UDP 特有的數據結構)

TCP 需要 struct inet_connection_sockstruct tcp_sock 來處理連接管理,而 UDP 直接使用 struct inet_sock,并在 struct udp_sock 中擴展少量的 UDP 相關字段。

listen()監聽TCP連接創建tcp socket的內核過程

當服務器使用 listen() 監聽 TCP 連接,并在 accept() 中接受新的連接時,Linux 內核會經歷以下幾個關鍵步驟:

  1. listen() 監聽 TCP 端口
  2. 三次握手期間,創建 struct sock 并存入半連接隊列,三次握手完成后連入全連接隊列中
  3. accept() 取出 struct sock,創建 struct socket
  4. 創建 struct file 并存入 struct files_struct->fd_array[]

1. listen():初始化監聽 socket 并設置全連接隊列

Linux 內核執行 tcp_listen_start(),配置 struct sock 進入監聽狀態。

listen() 作用

  • 設置 struct sock->sk_state = TCP_LISTEN
  • 初始化 icsk_accept_queue(半連接隊列)和 icsk_accept_head(全連接隊列)
  • 設置 backlog,決定全連接隊列最大容量

2. 客戶端三次握手,創建 struct sock 并進入全連接隊列

當客戶端發起 TCP 連接時:

  1. 客戶端發送 SYN

    • 服務器 TCP_LISTEN 狀態,調用 tcp_v4_rcv() 處理 SYN
    • 服務器分配 struct request_sock,存入 半連接隊列 (icsk_accept_queue)
  2. 服務器回復 SYN+ACK

    • 服務器仍然在 TCP_LISTEN 狀態。
    • SYN+ACK 發送后,客戶端需要回復 ACK
  3. 客戶端發送 ACK,服務器進入 ESTABLISHED

    • tcp_v4_rcv() 處理 ACK
    • 服務器 創建 struct sock,從半連接隊列轉移到 全連接隊列 (icsk_accept_head),等待 accept() 處理。

3. accept() 處理全連接隊列,創建 struct socket

當服務器調用:accept()

  • accept() 取出全連接隊列 icsk_accept_head 里的 struct sock
  • 創建 新的 struct socket 并關聯 struct sock
  • accept() 創建 struct socket 后,還需要 struct file 結構,以便進程可以通過文件描述符訪問它創建 struct file,并存入 fd_array[](文件描述符表)。

1.struct sock在三次握手過程中創建并進入半連接隊列

2.三次握手完成后,struct sock連接到全連接隊列中,accpet()調用后創建對應的struct socket并用struct sock*sk關聯,

3.再創建struct file用private_data連接struct socket,struct socket中struct file*file再反指向file。

4.把file的指針填入struct files_struct 中fd_array[]文件描述符表數組分配文件描述符fd。

5.再由accept()返回創建的fd

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

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

相關文章

程序化廣告行業(18/89):交易模式與關鍵概念解析

程序化廣告行業(18/89):交易模式與關鍵概念解析 大家好呀!一直以來,我都在深入研究程序化廣告這個充滿挑戰與機遇的領域,在學習過程中收獲了很多,也迫不及待想和大家分享。寫這篇博客&#xff…

在離線情況下如何使用 Python 翻譯文本

以下是在離線環境下使用Python進行文本翻譯的兩種主流方案,包含本地模型部署和輕量級詞典兩種方法: 方案一:使用本地神經網絡翻譯模型(推薦) # 安裝依賴(需提前下載) # pip install argos-tra…

OpenEuler-22.03-LTS上利用Ansible輕松部署MySQL 5.7

一、需求 使用ansible自動化部署mysql二進制部署mysql部署mysql并創建JDBC用戶 二、環境信息 本文涉及的代碼,配置文件地址: 鏈接:百度網盤 請輸入提取碼 提取碼:1g6y 軟件名稱版本備注Ansible2.9.27All modules — Ansible Doc…

基于javaweb的SpringBoot農資商城購物商城系統設計與實現(源碼+文檔+部署講解)

技術范圍:SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬蟲、數據可視化、小程序、安卓app、大數據、物聯網、機器學習等設計與開發。 主要內容:免費功能設計、開題報告、任務書、中期檢查PPT、系統功能實現、代碼編寫、論文編寫和輔導、論…

angular打地鼠

說明:我計劃用angular做一款打地鼠的小游戲, 打地鼠游戲實現文檔 🎮 游戲邏輯 ?游戲場景 采用 3x3 網格布局的 9 個地鼠洞?核心機制 地鼠隨機從洞口彈出點擊有效目標獲得積分30 秒倒計時游戲模式 ?難度系統 簡單模式:生成間…

博客網站(springboot)整合deepseek實現在線調用

🎉🎉🎉🎉🎉🎉 歡迎訪問的個人博客:https://swzbk.site/,加好友,拉你入福利群 🎉🎉🎉🎉🎉🎉 1、de…

Kubernetes 單節點集群搭建

Kubernetes 單節點集群搭建教程 本人嘗試基于Ubuntu搭建一個單節點K8S集群,其中遇到各種問題,最大的問題就是網絡,各種鏡像源下載不下來,特此記錄!注意:文中使用了幾個鏡像,將看來可能失效導致安…

【PTA題目解答】7-3 字符串的全排列(20分)next_permutation

1.題目 給定一個全由小寫字母構成的字符串,求它的全排列,按照字典序從小到大輸出。 輸入格式: 一行,一個字符串,長度不大于8。 輸出格式: 輸出所有全排列,每行一種排列形式,字典序從小到大。 輸入樣例…

專題三0~n-1中缺失的數字

1.題目 給一個數組,單調性是遞增的,需要找到缺失的數字,加上這個數字就變為等差數組了。 2.算法原理 這里用二分來解決,而二段性是根據下標區分,臨界值前的數字于下標相對應,臨界值后的于下標相差1&#x…

【圖像處理】ISP(Image Signal Processor) 圖像處理器的用途和工作原理?

ISP(圖像信號處理器)是數字影像設備的“視覺大腦”,負責將傳感器捕獲的原始電信號轉化為我們看到的高清圖像。以下從用途和工作原理兩方面通俗解析: 一、ISP的核心用途:讓照片“更像眼睛看到的” 提升畫質&#xff1a…

python學習筆記-mysql數據庫操作

現有一個需求,調用高德api獲取全國縣級以上行政區數據并保存為json文件,使用python獲取: import requests import json# 高德API Key api_key "your_api_key"# 調用行政區域查詢API def fetch_districts():url f"https://r…

Redisson 實現分布式鎖源碼淺析

大家好,我是此林。 今天來分享Redisson分布式鎖源碼。還是一樣,我們用 問題驅動 的方式展開講述。 1. redis 中如何使用 lua 腳本? Redis內置了lua解釋器,lua腳本有兩個好處: 1. 減少多次Redis命令的網絡傳輸開銷。…

【軟件】免費的PDF全文翻譯軟件,能保留公式圖表的樣式

轉載請注明出處:小鋒學長生活大爆炸[xfxuezhagn.cn] 如果本文幫助到了你,歡迎[點贊、收藏、關注]哦~ 很多PDF全文翻譯軟件都是收費的,而劃線翻譯看著又很累。這個開源的PDF全文翻譯軟件非常好用,并且能夠保留公式、圖表、目錄和注…

CentOS 7 系統上安裝 SQLite

1. 檢查系統更新 在安裝新軟件之前,建議先更新系統的軟件包列表,以確保使用的是最新的軟件源和補丁。打開終端,執行以下命令: sudo yum update -y -y 選項表示在更新過程中自動回答 “yes”,避免手動確認。 2. 安裝 …

Gin(后端)和 Vue3(前端)中實現 Server-Sent Events(SSE)推送

在 Gin(后端)和 Vue3(前端)中實現 Server-Sent Events(SSE)推送,主要分為以下幾個步驟: 后端(Gin)實現 SSE Gin 框架可以使用 c.SSEvent 方法來推送 SSE 事…

大模型微調中顯存占用和訓練時間的影響因素

BatchSize 顯存占用:與batch_size呈線性關系,可理解為 M t o t a l M f i x e d B a t c h S i z e ? M p e r ? s a m p l e M_{total}M_{fixed}BatchSize*M_{per-sample} Mtotal?Mfixed?BatchSize?Mper?sample?,其中 M f i x e d…

【排序算法對比】快速排序、歸并排序、堆排序

排序算法對比:快速排序、歸并排序、堆排序 1. 快速排序(Quick Sort) 原理 快速排序采用 分治法(Divide and Conquer),通過選取基準值(pivot),將數組劃分為 小于基準值…

PentestGPT 下載

PentestGPT 下載 PentestGPT 介紹 PentestGPT(Penetration Testing GPT)是一個基于大語言模型(LLM)的智能滲透測試助手。它結合了 ChatGPT(或其他 GPT 模型)與滲透測試工具,幫助安全研究人員自…

防火墻虛擬系統實驗

一實驗拓撲 二實驗過程 配置資源 創建虛擬系統 配置管理員 創建安全策略

代碼隨想錄算法訓練營第31天 | 56. 合并區間 738.單調遞增的數字 968.監控二叉樹

56. 合并區間 代碼隨想錄 56. 合并區間 - 力扣&#xff08;LeetCode&#xff09; class Solution {public int[][] merge(int[][] intervals) {Arrays.sort(intervals,(a,b)->{if(a[0] b[0])return a[1] - b[1];return a[0] - b[0];});List<int[]> result new Arra…