Linux網絡:socket編程TCP

文章目錄

  • 前言
  • 一,服務器端流程
    • 1-1 綁定協議
    • 1-2 綁定IP和端口
    • 1-3 監聽客戶端
    • 1-4 接收連接
    • 1-5 收發數據
    • 1-6 關閉連接
    • 1-7 服務端整體代碼
  • 二,客戶端流程
    • 2-1 指定地址和端口
    • 2-2 連接服務器
    • 2-3 發送消息
    • 2-4 客戶端整體代碼


前言

TCP 的通信過程就像兩個人打電話:客戶端先和服務端三次握手建立一條可靠的連接通道,之后數據會以字節流的形式在這條通道里雙向傳輸,系統會負責把數據切片、編號、確認和重傳,保證信息不丟失、不重復、按順序送達,最后通過四次揮手優雅地斷開連接。


連接流程大致如下圖
在這里插入圖片描述

一,服務器端流程

1-1 綁定協議

TCP通信也和UDP一樣需要先創建套接字

int server_fd = socket(AF_INET, SOCK_STREAM, 0);

這里的SOCK_STREAM,說明套接字是用字節流的形式傳遞數據,也就是TCP通信


1-2 綁定IP和端口

sockaddr_in addr {};
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY; // 本機任意 IP
addr.sin_port = htons(12345); // 端口 12345
if (bind(server_fd, (sockaddr * ) & addr, sizeof(addr)) < 0) {perror("bind");return 1;
}

addr.sin_family = AF_INET;的意思就是,設置協議為IPv4,其它的不過多講解就是綁定端口和將sockaddr_in轉化為sockaddr

addr.sin_addr.s_addr = INADDR_ANY表示本機的客戶端的任意IP都可以連接服務端


1-3 監聽客戶端

listen(server_fd, 5);
std::cout << "服務端啟動,等待客戶端連接..." << std::endl;

server_fd是我們socket創建的套接字,用于服務端得知是哪一個套接字要監聽,所以必須傳入 server_fd。沒有 server_fd,內核就不知道“我要監聽哪條網絡通道”,就沒法接受連接

這里的這個參數5表明:連接隊列的最大長度,內核會維護一個隊列,存放已到達但還沒被 accept() 處理的客戶端連接,這里寫 5 表示最多允許排隊 5 個連接請求。超過的請求可能會被拒絕。


1-4 接收連接

sockaddr_in client_addr{};
socklen_t len = sizeof(client_addr);
int client_fd = accept(server_fd, (sockaddr*)&client_addr, &len);

我們需要接收客戶端的連接,這時會用到 sockaddr_in 來存儲客戶端的地址信息。accept() 會返回一個新的套接字 client_fd。因此服務器中會有 兩種套接字:

  • server_fd:用于監聽端口和接受客戶端的連接請求。它可以同時管理多個客戶端連接,但 不能直接用于數據通信。

  • client_fd:由 accept() 返回,用于和 特定客戶端 進行通信。每個客戶端連接都會對應一個獨立的 client_fd,可以通過 read()write() 發送或接收數據。

簡而言之:server_fd 用于建立連接,client_fd 用于通信,server_fd 可以服務多個客戶端,而每個 client_fd 只對應一個客戶端。


1-5 收發數據

char buffer[1024];
int n = read(client_fd, buffer, sizeof(buffer) - 1);
if (n > 0) {buffer[n] = '\0';std::cout << "收到客戶端消息: " << buffer << std::endl;std::string reply = "Hello from server!";write(client_fd, reply.c_str(), reply.size());
}

先是讀取數據,我們先定義一個buffer,將對應客戶端的套接字對應的文件信息讀取到buffer中,再使用write將數據發送到client_fd對應的套接字當中,這里其實沒什么特別的,就是收數據/發數據


1-6 關閉連接

close(client_fd);
close(server_fd);

雖然只有一行,但是OS這里會讓客戶端和服務端發生四次揮手:

  • FIN(發送方): 服務端調用 close(client_fd)內核向客戶端發送 FIN 報文,表示“我已經沒有數據要發了”。

  • ACK(接收方): 客戶端收到 FIN 后,回復 ACK 報文,確認收到,客戶端仍然可以發送剩余數據。

  • FIN(接收方): 客戶端發送完數據后,也調用 close(),向服務端發送 FIN 報文,表示“我也發送完了”。

  • ACK(發送方): 服務端收到 FIN 后,發送 ACK 報文 確認。連接真正關閉。


