零基礎入門:用C++從零實現TCP Socket網絡小工具

個人主頁:chian-ocean

文章專欄-Linux

前言:

網絡編程中的套接字(Socket)是通信的基本接口,允許不同計算機之間通過網絡交換數據。套接字是計算機網絡中通信的“端點”,通過它,應用程序可以與網絡中的其他計算機進行數據通信。網絡套接字接口提供了一種抽象的、平臺無關的方式來進行進程間通信(IPC)或網絡通信。

在這里插入圖片描述

網絡套接字接口

頭文件

  • 編寫網絡的常用的4個頭文件,基本常用的函數都在這4個頭文件里面。
#include <sys/types.h>    // 包含各種系統數據類型
#include <sys/socket.h>    // 包含套接字操作相關函數和常量
#include <arpa/inet.h>     // 包含與Internet地址轉換相關的函數
#include <netinet/in.h>    // 定義與網絡字節序及IPv4/IPv6地址相關的結構體和常量

接口

socket

socket() 函數是創建網絡通信套接字的基礎。它用于創建一個套接字(socket)并返回一個套接字描述符(socket descriptor),這個描述符將被用來進行后續的網絡通信(例如發送和接收數據)。

image-20250718221207038

int socket(int domain, int type, int protocol);

參數說明

  1. domain(地址族):指定通信使用的協議族。
    • 常用值:
      • AF_INET:IPv4 地址族(用于 TCP/IP 通信)。
      • AF_INET6:IPv6 地址族。
      • AF_UNIX:本地通信,適用于 Unix 域套接字。
  2. type(套接字類型):指定套接字的類型,決定數據傳輸的方式。
    • 常用值:
      • SOCK_STREAM:流套接字(用于 TCP)。
      • SOCK_DGRAM:數據報套接字(用于 UDP)。
      • SOCK_RAW:原始套接字,用于底層協議。
  3. protocol(協議):指定使用的具體協議,通常設置為 0 讓系統自動選擇協議。
    • 常用值:
      • 0:自動選擇合適的協議。
      • IPPROTO_TCP:用于 TCP。
      • IPPROTO_UDP:用于 UDP。

返回值

  • 成功時,socket() 返回一個 非負整數,這是一個套接字描述符,代表這個套接字。該描述符將用于后續的套接字操作(如綁定、連接、發送數據等)。
  • 失敗時,返回 -1,并且設置全局變量 errno 來指示錯誤類型。

bind()

image-20250718221211415

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

參數說明

  1. sockfd(套接字描述符)

    • 類型int

    • 描述:這是通過 socket() 創建的套接字描述符。客戶端使用該套接字發起連接請求。

    • 說明:該套接字應該是已經創建并且可以進行連接的有效套接字。

  2. addr(目標地址)

    • 類型struct sockaddr *

    • 描述:指向一個 struct sockaddr 結構體的指針,包含了服務器的地址(IP 地址和端口號)。

    • 說明:具體的結構類型通常為 struct sockaddr_in(用于 IPv4 地址)或者 struct sockaddr_in6(用于 IPv6 地址)。這個結構體包含了目標服務器的 IP 地址和端口號。

  3. addrlen(地址長度)

    • 類型socklen_t

    • 描述:指定目標地址結構體的大小(字節數)。

    • 說明:通常設置為 sizeof(struct sockaddr_in)sizeof(struct sockaddr_in6),用于告訴 connect() 函數地址結構的實際長度。

返回值

  • 成功時:返回 0,表示成功將套接字與指定的本地地址綁定。
  • 失敗時:返回 -1,并將 errno 設置為具體的錯誤碼。

listen()

image-20250718221214485

int listen(int sockfd, int backlog);

參數說明

  1. sockfd
    • 類型int
    • 描述:表示要進入監聽狀態的套接字描述符。這個套接字通常是通過 socket() 創建的,并且應該已經通過 bind() 綁定了本地地址(如 IP 地址和端口)。
    • 說明:套接字需要是一個有效的連接套接字,用于接受客戶端連接。
  2. backlog
    • 類型int
    • 描述:表示 監聽隊列的最大長度,也就是可以等待的連接請求數量。如果有多個客戶端同時請求連接,系統會將這些請求放入隊列中,backlog 參數設置了隊列的最大長度。
    • 說明:如果有超過 backlog 數量的連接請求,新的連接請求會被拒絕,或者它們會根據操作系統的實現策略被丟棄。
    • 推薦值:常見的 backlog 值一般設置為 5 到 128,根據服務器的需求而定。對于高并發系統,可能需要更大的 backlog 值。

