SOCKET編程(3):相關結構體與函數

相關結構體與函數

sockaddr、sockaddr_in結構體

sockaddr和sockaddr_in詳解

struct sockaddr共16字節,協議族(family)占2字節,IP地址和端口號在sa_data字符數組中

/* Structure describing a generic socket address.  */
struct sockaddr
{__SOCKADDR_COMMON(sa_); /* Common data: address family and length.  */char sa_data[14];       /* Address data.  */
};#define	__SOCKADDR_COMMON(sa_prefix) \sa_family_t sa_prefix##family

struct sockaddr_in更細致地劃分了協議族、端口號和IP地址,其中IP地址定義了新的結構體struct in_addr該結構體中宏定義了uint32_t類型的變量,sin_zero字符數組存在的意義是為了使struct sockaddr_instruct sockaddr 大小相等,便于進行強制類型轉換(與bind()等函數的參數有關)

/* Structure describing an Internet socket address.  */
struct sockaddr_in
{__SOCKADDR_COMMON(sin_);in_port_t sin_port;      /* Port number.  */struct in_addr sin_addr; /* Internet address.  *//* Pad to size of `struct sockaddr'.  */unsigned char sin_zero[sizeof(struct sockaddr) -__SOCKADDR_COMMON_SIZE -sizeof(in_port_t) -sizeof(struct in_addr)];
};/* Internet address.  */
typedef uint32_t in_addr_t;
struct in_addr
{in_addr_t s_addr;
};

總結

  1. 二者長度一樣,都是16個字節,即占用的內存大小是一致的,因此可以互相轉化。二者是并列結構,指向sockaddr_in結構的指針也可以指向sockaddr
  2. sockaddr常用于bind、connect、recvfrom、sendto等函數的參數,指明地址信息,是一種通用的套接字地址
  3. sockaddr_in 是internet環境下套接字的地址形式
  4. 在網絡編程中我們會對sockaddr_in結構體進行操作,使用sockaddr_in來建立所需的信息,最后使用類型轉化
  5. 一般先把sockaddr_in變量賦值后,強制類型轉換后傳入用sockaddr做參數的函數:sockaddr_in用于socket定義和賦值;sockaddr用于函數參數

socket()函數

socket函數用于創建一個新的socket,也就是向系統申清一個socket資源

socket函數用戶客戶端和服務端

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

domain:協議域,又稱協議族(family)。常用的協議族有AF INET、AF INET6、AF LOCAL(或稱AF UNIX,Unix域Socket)、AF ROUTE等。協議族決定了socket的地址類型,在通信中必須采用對應的地址,如AF INET決定了要用ipv4地址(32位的)與端口號(16位的)的組合、AF_UNIX決定了要用一個絕對路徑名作為地址

type:指定socket類型。常用的socket類型有SOCK_STREAM、SOCK_DGRAM、SOCK RAW、SOCK_PACKET、SOCK_SEQPACKET等。流式socket(SOCK_STREAM)是一種面向連接的socket,針對于面向連接的TCP服務應用。數據報式socket(SOCK_DGRAM)是一種無連接的socket,對應于無連接的UDP服務應用

protocol:指定協議。常用協議有IPPROTO_TCP、IPPROTO_UDP、IPPROTO_STCP、IPPROTO_TIPC等,分別對應TCP傳輸協議、UDP傳輸協議、STCP傳輸協議、TIPC傳輸協議

💡 第一個參數只能填AF INET,第二個參數只能填SOCK STREAM,第三個參數只填0

除非系統資料耗盡,socket函數一般不會返回失敗

返回值:成功則返回一個socket,失敗返回-1,錯誤原因存于errno中

💡 “資源耗盡”即Linux對打開文件數的限制,見2022-06-10筆記

// 第1步:創建服務端的socket
int listenfd;
for (int i = 0; i < 2000; ++i)
{if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){perror("socket");return -1;}cout << "sock id:" << listenfd << endl;
}
sock id:1012
sock id:1013
sock id:1014
sock id:1015
sock id:1016
sock id:1017
sock id:1018
sock id:1019
sock id:1020
sock id:1021
sock id:1022
sock id:1023
socket: Too many open files

inet_addr() 和inet_ntoa()函數

