十七、TCP編程

? TCP 編程是網絡通信的核心,其 API 圍繞面向連接的特性設計,涵蓋服務端和客戶端的交互流程。以下是基于 ?C 語言的 TCP 編程核心 API 及使用流程的詳細解析:


? 核心 API 概覽

?函數?角色?描述
socket()通用創建套接字,指定協議族(IPv4/IPv6)和類型(SOCK_STREAM)。
bind()服務端將套接字綁定到特定 IP 地址和端口。
listen()服務端將套接字設為監聽模式,等待客戶端連接請求。
accept()服務端接受客戶端連接,返回用于通信的新套接字。
connect()客戶端客戶端主動連接服務端。
send()/write()通用發送數據(TCP 保證數據順序,可能拆包/粘包)。
recv()/read()通用接收數據(需處理部分讀取和緩沖區管理)。
close()通用關閉套接字,終止連接。
shutdown()通用優雅關閉連接(可選關閉讀/寫方向)。

1、socket函數

函數原型與頭文件
#include <sys/types.h>
#include <sys/socket.h>int socket(int domain, int type, int protocol);

? 參數詳解

? domain(協議族/地址族)?

? 定義通信使用的協議族,常見值包括:

?值?描述
AF_INETIPv4 協議(最常用)
AF_INET6IPv6 協議
AF_UNIX/AF_LOCAL本地進程間通信(UNIX 域套接字)
AF_PACKET底層數據包接口(如原始以太網幀捕獲)

? 如果是IPV6編程,要使用struct sockddr_in6結構體(man 7 IPV6,通常使用struct sockaddr_storage來編程。

? type(套接字類型)?

指定數據傳輸的語義,常用類型:

?值?描述
SOCK_STREAM面向連接的流式套接字(TCP,可靠傳輸)
SOCK_DGRAM無連接的數據報套接字(UDP,盡最大努力交付)
SOCK_RAW原始套接字(直接訪問 IP/ICMP 等協議)
protocol(具體協議?)

通常設為 0,表示根據 domaintype ?自動選擇默認協議。例如:

  • SOCK_STREAM 默認使用 IPPROTO_TCP
  • SOCK_DGRAM 默認使用 IPPROTO_UDP

若需顯式指定協議,可用:

?值?描述
IPPROTO_TCP強制使用 TCP 協議
IPPROTO_UDP強制使用 UDP 協議
IPPROTO_ICMP用于原始套接字的 ICMP 協議

返回值

  • ?成功:返回一個非負整數?(套接字文件描述符),后續操作(如 bind, connect)均基于此描述符。
  • ?失敗:返回 -1,并設置 errno 表示錯誤原因(如 EACCES, EAFNOSUPPORT)。

典型使用場景

創建 TCP 套接字
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {perror("socket() failed");exit(EXIT_FAILURE);
}
  • 用于 HTTP、FTP 等需要可靠傳輸的應用。
?創建 UDP 套接字
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd == -1) {perror("socket() failed");exit(EXIT_FAILURE);
}
  • 用于 DNS 查詢、實時音視頻傳輸等場景。
創建原始套接字(需 root 權限)?
int sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
if (sockfd == -1) {perror("socket() failed");exit(EXIT_FAILURE);
}
  • 可手動構造 IP 或 ICMP 頭部,用于網絡探測工具(如 ping)。

2、bind函數

? bind() 函數是網絡編程中用于將套接字(socket)?與特定的IP地址和端口綁定的關鍵步驟,常用于服務端設置監聽地址。以下是 bind() 的詳細解析,包含函數原型、參數解釋、使用示例及常見問題:

函數原型
#include <sys/types.h>
#include <sys/socket.h>int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

參數

?參數?類型?描述
sockfdint已創建的套接字描述符(由socket()返回)
addrstruct sockaddr*指向保存綁定地址信息的結構體指針(需根據協議族填充對應的結構類型)
addrlensocklen_t地址結構體的長度(字節數)

地址結構體

?1. IPv4 地址結構 (struct sockaddr_in)
struct sockaddr_in {sa_family_t    sin_family;   // 地址族(如 AF_INET)in_port_t      sin_port;     // 端口號(需用 `htons()` 轉換字節序)struct in_addr sin_addr;     // IPv4 地址(需用 `inet_pton()` 或 `htonl(INADDR_ANY)`)unsigned char  sin_zero[8];  // 填充字段(一般置零)
};struct in_addr {uint32_t s_addr;            // 32位 IPv4 地址(網絡字節序)
};
?2. IPv6 地址結構 (struct sockaddr_in6)
struct sockaddr_in6 {sa_family_t     sin6_family;   // 地址族(AF_INET6)in_port_t       sin6_port;     // 端口號(網絡字節序)uint32_t        sin6_flowinfo; // IPv6 流信息(通常為0)struct in6_addr sin6_addr;     // IPv6 地址uint32_t        sin6_scope_id; // 接口范圍標識符(用于本地鏈路地址)
};struct in6_addr {unsigned char s6_addr[16];     // 128位 IPv6 地址
};
?3. 通用地址結構 (struct sockaddr)
struct sockaddr {sa_family_t sa_family;  // 地址族(AF_xxx)char        sa_data[14];// 具體地址數據(由子結構展開填充)
};