返回值

  • 成功時:返回 0,表示成功將套接字轉換為監聽狀態。
  • 失敗時:返回 -1,并設置 errno 以指示錯誤原因。

accept()

image-20250718221217649

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

參數說明

  1. sockfd(套接字描述符)

    • 類型int

    • 描述:這是通過 socket() 創建的套接字描述符。客戶端使用該套接字發起連接請求。

    • 說明:該套接字應該是已經創建并且可以進行連接的有效套接字。

  2. addr(目標地址)

    • 類型struct sockaddr *

    • 描述:指向一個 struct sockaddr 結構體的指針,包含了服務器的地址(IP 地址和端口號)。

    • 說明:具體的結構類型通常為 struct sockaddr_in(用于 IPv4 地址)或者 struct sockaddr_in6(用于 IPv6 地址)。這個結構體包含了目標服務器的 IP 地址和端口號。

  3. addrlen(地址長度)

    • 類型socklen_t

    • 描述:指定目標地址結構體的大小(字節數)。

    • 說明:通常設置為 sizeof(struct sockaddr_in)sizeof(struct sockaddr_in6),用于告訴 connect() 函數地址結構的實際長度。

返回值

  • 成功時:返回 新的套接字描述符,用于與客戶端進行通信。這個新的套接字是通過 accept() 函數創建的,它與原始的監聽套接字不同,可以用于數據發送和接收。

  • 失敗時:返回 -1,并設置 errno 以指示錯誤原因。

connect()

image-20250718221220747

參數說明

  1. sockfd(套接字描述符)

    • 類型int

    • 描述:這是通過 socket() 創建的套接字描述符。客戶端使用該套接字發起連接請求。

    • 說明:該套接字應該是已經創建并且可以進行連接的有效套接字。

  2. addr(目標地址)

    • 類型struct sockaddr *

    • 描述:指向一個 struct sockaddr 結構體的指針,包含了服務器的地址(IP 地址和端口號)。

    • 說明:具體的結構類型通常為 struct sockaddr_in(用于 IPv4 地址)或者 struct sockaddr_in6(用于 IPv6 地址)。這個結構體包含了目標服務器的 IP 地址和端口號。

  3. addrlen(地址長度)

    • 類型socklen_t

    • 描述:指定目標地址結構體的大小(字節數)。

    • 說明:通常設置為 sizeof(struct sockaddr_in)sizeof(struct sockaddr_in6),用于告訴 connect() 函數地址結構的實際長度。

返回值

  • 成功時:返回 0,表示連接成功。

  • 失敗時:返回 -1,并且會設置 errno 來指示錯誤的具體原因。

close()

image-20250718221223631

int close(int fd);

參數說明

  1. fd(文件描述符):
    • 類型int
    • 描述:這是要關閉的文件描述符。對于套接字編程而言,這通常是由 socket() 函數返回的套接字描述符(sockfd)。
    • 說明:在網絡編程中,fd 是表示套接字的描述符,它可以是通過 socket() 創建的套接字描述符。關閉該描述符會釋放套接字占用的資源。

返回值

  • 成功時:返回 0,表示成功關閉套接字或文件描述符。
  • 失敗時:返回 -1,并設置 errno 為具體的錯誤代碼

網絡套接字封裝(TCP)

1. 頭文件引用

#include <iostream>
#include <string>
#include <cstring>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include "log.hpp"
  • <iostream>:提供輸入輸出流的功能,常用于打印日志或錯誤信息。
  • <string>:提供 C++ 標準庫的字符串類 std::string,用于字符串處理。
  • <cstring><strings.h>:用于處理字符串相關的操作,如 bzero()strerror()
  • <sys/types.h><sys/socket.h>:提供套接字編程所需的類型定義和系統調用。
  • <arpa/inet.h>:提供與 IP 地址轉換相關的函數(如 inet_ntop()inet_addr())。
  • <netinet/in.h>:定義了用于 IPv4 地址和端口的結構體和常量(如 sockaddr_inhtons())。
  • "log.hpp":這是一個自定義的日志頭文件,包含了日志記錄相關的內容。lg() 函數用于記錄日志,lg() 宏應該在 log.hpp 中定義。

2. 全局變量和枚舉類型