使用socket進行通信的時候,我們需要指定三個元素:通信域(地址族)、IP地址、端口號,這三個元素由SOCKADDR_IN結構體定義

為了簡化編程一般將IP地址設置為INADDR_ANY,如果需要使用特定的IP地址則需要使用inet_addr()** 和**inet_ntoa()函數

inet_addr()inet_ntoa()完成字符串和in_addr結構體的互換

inet_addr()函數參數cp代表點分十進制的IP地址,如1.2.3.4,返回值為in_addr_t 類型

/* Convert Internet host address from numbers-and-dots notation in CPinto binary data in network byte order.  */
extern in_addr_t inet_addr (const char *__cp) __THROW;

inet_ntoa() 函數輸入為in_addr結構體而輸出為字符串

/* Convert Internet number in IN to ASCII representation.  The return valueis a pointer to an internal array containing the string.  */
extern char *inet_ntoa (struct in_addr __in) __THROW;

hostent結構體

hostent實例詳解

/* Description of data base entry for a single host.  */
struct hostent
{char *h_name;			/* Official name of host.  */char **h_aliases;		/* Alias list.  */int h_addrtype;		/* Host address type.  */int h_length;			/* Length of address.  */char **h_addr_list;		/* List of addresses from name server.  */
#ifdef __USE_MISC
# define	h_addr	h_addr_list[0] /* Address, for backward compatibility.*/
#endif
};
struct hostent{char *h_name;         //正式主機名char **h_aliases;     //主機別名int h_addrtype;       //主機IP地址類型:IPV4-AF_INETint h_length;		      //主機IP地址字節長度,對于IPv4是四字節,即32位char **h_addr_list;	  //主機的IP地址列表};#define h_addr h_addr_list[0]   //保存的是IP地址
  • h_name:官方域名(Official domain name)。官方域名代表某一主頁,但實際上一些著名公司的域名并未用官方域名注冊
  • h_aliases:別名,可以通過多個域名訪問同一主機。同一 IP 地址可以綁定多個域名,因此除了當前域名還可以指定其他域名
  • h_addrtype:gethostbyname() 不僅支持 IPv4,還支持 IPv6,可以通過此成員獲取IP地址的地址族(地址類型)信息,IPv4 對應 AF_INET,IPv6 對應 AF_INET6
  • h_length:保存IP地址長度。IPv4 的長度為 4 個字節,IPv6 的長度為 16 個字節
  • h_addr_list:這是最重要的成員。通過該成員以整數形式保存域名對應的 IP 地址。對于用戶較多的服務器,可能會分配多個 IP 地址給同一域名,利用多個服務器進行均衡負載

在這里插入圖片描述

在實際的應用中,一臺服務器往往有好幾個IP地址,而域名只有一個,這樣設計的好處是,可以使系統分布設計,提升服務器的穩定性和抗災難能力

一般對服務器的訪問,則是先經過DNS(Domain Name System)服務器,DNS通過均衡設計,返回合適的IP與客戶端進行交互,避免客戶端只連接一個IP,導致網絡擁堵

gethostbyname()函數

gethostbyname()函數:通過域名獲取IP地址

gethostbyname()函數詳解

客戶端中直接使用IP地址會有很大的弊端,一旦IP地址變化(IP地址會經常變動),客戶端軟件就會出現錯誤
而使用域名會方便很多,注冊后的域名只要每年續費就永遠屬于自己的,更換IP地址時修改域名解析即可,不會影響軟件的正常使用

域名僅僅是 IP 地址的一個助記符,目的是方便記憶,通過域名并不能找到目標計算機,通信之前必須要將域名轉換成 IP 地址

gethostbyname() 函數可以完成這種轉換

/* Return entry from host data base for host with NAME.This function is a possible cancellation point and therefore notmarked with __THROW.  */
extern struct hostent *gethostbyname (const char *__name);

bind()函數

服務端用于將把用于通信的地址和端口綁定到socket上

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

sockfd:需要綁定的socket

addr:存放了服務端用于通信的地址和端口

addrlen:表示addr結構體的大小

返回值:成功則返回0,失敗返回-1,錯誤原因存于errno中

如果綁定的地址錯誤,或端口已被占用,bind函數一定會報錯,否則一般不會返回錯誤

💡 注意第二個參數為sockaddr結構體指針

在這里插入圖片描述

listen()函數

listen函數使用主動連接套接口變為被連接套接口,使得一個進程可以接受其它進程的請求,從而成為一個服務器進程

在TCP服務器編程中listen函數把進程變為一個服務器,并指定相應的套接字變為被動連接

/* Prepare to accept connections on socket FD.N connection requests will be queued before further requests are refused.Returns 0 on success, -1 for errors.  */
extern int listen (int __fd, int __n) __THROW;

_fd:服務端的socket,標識綁定的,未連接的套接字的描述符

-n:掛起的連接隊列的最大長度