? 使用場景與示例

?1. 服務端綁定 IP 和端口
int server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (server_fd == -1) { perror("socket"); exit(1); }// 允許地址重用(避免服務端重啟時 bind 失敗)
int optval = 1;
setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));struct sockaddr_in addr = {0};
addr.sin_family = AF_INET;                       // IPv4
addr.sin_addr.s_addr = htonl(INADDR_ANY);        // 綁定所有本地 IP
addr.sin_port = htons(8080);                     // 綁定端口 8080if (bind(server_fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {perror("bind");close(server_fd);exit(1);
}// 后續可調用 listen() 啟動監聽
?2. 客戶端綁定特定源地址
int client_fd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in client_addr = {0};
client_addr.sin_family = AF_INET;
client_addr.sin_port = htons(12345);             // 指定客戶端端口
inet_pton(AF_INET, "192.168.1.100", &client_addr.sin_addr); // 指定源 IPbind(client_fd, (struct sockaddr*)&client_addr, sizeof(client_addr));
connect(client_fd, server_addr, sizeof(server_addr));

3、listen函數

函數原型
#include <sys/types.h>
#include <sys/socket.h>int listen(int sockfd, int backlog);

? 參數詳解

?參數?類型?描述
sockfdint已通過 bind() 綁定地址的套接字描述符(必須是 ?SOCK_STREAM 類型)。
backlogint已建立連接(完成三次握手)的隊列最大長度,決定同時等待 accept() 處理的連接數。

? 核心作用

  1. ?轉換套接字狀態:

    • 將套接字從主動模式?(默認)轉為被動模式,使其能夠接收客戶端的連接請求。
    • 未調用 listen() 的套接字無法調用 accept()
  2. ?管理連接隊列:

    • 內核為監聽套接字維護兩個隊列?(具體實現可能因操作系統而異):
      • ?未完成隊列(SYN_RCVD 狀態)?:客戶端已發送 SYN,但未完成三次握手。
      • ?已完成隊列(ESTABLISHED 狀態)?:已完成三次握手,等待 accept() 取出。
    • backlog 參數通常指已完成隊列的最大長度?(Linux 中默認上限由 /proc/sys/net/core/somaxconn 定義)。

? 使用場景與示例

?1. 服務端啟動監聽
int server_fd = socket(AF_INET, SOCK_STREAM, 0);
// ...綁定地址(bind())...// 設置監聽隊列長度為 128
if (listen(server_fd, 128) == -1) {perror("listen() failed");close(server_fd);exit(EXIT_FAILURE);
}// 循環接受客戶端連接
while (1) {struct sockaddr_in client_addr;socklen_t addrlen = sizeof(client_addr);int client_fd = accept(server_fd, (struct sockaddr*)&client_addr, &addrlen);// ...處理 client_fd...
}
?2. backlog 的合理取值
?經驗值:通常設為 SOMAXCONN(系統定義的最大值,如 Linux 默認 4096)。
?調整方法?(Linux):# 臨時修改 somaxconn
echo 4096 > /proc/sys/net/core/somaxconn# 永久修改(需編輯 /etc/sysctl.conf)
net.core.somaxconn = 4096
  • ?注意:實際允許的連接數受系統資源和并發模型(如多線程、epoll)影響。

4、accept函數

函數原型
#include <sys/types.h>
#include <sys/socket.h>int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

? 參數詳解

?參數

?類型

?描述

sockfd

int

處于監聽狀態的套接字描述符(由 listen() 設置)。

addr

struct sockaddr*

輸出參數,用于存儲客戶端地址信息(如 IP 和端口)。若不需要可設為 NULL

addrlen

socklen_t*

輸入輸出參數:傳入 addr 緩沖區的長度,返回實際寫入的地址長度。若 addrNULL,可設為 NULL


? 返回值

  • ?成功:返回一個新的已連接套接字描述符?(非負整數),專門用于與客戶端通信。

  • ?失敗:返回 -1,并設置 errno(如 EINTRECONNABORTED)。