1-7 服務端整體代碼

int main() {// 1. 創建套接字int server_fd = socket(AF_INET, SOCK_STREAM, 0);if (server_fd < 0) {perror("socket");return 1;}// 2. 綁定 IP 和端口sockaddr_in addr {};addr.sin_family = AF_INET;addr.sin_addr.s_addr = INADDR_ANY; // 本機任意 IPaddr.sin_port = htons(12345); // 端口 12345if (bind(server_fd, (sockaddr * ) & addr, sizeof(addr)) < 0) {perror("bind");return 1;}// 3. 監聽listen(server_fd, 5);std::cout << "服務端啟動,等待客戶端連接..." << std::endl;// 4. 接受連接sockaddr_in client_addr {};socklen_t len = sizeof(client_addr);int client_fd = accept(server_fd, (sockaddr * ) & client_addr, & len);if (client_fd < 0) {perror("accept");return 1;}std::cout << "客戶端已連接!" << std::endl;// 5. 收發數據char buffer[1024];int n = read(client_fd, buffer, sizeof(buffer) - 1);if (n > 0) {buffer[n] = '\0';std::cout << "收到客戶端消息: " << buffer << std::endl;std::string reply = "Hello from server!";write(client_fd, reply.c_str(), reply.size());}// 6. 關閉連接close(client_fd);close(server_fd);return 0;
}

二,客戶端流程

在客戶端流程當中存在和服務端一樣的流程,就是創建套接字,這里我們直接省略了。


2-1 指定地址和端口

sockaddr_in server_addr {};
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(12345);
inet_pton(AF_INET, "127.0.0.1", & server_addr.sin_addr); // 本地回環地址

這里我們創建的inet_pton的作用是把點分十進制的 IP 地址字符串轉換成網絡字節序的二進制形式

因為 socket 系統調用只能處理二進制的網絡地址,而不能直接識別字符串形式的 IP,人類習慣用 "127.0.0.1" 這樣的點分十進制 IP

內核底層在發送數據時,需要 32 位的二進制形式(網絡字節序)來表示 IP 地址,inet_pton 就完成了 “人類可讀 IP → 網絡可用二進制 IP” 的轉換,如果不做轉換,connect()bind() 會因為地址無效而失敗


2-2 連接服務器

我們通過connet來與服務端建立連接

if (connect(sock, (sockaddr * ) & server_addr, sizeof(server_addr)) < 0) {perror("connect");return 1;
}

這里沒有什么很特別的,就是傳遞我們的地址端口接口體給服務端,然后服務端拿到結構體和客戶端進行連接,并且客戶端的sock套接字也和服務端的套接字對應的文件進行連接


2-3 發送消息

std::string msg = "Hello Server!";
write(sock, msg.c_str(), msg.size());
char buffer[1024];
int n = read(sock, buffer, sizeof(buffer) - 1);
if (n > 0) {buffer[n] = '\0';std::cout << "收到服務端回復: " << buffer << std::endl;
}

通過writeread發送和接收消息,也是很簡單的代碼


2-4 客戶端整體代碼

int main() {// 1. 創建套接字int sock = socket(AF_INET, SOCK_STREAM, 0);if (sock < 0) {perror("socket");return 1;}// 2. 指定服務端地址sockaddr_in server_addr {};server_addr.sin_family = AF_INET;server_addr.sin_port = htons(12345);inet_pton(AF_INET, "127.0.0.1", & server_addr.sin_addr); // 本地回環地址// 3. 連接服務器if (connect(sock, (sockaddr * ) & server_addr, sizeof(server_addr)) < 0) {perror("connect");return 1;}std::cout << "已連接服務器!" << std::endl;// 4. 發送消息std::string msg = "Hello Server!";write(sock, msg.c_str(), msg.size());// 5. 接收回復char buffer[1024];int n = read(sock, buffer, sizeof(buffer) - 1);if (n > 0) {buffer[n] = '\0';std::cout << "收到服務端回復: " << buffer << std::endl;}// 6. 關閉close(sock);return 0;
}

演示結果:
服務端

root@hcss-ecs-f59a:/gch/code/HaoHao/learn3/day6# ./server
服務端啟動,等待客戶端連接...
客戶端已連接!
收到客戶端消息: Hello Server!

客戶端

root@hcss-ecs-f59a:/gch/code/HaoHao/learn3/day6# ./client
已連接服務器!
收到服務端回復: Hello from server!