int backlog = 10;enum err
{Socketerr = 1,Bindeterr,Listeneterr, Accepteterr, 
};
  • backlog:這是傳遞給 listen() 函數的參數,定義了監聽隊列的最大長度(即最大客戶端連接數)。設置為 10
  • enum err:定義了與套接字相關的錯誤類型。
    • Socketerr = 1:表示套接字創建失敗。
    • Bindeterr:表示套接字綁定失敗。
    • Listeneterr:表示監聽失敗。
    • Accepteterr:表示接受客戶端連接失敗。

3. Sock

3.1 構造函數和析構函數

Sock() {}
~Sock() {}
  • 構造函數:默認構造函數,沒有進行任何初始化操作。
  • 析構函數:默認析構函數,沒有執行任何資源清理操作。

3.2 Socket() - 創建套接字

void Socket()
{sockfd_ = socket(AF_INET, SOCK_STREAM, 0);if(sockfd_ < 0){lg(FATAL,"Socket error: %d,%s",errno,strerror(errno));exit(Socketerr);}
}
  • 目的:創建一個 TCP 套接字。
    • AF_INET:表示 IPv4 地址族。
    • SOCK_STREAM:表示 TCP 流套接字(面向連接的套接字)。
    • 0:表示默認協議,通常是 TCP 協議。
  • 錯誤處理:如果 socket() 返回值小于 0,表示套接字創建失敗,記錄日志并退出程序,退出代碼為 Socketerr

3.3 Bind(uint16_t port) - 綁定套接字

void Bind(uint16_t port)
{struct sockaddr_in peer;socklen_t len = sizeof(peer);bzero(&peer,len);peer.sin_port = htons(port);peer.sin_family = AF_INET;peer.sin_addr.s_addr = INADDR_ANY;if(bind(sockfd_,(struct sockaddr *)&(peer),len) < 0){lg(FATAL,"Bind error: %d,%s",errno,strerror(errno));exit(Bindeterr);}
}
  • 目的:將套接字與本地 IP 地址和端口號綁定。通過 INADDR_ANY 將套接字綁定到所有可用的網絡接口上,接受來自任何 IP 地址的連接。
    • htons():將端口號從主機字節序轉換為網絡字節序。
  • 錯誤處理:如果 bind() 返回值小于 0,表示綁定失敗,記錄日志并退出程序,退出代碼為 Bindeterr

3.4 Listen() - 開始監聽

void Listen()
{if(listen(sockfd_, backlog) < 0){lg(FATAL,"Listen error: %d,%s",errno,strerror(errno));exit(Listeneterr);}
}
  • 目的:將套接字設置為監聽狀態,準備接受客戶端的連接。
    • backlog:監聽隊列的最大長度,定義最多能排隊等待的連接數。
  • 錯誤處理:如果 listen() 返回值小于 0,表示監聽失敗,記錄日志并退出程序,退出代碼為 Listeneterr

3.5 Accept(std::string \* clientip, uint16_t\* clientport) - 接受連接

int Accept(std::string * clientip, uint16_t* clientport)
{struct sockaddr_in peer;socklen_t len  = sizeof(peer);bzero(&peer,len);int newfd = accept(sockfd_,(struct sockaddr*)&(peer),&len);if(newfd < 0){lg(FATAL,"Accept error: %d,%s",errno,strerror(errno));exit(Accepteterr);}char ip[64];inet_ntop(AF_INET,&peer.sin_addr.s_addr,ip,sizeof(ip));*clientip = ip;*clientport = ntohs(peer.sin_port);return newfd;
}
  • 目的:接受來自客戶端的連接請求,并返回一個新的套接字用于與客戶端的通信。
    • accept() 函數返回一個新的套接字 newfd,用于與客戶端交換數據。
    • 通過 inet_ntop() 將客戶端的 IP 地址從二進制轉換為字符串格式,ntohs() 將客戶端的端口號轉換為主機字節序。
  • 錯誤處理:如果 accept() 返回值小于 0,表示接受連接失敗,記錄日志并退出程序,退出代碼為 Accepteterr

3.6 Connect(const std::string& ip, const uint16_t& port) - 連接服務器

bool Connect(const std::string& ip,const uint16_t& port)
{struct sockaddr_in peer;socklen_t len  = sizeof(peer);bzero(&peer,len);peer.sin_addr.s_addr = inet_addr(ip.c_str());peer.sin_port = htons(port);peer.sin_family = AF_INET;int n = connect(sockfd_,(struct sockaddr*)&(peer),len);if(n < 0){lg(WARNING,"Connect error: %d,%s",errno,strerror(errno));return false;}return true;
}
  • 目的:客戶端通過此函數連接到遠程服務器,指定服務器的 IP 地址和端口。
    • inet_addr():將 IP 地址從字符串轉換為網絡字節序的二進制格式。
    • htons():將端口號轉換為網絡字節序。
  • 錯誤處理:如果 connect() 失敗,記錄警告日志并返回 false,否則返回 true 表示連接成功。