  • 比如有100個用戶鏈接請求,但是系統一次只能處理20個,那么剩下的80個不能不理人家,所以系統就創建個隊列記錄這些暫時不能處理,一會兒處理的連接請求,依先后順序處理,那這個隊列到底多大?就是這個參數設置,比如2,那么就允許兩個新鏈接排隊。這個不能無限大,那內存就不夠了
  • 可以手動設置這個參數,但是別太大
  • 我們一般填寫這個參數為SOMAXCONN ,讓系統自動選擇最合適的個數

connect()函數

#include <sys/types.h> 					
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);參數:
第一個參數:int sockdf:socket文件描述符
第二個參數: const struct sockaddr *addr:傳入參數,指定服務器端地址信息,含IP地址和端口號
第三個參數:socklen_t addrlen:傳入參數,傳入sizeof(addr)大小
返回值:成功: 0失敗:-1,設置errno

當客戶端調用 connect()函數之后,發生一下情況之一才會返回(完成函數調用)

  • 服務器端接收連接請求
  • 發生斷網的異常情況而終端連接請求

需要注意的是,所謂的“接收連接”并不意味著服務器調用 accept()函數,其實是服務器端把連接請求信息記錄到等待隊列,因此 connect()函數返回后并不進行數據交換,而是要等服務器端 accept 之后才能進行數據交換(read、write)

客戶端端需要調用connect()連接服務器,connect和bind的參數形式一致,區別在于bind的參數是自己的地址,而connect的參數是對方的地址

accept()函數

socket的accept函數解析

socket中accept()函數的理解

/* Await a connection on socket FD.When a connection arrives, open a new socket to communicate with it,set *ADDR (which is *ADDR_LEN bytes long) to the address of the connectingpeer and *ADDR_LEN to the address's actual length, and return thenew socket's descriptor, or -1 for errors.This function is a cancellation point and therefore not marked with__THROW.  */
extern int accept (int __fd, __SOCKADDR_ARG __addr,socklen_t *__restrict __addr_len);

在這里插入圖片描述

send()函數

send函數用于把數據通過socket發送給對端

不論是客戶端還是服務端,應用程序都用send函數來向TCP連接的另一端發送數據

ssize_t send(int sockfd, const void *buf, size_t len, int flags);
  • sockfd為已建立好連接的socket
  • buf為需要發送的數據的內存地址,可以是C語言基本數據類型變量的地址,也可以數組、結構體、字符串,內存中有什么就發送什么
  • len需要發送的數據的長度,為buf中有效數據的長度
  • flags填0,其他數值意義不大
  • 函數返回已發送的字符數,出錯時返回-1,錯誤信息errno被標記
  • 注意,就算是網絡斷開,或socket已被對端關閉,send函數不會立即報錯,要過幾秒才會報錯
  • 如果send函數返回的錯誤(<=0),表示通信鏈路已不可用

recv()函數

recv函數用于接收對端通過socket發送過來的數據

不論是客戶端還是服務端,應用程序都用recv函數接收來自TCP連接的另一端發送過來數據

ssize_t recv(int sockfd, void *buf, size_t len, int flags);

參數信息同send()函數

函數返回已接收的字符數,出錯時返回-1,失敗時不會設置errno的值

  • 如果socket的對端沒有發送數據,recv函數就會等待
  • 如果對端發送了數據,函數返回接收到的字符數
  • 出錯時返回-1,如果socket被對端關閉,返回值為0
  • 如果recv函數返回的錯誤(<=0),表示通信通道已不可用

💡 數據收發時的數據量會受到發送緩沖區和接收緩沖區大小的限制
數據收發時要注意字節序的問題(不同主機字節序的問題)

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

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