? 核心作用

  1. ?提取連接:從監聽套接字的已完成連接隊列?(已完成三次握手)中取出一個客戶端連接。

  2. ?生成新套接字:返回的已連接套接字與客戶端一一對應,原監聽套接字繼續接受其他連接。

  3. ?獲取客戶端地址:通過 addr 參數獲取客戶端的 IP 地址和端口(可選)。

5、connect函數

函數原型
#include <sys/types.h>
#include <sys/socket.h>int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

? 參數詳解

?參數?類型?描述
sockfdint客戶端套接字描述符(由 socket() 創建)。
addrstruct sockaddr*指向服務端地址結構體的指針(如 sockaddr_in)。
addrlensocklen_t地址結構體的長度(單位:字節)。

? 返回值

  • ?成功:返回 0,套接字進入已連接狀態(TCP)或設置默認地址(UDP)。
  • ?失敗:返回 -1,并設置 errno 表示錯誤原因。

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

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

相關文章

將外網下載的 Docker 鏡像拷貝到內網運行

將外網下載的 Docker 鏡像拷貝到內網運行&#xff0c;可以通過以下步驟實現&#xff1a; 一、在有外網訪問權限的機器上操作 下載鏡像 使用docker pull命令下載所需的鏡像。例如&#xff0c;如果你需要下載一個名為nginx的鏡像&#xff0c;可以運行以下命令&#xff1a;docke…

《深入理解生命周期與作用域:以C語言為例》

&#x1f680;個人主頁&#xff1a;BabyZZの秘密日記 &#x1f4d6;收入專欄&#xff1a;C語言 &#x1f30d;文章目入 一、生命周期&#xff1a;變量的存在時間&#xff08;一&#xff09;生命周期的定義&#xff08;二&#xff09;C語言中的生命周期類型&#xff08;三&#…

Hqst的超薄千兆變壓器HM82409S在Unitree宇樹Go2智能機器狗的應用

本期拆解帶來的是宇樹科技推出的Go2智能機器狗&#xff0c;這款機器狗采用狗身體形態&#xff0c;前端設有激光雷達&#xff0c;攝像頭和照明燈。在腿部設有12個鋁合金精密關節電機&#xff0c;并配有足端力傳感器&#xff0c;通過關節運動模擬狗的運動&#xff0c;并可做出多種…

壹起航:15年深耕,引領中國工廠出海新征程

在全球化浪潮洶涌澎湃的當下&#xff0c;中國工廠正以前所未有的熱情和決心&#xff0c;將目光投向廣闊的海外市場。然而&#xff0c;出海之路并非一帆風順&#xff0c;建立品牌、獲取穩定詢盤、降低營銷成本等難題&#xff0c;如同橫亙在企業面前的高山&#xff0c;阻礙著他們…

【差分隱私相關概念】基礎合成定理和高級合成技術簡單關系

差分隱私中的合成定理用于分析多個機制組合時的隱私損失。基礎合成定理和高級合成技術分別在不同場景下提供了隱私預算增長的估計&#xff0c;其關系如下&#xff1a; 基礎合成定理&#xff08;線性增長&#xff09; 機制組合&#xff1a;當k個滿足(ε, δ)-DP的機制按順序組…

【異常處理】Clion IDE中cmake時頭文件找不到 頭文件飄紅

如圖所示是我的clion項目目錄 我自定義的data_structure.h和func_declaration.h在unit_test.c中無法檢索到 cmakelists.txt配置文件如下所示&#xff1a; cmake_minimum_required(VERSION 3.30) project(noc C) #設置頭文件的目錄 include_directories(${CMAKE_SOURCE_DIR}/…

MOS的驅動電流怎么計算?

一、MOS 驅動電流的計算方法 MOS 管在開關時&#xff0c;驅動電路主要是給柵極充放電。柵極電流 不是用來維持電流&#xff0c;而是用來克服電容的充放電需求&#xff0c;尤其是總柵極電荷 Qg。 驅動電流估算公式如下&#xff1a; I_drive Qg f_sw&#xff08;Qg&#xff…

GGML源碼逐行調試(下)

目錄 前言1. 簡述2. 預分配計算圖內存2.1 創建圖內存分配器2.2 構建最壞情況的計算圖2.3 預留計算圖內存 3. 分詞4. 模型推理與生成4.1 模型推理4.2 采樣 結語下載鏈接參考 前言 學習 UP 主 比飛鳥貴重的多_HKL 的 GGML源碼逐行調試 視頻&#xff0c;記錄下個人學習筆記&#x…

1.5-APP的架構\微信小程序的架構