3.7 GetFd() - 獲取套接字描述符

int  GetFd()
{return sockfd_;
}
  • 目的:返回套接字描述符,便于外部訪問該套接字,用于進一步的操作(如 send()recv() 等)。

網絡小組件鏈接

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

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

相關文章

SOES:軟實現EtherCAT從站協議棧項目介紹及從站開發案例

在現代工業自動化領域&#xff0c;EtherCAT&#xff08;Ethernet for Control Automation Technology&#xff09;以其高速、實時和開放的特性&#xff0c;成為現場總線通信的主流協議之一。EtherCAT網絡中&#xff0c;主站&#xff08;Master&#xff09;負責調度和管理&#…

[simdjson] 填充字符串 | `document` 對象 | on-demand 模式

第二章&#xff1a;填充字符串 在第一章解析器中&#xff0c;我們學習了simdjson::dom::parser和simdjson::ondemand::parser作為可復用內存的JSON解析工具。 本章將深入解析JSON數據輸入的核心要求——“填充字符串”。 為何需要填充&#xff1f; simdjson通過SIMD&#x…

扭蛋機小程序開發:開啟線上娛樂新風尚

在當今數字化浪潮席卷的時代&#xff0c;娛樂方式正經歷著前所未有的變革。傳統的扭蛋機&#xff0c;那充滿驚喜與期待的實體裝置&#xff0c;曾是無數人童年回憶中的歡樂源泉。如今&#xff0c;隨著科技的飛速發展&#xff0c;扭蛋機小程序開發應運而生&#xff0c;將這份經典…

【React Native】布局和 Stack 、Slot

布局和Stack 點擊鏈接后&#xff0c;頁面切換時最好是有動畫效果。頁面一般都有頭部&#xff0c;里面有頁面的標題之類的東西。 在app目錄里&#xff0c;新建一個_layout.js文件&#xff0c;這是項目的布局文件。 這個名字是固定的&#xff0c;前面必須有一個_ 。 布局的意…

3C電子產品藍光三維掃描檢測方案-中科米堆CASAIM

隨著3C電子產品向輕薄化、精密化方向發展&#xff0c;傳統的二維檢測技術已難以滿足現代制造業對產品精度的高標準要求。特別是在智能手機、平板電腦等消費電子領域&#xff0c;微小的結構偏差都可能導致產品組裝困難或性能下降。當前行業內普遍面臨檢測效率低、數據采集不完整…

Docker 鏡像原理

Union FS(聯合文件系統) Union File System 是一種分層、輕量級并且高性能的文件系統&#xff0c;它支持對文件系統的修改作為一次提交來一層層的疊加&#xff0c;同時可以將不同目錄掛載到同一個虛擬文件系統下。UnionFS 是一種為 Linux&#xff0c;FreeBSD 和 NetBSD 操作系統…

為什么IoTDB成為物聯網場景的技術優選?

在物聯網、工業監控等領域&#xff0c;時序數據的高效管理成為技術架構設計的關鍵環節。時序數據庫作為專門處理帶時間戳數據的系統&#xff0c;其選型需兼顧性能、兼容性與場景適配性。本文將從技術角度解析 IoTDB 的設計理念與實踐方法&#xff0c;為時序數據庫選型提供參考。…

js中的微任務和宏任務的理解

在JavaScript中&#xff0c;微任務&#xff08;Microtask&#xff09;和宏任務&#xff08;Macrotask&#xff09;是異步任務執行機制的重要組成部分&#xff0c;它們共同構成了JavaScript事件循環&#xff08;Event Loop&#xff09;的核心邏輯。理解這兩個概念對于編寫高性能…

Spring-AI系列-AI模型-Model

原文-知識庫&#xff0c;歡迎大家評論互動 AI Model API Portable ModelAPI across AI providers for Chat, Text to Image, Audio Transcription, Text to Speech, and Embedding models. Both synchronous and stream API options are supported. Dropping down to access mo…

MySQL查詢今天、昨天、上周、近30天、去年等的數據的方法

目錄 常用的MySQL查詢今天、昨天、上周、近30天、去年等數據的方法 0、Sql server中DateDiff()用法 1、MySQL的DATE_SUB()函數 定義和用法 語法 實例 2、MySQL的TO_DAYS(date) 3、MySQL的DATE() 函數 定義和用法 4、MySQL NOW() 函數 定義和用法 語法 實例 例子 …