相關文章

抓大鵝教程電腦端秒通關……

大家好&#xff0c;我是小黃。 最近抓大鵝小程序游戲很火&#xff0c;抓大鵝小游戲是由青島藍飛互娛科技股份有限公司開發并推出的一款休閑益智類三消游戲。在游戲中&#xff0c;玩家需要在特定的“購物籃子”背景下&#xff0c;找到三個相同的物品并將其消除。游戲的玩法簡單…

社工庫信息查詢

此網站需要注冊賬號&#xff0c;新用戶注冊送3點券&#xff0c;每日簽到可獲得1.5點券。也可通過充值來查 我這里有方法可以利用缺陷來無限獲取點券查人

Python 實戰之量化交易

1. Python 實戰之量化交易 2..Python量化交易實戰-04.量化交易系統架構的設計 Python量化交易實戰-04.量化交易系統架構的設計 - 知乎 3.Python量化交易實戰-06.通過PythonAPI獲取股票數據 Python量化交易實戰-06.通過PythonAPI獲取股票數據 - 知乎 3.Python量化交易實戰…

程序員的歸宿。。

大家好&#xff0c;我是瑤琴呀。 相信每個進入職場的人都考慮過自己的職業生涯規劃&#xff0c;在不同的年齡段可能面臨不同挑戰&#xff0c;這點對于 35 的人應該更為感同身受。 對于程序員來說&#xff0c;大部分人的職業道路主要是下面三種&#xff1a;第一條&#xff0c;…

【Delphi 爬蟲庫 6】使用正則表達式提取貓眼電影排行榜top100

正則表達式庫的簡單介紹 正則表達式易于使用&#xff0c;功能強大&#xff0c;可用于復雜的搜索和替換以及基于模板的文本檢查。這對于輸入形式的用戶輸入驗證特別有用-驗證電子郵件地址等。您還可以從網頁或文檔中提取電話號碼&#xff0c;郵政編碼等&#xff0c;在日志文件中…

人生是曠野,不是軌道

最近看到一句話&#xff0c;很喜歡&#xff0c;分享一下。"人生是曠野&#xff0c;不是軌道"。人生不是固定的方程式&#xff0c;也沒有唯一答案&#xff0c;沒有誰生來就應該是什么樣。別太被太多世俗觀念束縛住手腳&#xff0c;每個人都有權利自由生長&#xff0c;…

用友暢捷通T+ keyEdit sql注入漏洞

產品介紹 暢捷通 T 是一款靈動&#xff0c;智慧&#xff0c;時尚的基于互聯網時代開發的管理軟件&#xff0c;主要針對中小型工貿與商貿企業&#xff0c;尤其適合有異地多組織機構&#xff08;多工廠&#xff0c;多倉庫&#xff0c;多辦事處&#xff0c;多經銷商&#xff09;的…

朋友圈刷屏的粘土風格照片,你體驗過了嗎?

Remini 的粘土風格真的丑萌丑萌的&#xff01; 從去年“妙鴨相機”的走紅&#xff0c;到今年Remini的刷屏&#xff0c;其實可以看出大眾對于圖片趣玩的興趣非常大&#xff01; 一張普通的照片經過工具的處理&#xff0c;一下子變成新風格&#xff0c;讓人眼前一亮。如果你也對…

GPT-SoVits:語音克隆,語音融合

首發網站 https://tianfeng.space 前言 零樣本文本到語音&#xff08;TTS&#xff09;&#xff1a; 輸入 5 秒的聲音樣本&#xff0c;即刻體驗文本到語音轉換。少樣本 TTS&#xff1a; 僅需 1 分鐘的訓練數據即可微調模型&#xff0c;提升聲音相似度和真實感。跨語言支持&…

信息收集方法合集 第1期

前言 在工作中&#xff0c;經常被問到某個文件怎么下載&#xff0c;原文來自哪里。索性把我知道的所有信息收集方法全部整理一遍&#xff0c;希望對大家有用&#xff0c;如果有幫助到你&#xff0c;非常榮幸&#xff0c;我會堅持分享我的學習、工作經驗。 信息種類&#xff1…

如何用java編寫一個猜數字游戲