1.5-APP的架構\微信小程序的架構 APP的三種開發架構&#xff1a; 原生態APP類型 APP-開發架構-原生態-IDEA 演示&#xff1a;remusic項目源碼 NP管理器&#xff1a; http://normalplayer.top/ HttpCanary&#xff1a;https://github.com/mingww64/HttpCanary-SSL-Magisk 安全影…

用css畫一條弧線

ui里有一條弧線&#xff0c;現在用css實現 關鍵代碼 border-bottom-left-radius: 100% 7px 兩個參數分別代表橫向和縱向的深度border-bottom-right-radius: 100% 7px

MSCKF及可觀性總結

可觀性 參考鏈接 真實VIO系統不能觀的維度是4&#xff08;位置和yaw角&#xff09;&#xff0c;由于EKF的轉移和觀測Jacobian矩陣的線性化點不同、不可觀方向噪聲的存在&#xff0c;實際MSCKF不能觀的維度變成了3&#xff0c;繞重力軸的旋轉&#xff08;yaw角&#xff09;被錯…

【Hotspot虛擬機創建對象的過程是什么樣的?】

1. 類加載檢查 觸發條件&#xff1a;當遇到 new 指令時&#xff0c;JVM首先檢查該指令的參數&#xff08;類符號引用&#xff09;是否已在常量池中。檢查內容&#xff1a; 類是否已被加載、解析和初始化。若未加載&#xff0c;則觸發類加載過程&#xff08;加載 → 驗證 → 準…

南墻WAF非標端口防護實戰解析——指定端口安全策略深度剖析

本文系統解析非標端口DDoS攻擊防護難點&#xff0c;重點闡述南墻WAF在指定端口防御中的技術突破。通過某金融機構真實攻防案例&#xff0c;結合Gartner最新防御架構模型&#xff0c;揭示如何構建基于智能流量建模的精準防護體系&#xff0c;為金融、政務等關鍵領域提供可落地的…

Context的全面解析:在不同技術應用中的通用作用與差異

Context的全面解析&#xff1a;在不同技術應用中的通用作用與差異 引言&#xff1a; 在軟件開發中&#xff0c;“Context”這個概念被廣泛使用。它不僅限于某個特定的技術或編程語言&#xff0c;實際上&#xff0c;Context 作為一種抽象的設計模式&#xff0c;貫穿在許多開發領…

尋找峰值 --- 二分查找

目錄 一&#xff1a;題目 二&#xff1a;算法原理 三&#xff1a;代碼實現 一&#xff1a;題目 題目鏈接&#xff1a;162. 尋找峰值 - 力扣&#xff08;LeetCode&#xff09; 二&#xff1a;算法原理 三&#xff1a;代碼實現 class Solution { public:int findPeakElemen…

基礎算法訓練7

目錄 庫存管理II 翻轉對 合并K個升序鏈表 存在重復元素II 字符串相乘 字符串解碼 在每個樹行中找最大值 數據流的中位數 被包圍的區域 為高爾夫比賽砍樹 庫存管理II LCR 159. 庫存管理 III - 力扣&#xff08;LeetCode&#xff09; 解法一&#xff1a;先進行排序&a…

從單機版到超級APP:MCP如何解鎖AI的超能力

MCP&#xff1a;AI界的“萬能充電寶”——讓AI從此告別“語言不通”的尷尬&#xff01; 開篇&#xff1a;AI咖啡館的尷尬日常 想象一下這樣的場景&#xff1a; 一位AI助手在咖啡館里手忙腳亂——它想幫用戶點杯咖啡&#xff0c;但需要先寫代碼調用天氣API&#xff08;“今天下…

Grafana將棄用AngularJS-我們該如何遷移

AngularJS 棄用時間線 AngularJS 支持已在 Grafana 9 中正式棄用。在 2024 年 5 月發布的 Grafana 11 中&#xff0c;所有 Grafana Cloud 和自托管安裝默認關閉該功能。到 Grafana 12 版本時&#xff0c;將完全移除對 AngularJS 的支持&#xff0c;包括配置參數開關 angular_s…

Qt之opengl定點數據添加更多屬性

將顏色數據加入到定點數據中去 shader中代碼 api中的代碼 #include "sunopengl.h"#include <QTime>sunOpengl::sunOpengl(QWidget *parent) { } unsigned int VBO,VAO; float vertices[]{0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f,0.5f, -0.5f, 0.0f, 0.0f, 1.0f…

【Flink運行時架構】作業提交流程

本文介紹在單作業模式下Flink提交作業的具體流程&#xff0c;如下圖所示。 客戶端將作業提交給YARN的RM&#xff1b;YARN的RM啟動Flink JobManager&#xff0c;并將作業提交給JobMaster&#xff1b;JobMaster向Flink內置的RM請求slots&#xff1b;Flink內置的RM向YARN RM請求…