Linux —— B / 基礎開發工具

一、軟件包管理器1.1什么是軟件包1.2 Linux軟件生態1.3 yum具體操作1.3.1 查看軟件包1.3.2 安裝軟件1.3.3 卸載軟件1.3.4 注意事項1.4 安裝源二、編輯器Vim2-1 Linux編輯器-vim使用2-2 vim的基本概念2-3 vim的基本操作2-4 vim正常模式命令集2-5 vim末行模式命令集2-6 vim操作總…

SQL,在join中,on和where的區別

0.結論 兩個表在&#xff0c;join時&#xff0c;首先做一個笛卡爾積&#xff0c;on后面的條件是對這個笛卡爾積做一個過濾形成一張臨時表&#xff0c;如果沒有where就直接返回結果&#xff0c;如果有where就對上一步的臨時表再進行過濾。 先on&#xff0c;再join&#xff0c;再…

SD-WAN在儲能網絡中的應用,傳統方案如何借力智能化升級?(附網絡架構圖)

一、儲能網絡的建設挑戰在儲能項目中&#xff0c;網絡系統通常需要實現以下目標&#xff1a;高可靠性&#xff1a;實時采集和傳輸儲能設備狀態數據&#xff0c;鏈路中斷可能導致系統故障。靈活擴展&#xff1a;分布式站點部署廣泛&#xff0c;傳統網絡擴展需重新鋪設線路&#…

Oracle11.2.0.4 RAC遷移升級Oracle19.3 RAC

問題描述 填寫問題的基礎信息。 系統名稱 Oracle11.2.0.4遷移升級Oracle19.3 IP地址 操作系統 Centos7.5 數據庫 Oracle11.2.0.4遷移升級Oracle19.3 癥狀表現 問題的癥狀表現如下 需要將單機的Oracle11.2.0.4環境升級到Oracle19.3.0RAC環境&#xff0c;采用遷移升級的…

SAP-ABAP:SAP的‘cl_http_utility=>escape_url‘對URL進行安全編碼方法詳解

SAP的’cl_http_utility>escape_url’對URL進行安全編碼方法詳解 核心作用&#xff1a;對 URL 進行安全編碼&#xff0c;將特殊字符轉換為 %XX 格式&#xff0c;確保符合 HTTP 傳輸規范。1. 功能與作用 ? URL 安全編碼 將非安全字符轉換為十六進制 ASCII 碼&#xff08;%XX…

基于HarmonyOS的智能燈光控制系統設計:從定時觸發到動作聯動全流程實戰

摘要 隨著智能家居的快速普及&#xff0c;人們對居住環境的智能化需求越來越高&#xff0c;其中智能燈光控制是最基礎、也是最常用的功能之一。從最初的遠程控制發展到如今能“感知環境、自動響應”的智能燈光系統&#xff0c;背后依賴的是強大的系統聯動能力。鴻蒙系統作為面向…

ROS1/Linux——linux虛擬機主ip地址:網絡信息不可用

ROS1/Linux——linux虛擬機主ip地址&#xff1a;網絡信息不可用 文章目錄ROS1/Linux——linux虛擬機主ip地址&#xff1a;網絡信息不可用參考億點鏈接問題描述最終解決方案參考億點鏈接 Unable to fetch some archives, maybe run apt-get update or try with –fix-missingli…

ssl相關命令生成證書

當前環境 OpenSSL 3.5.1 1 Jul 2025 (Library: OpenSSL 3.5.1 1 Jul 2025) GmSSL 3.1.2 Dev 本地gmssl命令 #生成證書公私鑰對 gmssl sm2keygen -pass 1234 -out sm2.key -pubout sm2pub.pem #使用certgen命令生成自簽名證書cert.crt gmssl certgen -C CN -ST Beijing -L Ha…

TensorFlow深度學習實戰——DCGAN詳解與實現

TensorFlow深度學習實戰——DCGAN詳解與實現0. 前言1. DCGAN 架構2. 構建 DCGAN 生成手寫數字圖像2.1 生成器與判別器架構2.2 構建 DCGAN相關鏈接0. 前言 深度卷積生成對抗網絡 (Deep Convolutional Generative Adversarial Network, DCGAN) 是一種基于生成對抗網絡 (Generati…

SpringBoot 使用MyBatisPlus

引入依賴<dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId><version>4.3.0</version> </dependency>寫一個interface 繼承basemapMapper public in…