本博客中只是做了一個簡單的服務端和客戶端的通信,在實際項目當中,這種通信代碼還是前篇一律的,所以我就采用了分布式講解

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

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

相關文章

飛書智能查詢機器人搭建說明文檔

飛書智能查詢機器人搭建說明文檔 一、使用手冊 1. 創建飛書機器人應用 如果僅需對接已有機器人應用則可跳過該步驟&#xff08;建議各業務部門獨立使用各自的機器人應用&#xff09;。在飛書開發者后臺中創建企業自建應用&#xff0c;添加機器人應用能力并申請對應的身份權限…

藍色系列包裝行業網站 適合企業站,帶手機版自適應

內容目錄一、詳細介紹二、效果展示1.部分代碼2.效果圖展示三、學習資料下載一、詳細介紹 藍色通用企業網站是基于SDCMS四合一企業網站管理系統開發的模板&#xff0c;適合企業站&#xff0c;帶手機版。 四網合一企業網站管理系統是一個以PHPMySQL/Sqlite進行開發的四網合一網…

【大模型:知識圖譜】--6.Neo4j DeskTop安裝+使用

上一期講了圖知識庫的安裝&#xff0c; 【圖數據庫】--Neo4j 安裝_neo4j安裝-CSDN博客 現在來看看可視化管理程序&#xff1a;Neo4j DeskTop的安裝. 需要先安裝java環境&#xff0c;具體看上面 目錄 1.Neo4j DeskTop版下載 2.Neo4j DeskTop版安裝 3.Neo4j DeskTop版使用 …

Python爬蟲實戰——使用NetNut網頁解鎖器獲取亞馬遜電商數據

文章目錄一、電商數據的作用1.1 支撐科學決策&#xff0c;降低試錯成本1.2 提升運營效率&#xff0c;實現降本增效1.3 深化用戶理解&#xff0c;驅動個性化服務1.4 監測競品動態&#xff0c;制定差異化策略1.5 驅動產品創新&#xff0c;滿足用戶需求二、爬取目標三、環境準備四…

超越NAT:如何構建高效、安全的內網穿透隧道

在敏捷開發和分布式協作成為主流的今天&#xff0c;開發者需要一個能夠將本地開發環境瞬間暴露給公網的能力&#xff0c;以便進行演示、聯調或處理回調。傳統方案如配置路由器端口映射或部署VPN&#xff0c;不僅繁瑣且存在安全風險。內網穿透技術&#xff0c;特別是以 ngrok、Z…

第二十三章 ESP32S3 RTC 實驗

本章介紹 ESP32-S3 實時時鐘&#xff08;RTC&#xff09;的使用&#xff0c;實時時鐘能為系統提供一個準確的時間&#xff0c;即時系統復位或主電源斷電&#xff0c; RTC 依然能夠運行&#xff0c;因此 RTC 也經常用于各種低功耗場景。通過本章的學習&#xff0c;將學習到 RTC …

Java 輕松實現 Markdown 轉 Word、PDF、HTML

在軟件開發和技術寫作領域&#xff0c;Markdown 已成為一種被廣泛使用的輕量級標記語言。它的語法簡潔&#xff0c;書寫效率高&#xff0c;非常適合快速記錄筆記、撰寫技術文檔或博客文章。但在實際應用中&#xff0c;Markdown 文件往往需要被轉換為更通用的格式&#xff0c;例…

Kafka系列之:Kafka broker does not support the ‘MetadataRequest_v0‘ Kafka protocol.

Kafka系列之:Kafka broker does not support the MetadataRequest_v0 Kafka protocol. 一、完整報錯 二、錯誤原因 三、解決方法 一、完整報錯 kafka.errors.IncompatibleBrokerVersion: IncompatibleBrokerVersion: Kafka broker does not support the ‘MetadataRequest_v0’…

開源AI紅隊工具“Red AI Range“助力發現、分析與緩解AI系統漏洞

開源AI紅隊平臺Red AI Range&#xff08;RAR&#xff09;正在改變安全專業人員評估和強化AI系統的方式。該平臺通過模擬真實攻擊場景&#xff0c;利用容器化架構和自動化工具&#xff0c;簡化了AI特有漏洞的發現、分析和緩解流程。**核心功能** 1. 武器庫/目標按鈕可快速啟動…

SQL 數據庫簡介

SQL&#xff08;Structured Query Language&#xff09;是一種用于管理和操作關系型數據庫的標準語言。關系型數據庫以表格形式存儲數據&#xff0c;并通過行和列的結構化方式組織信息。SQL 提供了一套強大的命令&#xff0c;用于查詢、插入、更新和刪除數據&#xff0c;以及管…