我想到用c能編出一個猜數字游戲&#xff0c;于是我就嘗試用java編寫一個 代碼如下&#xff1a; import java.util.Scanner; import java.util.Random;public class GuessTheNumber {public static void main(String[] args) {Scanner scanner new Scanner(System.in);Random…

云啟未來:“云計算與網絡運維精英交流群”與“獨家資料”等你來探索“

作者簡介&#xff1a;一名云計算網絡運維人員、每天分享網絡與運維的技術與干貨。 公眾號&#xff1a;網絡豆云計算學堂 座右銘&#xff1a;低頭趕路&#xff0c;敬事如儀 個人主頁&#xff1a; 網絡豆的主頁????? &#x1f680; 云計算與運維精英交流群誠邀您的加入…

搭建Docker私服鏡像倉庫Harbor

1、概述 Harbor是由VMware公司開源的企業級的Docker Registry管理項目&#xff0c;它包括權限管理(RBAC)、LDAP、日志審核、管理界面、自我注冊、鏡像復制和中文支持等功能。 Harbor 的所有組件都在 Dcoker 中部署&#xff0c;所以 Harbor 可使用 Docker Compose 快速部署。 …

PermissionError: [Errno 13] Permission denied: ‘xx.xlsx‘的解決辦法

我在轉換文件的時候遇到這個報錯&#xff0c;原因是文件名與已有文件名重復了 解決辦法很簡單&#xff0c;如下圖把" " 里的名字換成不重復的&#xff0c;再次允許代碼&#xff0c;會恢復正常

ue引擎游戲開發筆記(37)——實現敵人接收攻擊傷害,并作出反應

1.需求分析&#xff1a; 現在已經顯示造成實際傷害&#xff0c;但敵人對實際傷害并未產生反饋&#xff0c;例如還擊&#xff0c;或者死亡倒地等等&#xff0c;實現敵人對于受擊的反饋。 2.操作實現&#xff1a; 1.思路&#xff1a;在動畫藍圖中添加死亡動畫&#xff0c;并通過…

【姿態解算與濾波算法】

姿態解算 一、主線 姿態表示方式&#xff1a;矩陣表示&#xff0c;軸角表示&#xff0c;歐拉角表示&#xff0c;四元數表示。 慣性測量單元IMU&#xff08;Inertial Measurement Unit&#xff09;&#xff1a;MPU6050芯片&#xff0c;包含陀螺儀和加速度計&#xff0c;分別測…

winhex工具,將文件轉換為16進制數據放入代碼。

今天介紹winhex工具&#xff0c;可以將任何內容讀取讀取為16進制數據。下面看下效果。 下載鏈接&#xff1a; WinHex: Hex Editor & Disk Editor, Computer Forensics & Data Recovery Software 一、WinHex打開文件 我們要打開的文件&#xff1a; 打開后&#xff1a; 我…

服務器遠程桌面局域網連接不上的解決方法

在企業網絡環境中&#xff0c;服務器遠程桌面局域網連接不上是一個常見且棘手的問題。這種問題可能導致工作效率下降&#xff0c;甚至影響業務運營。因此&#xff0c;我們需要采取專業的方法來解決這一問題。 服務器遠程桌面局域網連接不上的解決方法&#xff1a; 1、確保服務器…

SQL注入-通達OA SQL注入漏洞【CVE-2023-4166】原理及檢測思路分析

1、漏洞描述 通達OA中發現一個漏洞&#xff0c;并被列為嚴重漏洞。該漏洞影響文件general/system/seal_manage/dianju/delete_log.php的未知代碼。對參數 DELETE_STR 的操作會導致 sql 注入。 2、影響范圍 通達OA版本11.10之前 3、復現環境 FOFA搜索&#xff1a;app"TDX…

解鎖網站SEO優勢,百度站長工具助您一臂之力(百度站長平臺還提供了哪些工具供seo人員使用?)

在當今數字化時代&#xff0c;網站已經成為企業宣傳、產品銷售、信息發布的主要渠道之一。有著再好的網站&#xff0c;如果在百度等搜索引擎中無法被用戶搜索到&#xff0c;那就等于白搭。因此&#xff0c;網站的SEO優化顯得尤為重要。而作為國內最大的搜索引擎&#xff0c;百度…