SpringBoot4與Spring7發布:云原生深度進化

Spring Boot 4和Spring Framework 7帶來基礎要求升級、模塊化改進、API版本化、聲明式HTTP客戶端、彈性注解等重大特性&#xff0c;標志著Java開發生態向云原生時代的深度進化。 近日&#xff0c;Spring生態迎來了自2022年以來最具里程碑意義的更新——Spring Boot 4和Spring …

基于Spring Boot與Micrometer的系統參數監控指南

如何為你的Spring Boot應用裝上一個功能強大的監控儀表盤在現代微服務架構中&#xff0c;系統監控已成為保障應用穩定性的關鍵環節。通過有效的監控&#xff0c;我們可以實時了解應用的運行狀態&#xff0c;及時發現并解決性能問題。本文將介紹如何使用Micrometer及其注冊表&am…

【運維】-- 前端會話回放與產品分析平臺之 openreplay

目錄 OpenReplay 項目分析 1、項目概覽 2、關鍵特性 3、代碼結構&#xff08;Monorepo&#xff09; 4、技術棧與語言占比 5、部署與交付 6、社區與支持 7、版本與活躍度&#xff08;截至倉庫頁面所示&#xff09; 8、適用場景 9、優勢與注意事項 10、落地建議&#…

NineData社區版 V4.5.0 正式發布!運維中心新增細粒度任務權限管理,新增MySQL至Greenplum全鏈路復制對比

NineData 社區版 V4.5.0 正式發布&#xff01;在數據復制方面&#xff0c;新增 MySQL 至 Greenplum 全鏈路復制對比&#xff0c;并優化全局 DDL 管控、MySQL/PostgreSQL/MongoDB 同構性能。在數據庫 DevOps 方面&#xff0c;新增支持 AWS RDS 全系列及阿里云 PolarDB&#xff0…

discuz所有下載版本和升級工具

下載版本: Discuz! 每日構建版下載 - DiscuzX 3.x Daily Build Download Site SC是簡體中文 TC是繁體中文 可能你需要其他版本: Discuz!官方網站 - 開放、連接、共贏 下載簡體中文就好。 升級工具: 升級程序下載地址 https://gitee.com/oldhuhu/DiscuzX34235.git(…

【開題答辯全過程】以 “紅色棗莊”旅游網站為例,包含答辯的問題和答案

個人簡介一名14年經驗的資深畢設內行人&#xff0c;語言擅長Java、php、微信小程序、Python、Golang、安卓Android等開發項目包括大數據、深度學習、網站、小程序、安卓、算法。平常會做一些項目定制化開發、代碼講解、答辯教學、文檔編寫、也懂一些降重方面的技巧。感謝大家的…

【LeetCode】2785. 將字符串中的元音字母排序

題目描述 題目鏈接 問題分析 這道體的思路非常簡單和好理解&#xff0c;找出字符串中的元音字符&#xff0c;然后按照ASSIC值進行排序&#xff0c;然后插入回對應的位置&#xff0c;解題步驟為&#xff1a; 使用一個set&#xff08;可以快速查找的容器&#xff09;&#x…

3 步發 10 億郵件,這個 GitHub 開源項目牛逼。

你是否要經常批量發郵件&#xff1f;無論是向客戶推送最新資訊、產品營銷&#xff0c;還是發送日常常規通知類郵件。使用第三方郵件服務平臺不僅成本高昂&#xff0c;功能限制多&#xff0c;而且可能無法保證隱私和安全。現在&#xff0c;有一個完全開源、能自己部署的解決方案…

【計算機網絡】DNS 解析 DNS 污染

1. DNS 解析&#xff08;工作流程、參與方與緩存&#xff09; DNS 的目標&#xff1a;把人類可讀的域名&#xff08;如 www.example.com&#xff09;映射為 IP 地址&#xff08;如 93.184.216.34&#xff09;。 典型解析流程&#xff08;遞歸解析器 迭代查詢&#xff09;&…

用住宿樓模型徹底理解Kubernetes架構(運行原理視角)

導讀&#xff1a;從樓宇建設到租客入住的全流程想象我們正在建設一棟巨型智能住宿樓&#xff0c;從基礎設施搭建到租客入住管理&#xff0c;每個環節都對應Kubernetes的組件和概念。本文將按運行原理的先后順序&#xff0c;系統解析Kubernetes的23個核心組件與基本概念。把 Kub…