LINUX網絡編程API原型詳細解析

1. 網絡體系

1.1. 簡介? ? ? ??

????????網絡采用分而治之的方法設計,將網絡的功能劃分為不同的模塊,以分層的形式有機組合在一起。 每層實現不同的功能,其內部實現方法對外部其他層次來說是透明的。每層向上層提供服務,同時使用下層提供的服務 網絡體系結構即指網絡的層次結構和每層所使用協議的集合 兩類非常重要的體系結構:OSI與TCP/IP.

1.1.1. OSI開放系統互聯模型

????????OSI模型相關的協議已經很少使用,但模型本身非常通用 OSI模型是一個理想化的模型,尚未有完整的實現 OSI模型共有七層.

1.1.2.?TCP/IP協議族的體系結構

????????TCP/IP協議是Internet事實上的工業標準。 一共有四層

1.1.3. TCP協議通信模型

1.1.4. TCP/IP協議下的數據包

1.1.5. 數據的封裝與傳遞過程

1.1.6.?TCP/IP結構

1.1.7. TCP協議特點

????????TCP(即傳輸控制協議):是一種面向連接的傳輸層協議,它能提供高可靠性通信(即數據無誤、數據無丟失、數據無失序、數據無重復到達的通信) 適用情況: 適合于對傳輸質量要求較高,以及傳輸大量數據的通信。 在需要可靠數據傳輸的場合,通常使用TCP協議 MSN/QQ等即時通訊軟件的用戶登錄賬戶管理相關的功能通常采用TCP協議.

1.1.8. UDP協議特點

????????UDP(User Datagram Protocol)用戶數據報協議,是不可靠的無連接的協議。在數據發送前,因為不需要進行連接,所以可以進行高效率的數據傳輸。 適用情況: 發送小尺寸數據(如對DNS服務器進行IP地址查詢時) 在接收到數據,給出應答較困難的網絡中使用UDP。(如:無線網絡) 適合于廣播/組播式通信中。 MSN/QQ/Skype等即時通訊軟件的點對點文本通訊以及音視頻通訊通常采用UDP協議 流媒體、VOD、VoIP、IPTV等網絡多媒體服務中通常采用UDP方式進行實時數據傳輸.

1.2.?TCP/IP網絡編程預備知識

1.2.1. Socket

????????Socket 是一個編程接口 是一種特殊的文件描述符 (everything in Unix is a file) 并不僅限于TCP/IP協議 面向連接 (Transmission Control Protocol - TCP/IP) 無連接 (User Datagram Protocol -UDP 和 Inter-network Packet Exchange - IPX).

1.2.1.1.??Socket類型

????????流式套接字(SOCK_STREAM) 提供了一個面向連接、可靠的數據傳輸服務,數據無差錯、無重復的發送且按發送順序接收。內設置流量控制,避免數據流淹沒慢的接收方。數據被看作是字節流,無長度限制。 數據報套接字(SOCK_DGRAM) 提供無連接服務。數據包以獨立數據包的形式被發送,不提供無差錯保證,數據可能丟失或重復,順序發送,可能亂序接收。 原始套接字(SOCK_RAW) 可以對較低層次協議如IP、ICMP直接訪問.

1.2.1.2.??Socket的位置

1.2.2.? IP地址

????????IP地址是Internet中主機的標識 Internet中的主機要與別的機器通信必須具有一個IP地址 IP地址為32位(IPv4)或者128位(IPv6) 每個數據包都必須攜帶目的IP地址和源IP地址,路由器依靠此信息為數據包選擇路由 表示形式:常用點分形式,如202.38.64.10,最后都會轉換為一個32位的無符號整數。 IP地址分類 子網掩碼.

1.2.3.? 端口號

????????為了區分一臺主機接收到的數據包應該轉交給哪個進程來進行處理,使用端口號來區別 TCP端口號與UDP端口號獨立 端口號一般由IANA (Internet Assigned Numbers Authority) 管理 眾所周知端口:1~1023(1~255之間為眾所周知端口,256~1023端口通常由UNIX系統占用) 注冊端口:1024~49150 動態或私有端口:49151~65535.

1.2.4. 字節序

????????不同類型CPU的主機中,內存存儲多字節整數序列有兩種方法,稱為主機字節序(HBO): 小端序(little-endian) - 低序字節存儲在低地址 將低字節存儲在起始地址,稱為“Little-Endian”字節序,Intel、AMD等采用的是這種方式; 大端序(big-endian)- 高序字節存儲在低地址 將高字節存儲在起始地址,稱為“Big-Endian”字節序,由ARM、Motorola等所采用 網絡中傳輸的數據必須按網絡字節序,即大端字節序 在大部分PC機上,當應用進程將整數送入socket前,需要轉化成網絡字節序;當應用進程從socket取出整數后,要轉化成小端字節序.

????????網絡字節序(NBO - Network Byte Order) 使用統一的字節順序,避免兼容性問題 主機字節序(HBO - Host Byte Order) 不同的機器HBO是不一樣的,這與CPU的設計有關 Motorola 68K系列、ARM系列,HBO與NBO是一致的 Intel X86系列,HBO與NBO不一致.

????????大端(Big-Endian):字節的高位在內存中放在存儲單元的起始位置.

?1.2.5. 字節序轉換函數

????????把給定系統所采用的字節序稱為主機字節序。為了避免不同類別主機之間在數據交換時由于對于字節序的不同而導致的差錯,引入了網絡字節序。

????????主機字節序到網絡字節序:

???????????????? u_long htonl (u_long hostlong);

????????????????u_short htons (u_short short);

????????網絡字節序到主機字節序:

???????? ????????u_long ntohl (u_long hostlong);

????????????????u_short ntohs (u_short short);

1.2.6. IP地址的轉換

????????inet_aton( )

????????????????將strptr所指的字符串轉換成32位的網絡字節序二進制值

????????????????#include <arpa/inet.h> int inet_aton(const char *strptr, struct in_addr *addrptr); ????????inet_addr( )

????????????????功能同上,返回轉換后的地址。

????????????????int_addr_t inet_addr(const char *strptr);

????????inet_ntoa( )

????????????????將32位網絡字節序二進制地址轉換成點分十進制的字符串。

????????????????char *inet_ntoa(stuct in_addr inaddr);

????????inet_pton()

????????????????將IPV4/IPV6的地址轉換成binary格式 ?? ?

????????????????int inet_pton(int af, const char *src, void *dst);

2. 系統調用

2.1.?網絡編程相關API

2.1.1.?網絡編程常用函數

  • socket() 創建套接字
  • bind() 綁定本機地址和端口
  • connect() 建立連接
  • listen() 設置監聽端口
  • accept() 接受TCP連接
  • recv(), read(), recvfrom() 數據接收
  • send(), write(), sendto() 數據發送
  • close(), shutdown() 關閉套接字

2.1.2.?socket創建套接字

int socket(int domain, int type, int protocol);參數說明
domain (協議域):描述: 指定通信的協議域,即通信的地址族。
常見值:
AF_INET: IPv4協議族。
AF_INET6: IPv6協議族。
AF_UNIX 或 AF_LOCAL: 本地通信協議族,用于進程間通信(IPC)。
type (套接字類型):描述: 指定套接字的類型,即通信的語義。
常見值:
SOCK_STREAM: 提供面向連接的、可靠的、雙向的、基于字節流的通信(如TCP)。
SOCK_DGRAM: 提供無連接的、不可靠的、基于數據報的通信(如UDP)。
SOCK_RAW: 提供原始網絡協議訪問。
SOCK_SEQPACKET: 提供面向連接的、可靠的、雙向的、基于記錄的通信。
protocol (協議):描述: 指定使用的具體協議。通常情況下,可以設置為0,表示使用默認協議。
常見值:
0: 使用默認協議。例如,對于AF_INET和SOCK_STREAM,默認協議是TCP;對于AF_INET和SOCK_DGRAM,默認協議是UDP。
具體協議值可以通過getprotobyname函數獲取,但通常情況下設置為0即可。
返回值說明
成功:返回一個非負整數,表示新創建的套接字描述符(socket file descriptor)。
套接字描述符是一個整數,用于在后續的套接字操作中標識該套接字。
失敗:返回-1,并設置errno以指示錯誤類型。
常見的錯誤碼包括:
EAFNOSUPPORT: 指定的協議域不受支持。
EPROTONOSUPPORT: 指定的協議不受支持。
ESOCKTNOSUPPORT: 指定的套接字類型不受支持。
ENOBUFS 或 ENOMEM: 內存不足,無法創建套接字。

2.1.3. 地址相關的數據結構

通用地址結構struct sockaddr{    u_short  sa_family;    // 地址族, AF_xxxchar  sa_data[14];     // 14字節協議地址};Internet協議地址結構struct sockaddr_in{           u_short sin_family;      // 地址族, AF_INET,2 bytesu_short sin_port;      // 端口,2 bytesstruct in_addr sin_addr;  // IPV4地址,4 bytes 	char sin_zero[8];        // 8 bytes unused,作為填充}; 
IPv4地址結構
// internet address  
struct in_addr
{in_addr_t  s_addr;            // u32 network address 
};

2.1.4. bind綁定本機地址和端口

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
參數說明
sockfd (套接字描述符):描述: 表示要綁定的套接字的文件描述符。
類型: int
說明: 這個文件描述符通常是通過socket函數創建的。
addr (地址結構體指針):描述: 指向包含地址信息的struct sockaddr結構體的指針。
類型: const struct sockaddr *
說明: 這個結構體的具體類型取決于domain參數(例如,AF_INET使用struct sockaddr_in,AF_INET6使用struct sockaddr_in6)。
示例:
對于IPv4地址,通常使用struct sockaddr_in:struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(8888);
addr.sin_addr.s_addr = inet_addr("192.168.1.100");
對于IPv6地址,通常使用struct sockaddr_in6:struct sockaddr_in6 addr;
addr.sin6_family = AF_INET6;
addr.sin6_port = htons(8888);
inet_pton(AF_INET6, "2001:db8::1", &addr.sin6_addr);
addrlen (地址結構體長度):描述: 指定addr參數指向的地址結構體的長度。
類型: socklen_t
說明: 這個參數通常通過sizeof運算符獲取。
示例:
對于struct sockaddr_in:socklen_t addrlen = sizeof(struct sockaddr_in);
對于struct sockaddr_in6:socklen_t addrlen = sizeof(struct sockaddr_in6);
返回值說明
成功:返回0,表示綁定成功。
失敗:返回-1,并設置errno以指示錯誤類型。
常見的錯誤碼包括:
EBADF: sockfd不是一個有效的文件描述符。
ENOTSOCK: sockfd不是一個套接字。
EADDRINUSE: 指定的地址已經被其他套接字使用。
EADDRNOTAVAIL: 指定的地址不可用。
EFAULT: addr指向的內存區域不可訪問。
EINVAL: addrlen不正確或addr指向的地址結構體不正確。
EACCES: 權限不足,無法綁定到指定的地址。

2.1.5. 地址結構的一般用法

// 定義并清空 sockaddr_in 類型的變量
memset(&myaddr, 0, sizeof(myaddr)); // 清空 myaddr 結構體// 填充地址信息
myaddr.sin_family = AF_INET; // 設置協議族為 IPv4
myaddr.sin_port = htons(8888); // 設置端口號,并轉換為主機字節序到網絡字節序
myaddr.sin_addr.s_addr = inet_addr("192.168.1.100"); // 設置服務器 IP 地址// 綁定套接字
if (bind(listenfd, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) {perror("bind failed"); // 打印錯誤信息close(listenfd);       // 關閉套接字return -1;             // 返回錯誤碼
}

2.1.6.?地址轉換函數

unsigned long inet_addr(char *address);address是以’\0’結尾的點分IPv4字符串。該函數返回32位的地址。如果字符串包含的不是合法的IP地址,則函數返回-1。例如:
struct in_addr addr;
addr.s_addr = inet_addr(" 192.168.1.100 ");char* inet_ntoa(struct in_addr address);address是IPv4地址結構,函數返回一指向包含點分IP地址的靜態存儲區字符指針。如果錯誤則函數返回NULL

2.1.7.?listen設置監聽端口

int listen(int sockfd, int backlog);
參數說明
sockfd (套接字描述符):描述: 表示要監聽的套接字的文件描述符。
類型: int
說明: 這個文件描述符通常是通過socket函數創建的,并且已經通過bind函數綁定到一個地址和端口。
backlog (最大連接隊列長度):描述: 指定等待接受(accept)的連接隊列的最大長度。
類型: int
說明:
backlog參數定義了內核為相應套接字排隊的最大連接數。
當多個客戶端同時嘗試連接到服務器時,這些連接會被放入一個隊列中等待處理。
如果隊列已滿,新的連接請求可能會被拒絕。
常見的backlog值為5、10或20,具體值可以根據實際需求調整。
返回值說明
成功:返回0,表示監聽成功。
失敗:返回-1,并設置errno以指示錯誤類型。
常見的錯誤碼包括:
EBADF: sockfd不是一個有效的文件描述符。
ENOTSOCK: sockfd不是一個套接字。
EOPNOTSUPP: sockfd不支持監聽操作。
EADDRINUSE: 地址已經被其他套接字使用。
EINVAL: sockfd已經處于監聽狀態,或者backlog參數無效。
EACCES: 權限不足,無法監聽指定的地址。

????????注意:完成listen()調用后,socket變成了監聽socket(listening socket).

2.1.8.?accept接受TCP連接

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
參數說明
sockfd (監聽套接字描述符):描述: 表示要接受連接的監聽套接字的文件描述符。
類型: int
說明: 這個文件描述符通常是通過socket函數創建的,并且已經通過bind函數綁定到一個地址和端口,然后通過listen函數設置為監聽狀態。
addr (客戶端地址結構體指針):描述: 指向一個struct sockaddr類型的結構體,用于存儲客戶端的地址信息。
類型: struct sockaddr *
說明:
如果不需要客戶端的地址信息,可以將此參數設置為NULL。
如果需要客戶端的地址信息,需要先定義一個適當的結構體(如struct sockaddr_in),然后將其強制轉換為struct sockaddr *類型。
例如,對于IPv4地址,可以使用struct sockaddr_in:struct sockaddr_in client_addr;
socklen_t client_addr_len = sizeof(client_addr);
int client_fd = accept(listenfd, (struct sockaddr *)&client_addr, &client_addr_len);
addrlen (地址結構體長度指針):描述: 指向一個socklen_t類型的變量,用于指定addr參數指向的地址結構體的長度。
類型: socklen_t *
說明:
在調用accept之前,需要初始化addrlen為地址結構體的實際大小。
例如,對于struct sockaddr_in,可以這樣做:struct sockaddr_in client_addr;
socklen_t client_addr_len = sizeof(client_addr);
int client_fd = accept(listenfd, (struct sockaddr *)&client_addr, &client_addr_len);
在accept返回后,addrlen會被設置為實際存儲的客戶端地址信息的長度。
返回值說明
成功:返回一個新的套接字描述符,用于與客戶端通信。
失敗:返回-1,并設置errno以指示錯誤類型。
常見的錯誤碼包括:
EBADF: sockfd不是一個有效的文件描述符。
ENOTSOCK: sockfd不是一個套接字。
EOPNOTSUPP: sockfd不支持接受操作。
ECONNABORTED: 連接被中斷。
EINTR: 被信號中斷。
EMFILE: 進程打開的文件描述符數量達到限制。
ENFILE: 系統打開的文件描述符數量達到限制。
ENOMEM: 內存不足,無法創建新的套接字。

2.1.9.?connect?建立連接

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
參數說明
sockfd (套接字描述符):描述: 表示要連接的套接字的文件描述符。
類型: int
說明: 這個文件描述符通常是通過socket函數創建的,但尚未連接到任何遠程地址。
addr (服務器地址結構體指針):描述: 指向一個struct sockaddr類型的結構體,用于存儲服務器的地址信息。
類型: const struct sockaddr *
說明:
必須提供一個有效的服務器地址結構體,通常使用struct sockaddr_in(對于IPv4)或struct sockaddr_in6(對于IPv6)。
例如,對于IPv4地址,可以使用struct sockaddr_in:
c
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(8888);
server_addr.sin_addr.s_addr = inet_addr("192.168.1.100");
對于IPv6地址,可以使用struct sockaddr_in6:
c
struct sockaddr_in6 server_addr;
server_addr.sin6_family = AF_INET6;
server_addr.sin6_port = htons(8888);
inet_pton(AF_INET6, "2001:db8::1", &server_addr.sin6_addr);
addrlen (地址結構體長度):描述: 指定addr參數指向的地址結構體的長度。
類型: socklen_t
說明: 這個參數通常通過sizeof運算符獲取。
示例:
對于struct sockaddr_in:socklen_t addrlen = sizeof(struct sockaddr_in);
對于struct sockaddr_in6:socklen_t addrlen = sizeof(struct sockaddr_in6);
返回值說明
成功:返回0,表示連接成功。
失敗:返回-1,并設置errno以指示錯誤類型。
常見的錯誤碼包括:
EBADF: sockfd不是一個有效的文件描述符。
ENOTSOCK: sockfd不是一個套接字。
EADDRINUSE: 本地地址已經被其他套接字使用。
EADDRNOTAVAIL: 本地地址不可用。
EAFNOSUPPORT: 地址族不支持。
EALREADY: 套接字是非阻塞的,并且連接操作正在進行中。
ECONNREFUSED: 連接被服務器拒絕。
EISCONN: 套接字已經連接。
ENETUNREACH: 網絡不可達。
ETIMEDOUT: 連接超時。
EHOSTUNREACH: 主機不可達。
EINPROGRESS: 套接字是非阻塞的,并且連接操作正在進行中。
EINTR: 被信號中斷。
EACCES: 權限不足,無法連接到指定的地址。

2.1.10. send數據發送

ssize_t send(int socket, const void *buffer, size_t length, int flags);
參數說明
socket (套接字描述符):描述: 表示要發送數據的套接字的文件描述符。
類型: int
說明: 這個文件描述符通常是通過socket函數創建的,并且已經通過connect函數連接到遠程地址(對于TCP)或準備好發送數據(對于UDP)。
buffer (數據緩沖區):描述: 指向包含要發送數據的緩沖區的指針。
類型: const void *
說明:
buffer指向的數據可以是任意類型,但通常是一個字節數組。
使用const void *表示send函數不會修改緩沖區中的數據。
length (數據長度):描述: 指定要發送的數據長度(以字節為單位)。
類型: size_t
說明:
length參數指定buffer中要發送的字節數。
通常使用strlen函數獲取字符串的長度,但要注意strlen不包括字符串結束符\0。
flags (標志位):描述: 指定發送操作的行為。
類型: int
說明:
flags參數可以是0,表示默認行為。
常見的標志位包括:
MSG_DONTROUTE: 不使用路由表查找目標地址。
MSG_OOB: 發送帶外數據(僅適用于支持帶外數據的協議,如TCP)。
MSG_NOSIGNAL: 如果發送操作導致對端關閉連接,不發送SIGPIPE信號。
MSG_CONFIRM: 確認連接(僅適用于某些協議)。
返回值說明
成功:返回實際發送的字節數(ssize_t類型)。
返回值可能小于length,表示部分數據已發送。
失敗:返回-1,并設置errno以指示錯誤類型。
常見的錯誤碼包括:
EBADF: socket不是一個有效的文件描述符。
ENOTSOCK: socket不是一個套接字。
EAGAIN 或 EWOULDBLOCK: 套接字是非阻塞的,并且當前不可寫。
EDESTADDRREQ: 目標地址未指定(對于無連接的套接字,如UDP)。
EINTR: 發送操作被信號中斷。
EINVAL: flags參數無效。
EISCONN: 套接字已經連接(對于無連接的套接字,如UDP)。
EMSGSIZE: 發送的數據長度超過協議允許的最大值。
ENOBUFS 或 ENOMEM: 內存不足,無法發送數據。
ENOTCONN: 套接字未連接(對于面向連接的套接字,如TCP)。
EPIPE: 對端關閉了連接(僅適用于面向連接的套接字,如TCP),并且flags未設置MSG_NOSIGNAL。

2.1.11. recv數據接收

ssize_t recv(int socket, void *buffer, size_t length, int flags);
參數說明
socket (套接字描述符):描述: 表示要接收數據的套接字的文件描述符。
類型: int
說明: 這個文件描述符通常是通過socket函數創建的,并且已經通過bind和listen函數設置為監聽狀態(對于TCP服務器),或者已經通過connect函數連接到遠程地址(對于TCP客戶端或UDP套接字)。
buffer (數據緩沖區):描述: 指向用于存儲接收到的數據的緩沖區的指針。
類型: void *
說明:
buffer指向的數據可以是任意類型,但通常是一個字節數組。
recv函數會將接收到的數據存儲在這個緩沖區中。
length (緩沖區長度):描述: 指定緩沖區的最大長度(以字節為單位),即最多可以接收的數據量。
類型: size_t
說明:
length參數指定buffer可以存儲的最大字節數。
通常設置為緩沖區的實際大小減1,以確保有足夠的空間存儲字符串結束符\0(如果需要)。
flags (標志位):描述: 指定接收操作的行為。
類型: int
說明:
flags參數可以是0,表示默認行為。
常見的標志位包括:
MSG_DONTWAIT: 非阻塞模式,如果數據不可用,立即返回EAGAIN或EWOULDBLOCK。
MSG_OOB: 接收帶外數據(僅適用于支持帶外數據的協議,如TCP)。
MSG_PEEK: 查看數據而不從緩沖區中移除。
MSG_TRUNC: 返回實際接收的數據長度,即使數據被截斷。
MSG_WAITALL: 等待直到接收指定數量的數據(僅適用于面向連接的套接字,如TCP)。
返回值說明
成功:返回實際接收的字節數(ssize_t類型)。
返回值可能小于length,表示部分數據已接收。
失敗:返回-1,并設置errno以指示錯誤類型。
常見的錯誤碼包括:
EBADF: socket不是一個有效的文件描述符。
ENOTSOCK: socket不是一個套接字。
EAGAIN 或 EWOULDBLOCK: 套接字是非阻塞的,并且當前沒有數據可讀。
EINTR: 接收操作被信號中斷。
EINVAL: flags參數無效。
ENOMEM: 內存不足,無法接收數據。
ENOTCONN: 套接字未連接(對于面向連接的套接字,如TCP)。
EFAULT: buffer指向的內存區域不可訪問。

2.1.12.?read數據接收/write數據發送

????????read()和write()經常會代替recv()和send(),通常情況下,看自己的的偏好使用read()/write()和recv()/send()時最好統一.

ssize_t read(int fd, void *buf, size_t count);
參數說明
fd (文件描述符):描述: 表示要讀取數據的文件描述符。
類型: int
說明: 這個文件描述符可以是任何類型的文件描述符,包括套接字、文件、管道等。
buf (數據緩沖區):描述: 指向用于存儲讀取數據的緩沖區的指針。
類型: void *
說明:
buf指向的數據可以是任意類型,但通常是一個字節數組。
read函數會將讀取的數據存儲在這個緩沖區中。
count (數據長度):描述: 指定要讀取的最大字節數。
類型: size_t
說明:
count參數指定buf可以存儲的最大字節數。
實際讀取的字節數可能小于count,具體取決于文件或套接字的狀態。
返回值說明
成功:返回實際讀取的字節數(ssize_t類型)。
返回值可能小于count,表示部分數據已讀取。
失敗:返回-1,并設置errno以指示錯誤類型。
常見的錯誤碼包括:
EBADF: fd不是一個有效的文件描述符。
EAGAIN 或 EWOULDBLOCK: 文件描述符是非阻塞的,并且當前沒有數據可讀。
EINTR: 讀取操作被信號中斷。
EINVAL: buf指向的內存區域不可訪問。
EIO: I/O 錯誤。
EFAULT: buf指向的內存區域不可訪問。
EISDIR: fd是一個目錄。
ECONNRESET: 連接被對端重置(僅適用于套接字)。
ssize_t write(int fd, const void *buf, size_t count);
參數說明
fd (文件描述符):描述: 表示要寫入數據的文件描述符。
類型: int
說明: 這個文件描述符可以是任何類型的文件描述符,包括套接字、文件、管道等。
buf (數據緩沖區):描述: 指向包含要寫入數據的緩沖區的指針。
類型: const void *
說明:
buf指向的數據可以是任意類型,但通常是一個字節數組。
write函數不會修改緩沖區中的數據。
count (數據長度):描述: 指定要寫入的最大字節數。
類型: size_t
說明:
count參數指定buf中要寫入的字節數。
實際寫入的字節數可能小于count,具體取決于文件或套接字的狀態。
返回值說明
成功:返回實際寫入的字節數(ssize_t類型)。
返回值可能小于count,表示部分數據已寫入。
失敗:返回-1,并設置errno以指示錯誤類型。
常見的錯誤碼包括:
EBADF: fd不是一個有效的文件描述符,或者不是打開用于寫入的文件描述符。
EAGAIN 或 EWOULDBLOCK: 文件描述符是非阻塞的,并且當前不可寫。
EINTR: 寫入操作被信號中斷。
EINVAL: buf指向的內存區域不可訪問。
EIO: I/O 錯誤。
EFAULT: buf指向的內存區域不可訪問。
ENOSPC: 設備上沒有足夠的空間寫入數據。
EPIPE: 對端關閉了連接(僅適用于套接字),并且fd未設置O_NONBLOCK。
示例代碼

2.1.13.?sendto數據發送/recvfrom數據接收

????????這兩個函數一般在使用UDP協議時使用.

ssize_t sendto(int socket, const void *message, size_t length, int flags, const struct sockaddr *dest_addr, socklen_t dest_len);
參數說明
socket (套接字描述符):描述: 表示要發送數據的套接字的文件描述符。
類型: int
說明: 這個文件描述符通常是通過socket函數創建的,并且可以是UDP套接字或未連接的TCP套接字。
message (數據緩沖區):描述: 指向包含要發送數據的緩沖區的指針。
類型: const void *
說明:
message指向的數據可以是任意類型,但通常是一個字節數組。
sendto函數不會修改緩沖區中的數據。
length (數據長度):描述: 指定要發送的數據長度(以字節為單位)。
類型: size_t
說明:
length參數指定message中要發送的字節數。
通常使用strlen函數獲取字符串的長度,但要注意strlen不包括字符串結束符\0。
flags (標志位):描述: 指定發送操作的行為。
類型: int
說明:
flags參數可以是0,表示默認行為。
常見的標志位包括:
MSG_DONTROUTE: 不使用路由表查找目標地址。
MSG_OOB: 發送帶外數據(僅適用于支持帶外數據的協議,如TCP)。
MSG_NOSIGNAL: 如果發送操作導致對端關閉連接,不發送SIGPIPE信號。
MSG_CONFIRM: 確認連接(僅適用于某些協議)。
dest_addr (目標地址結構體指針):描述: 指向包含目標地址信息的struct sockaddr類型的結構體的指針。
類型: const struct sockaddr *
說明:
這個結構體的具體類型取決于socket的協議族(例如,AF_INET使用struct sockaddr_in,AF_INET6使用struct sockaddr_in6)。
例如,對于IPv4地址,通常使用struct sockaddr_in:struct sockaddr_in dest_addr;
dest_addr.sin_family = AF_INET;
dest_addr.sin_port = htons(8888);
dest_addr.sin_addr.s_addr = inet_addr("192.168.1.100");
對于IPv6地址,通常使用struct sockaddr_in6:struct sockaddr_in6 dest_addr;
dest_addr.sin6_family = AF_INET6;
dest_addr.sin6_port = htons(8888);
inet_pton(AF_INET6, "2001:db8::1", &dest_addr.sin6_addr);
dest_len (目標地址結構體長度):描述: 指定dest_addr參數指向的地址結構體的長度。
類型: socklen_t
說明: 這個參數通常通過sizeof運算符獲取。
示例:
對于struct sockaddr_in:socklen_t dest_len = sizeof(struct sockaddr_in);
對于struct sockaddr_in6:socklen_t dest_len = sizeof(struct sockaddr_in6);
返回值說明
成功:返回實際發送的字節數(ssize_t類型)。
返回值可能小于length,表示部分數據已發送。
失敗:返回-1,并設置errno以指示錯誤類型。
常見的錯誤碼包括:
EBADF: socket不是一個有效的文件描述符。
ENOTSOCK: socket不是一個套接字。
EAGAIN 或 EWOULDBLOCK: 套接字是非阻塞的,并且當前不可寫。
EDESTADDRREQ: 目標地址未指定(對于無連接的套接字,如UDP)。
EINTR: 發送操作被信號中斷。
EINVAL: flags參數無效。
EMSGSIZE: 發送的數據長度超過協議允許的最大值。
ENOBUFS 或 ENOMEM: 內存不足,無法發送數據。
ENOTCONN: 套接字未連接(對于面向連接的套接字,如TCP)。
EPIPE: 對端關閉了連接(僅適用于面向連接的套接字,如TCP),并且flags未設置MSG_NOSIGNAL。
ssize_t recvfrom(int socket, void *buffer, size_t length, int flags, struct sockaddr *address, socklen_t *address_len);
參數說明
socket (套接字描述符):描述: 表示要接收數據的套接字的文件描述符。
類型: int
說明: 這個文件描述符通常是通過socket函數創建的,并且可以是UDP套接字或未連接的TCP套接字。
buffer (數據緩沖區):描述: 指向用于存儲接收到的數據的緩沖區的指針。
類型: void *
說明:
buffer指向的數據可以是任意類型,但通常是一個字節數組。
recvfrom函數會將接收到的數據存儲在這個緩沖區中。
length (緩沖區長度):描述: 指定緩沖區的最大長度(以字節為單位),即最多可以接收的數據量。
類型: size_t
說明:
length參數指定buffer可以存儲的最大字節數。
通常設置為緩沖區的實際大小減1,以確保有足夠的空間存儲字符串結束符\0(如果需要)。
flags (標志位):描述: 指定接收操作的行為。
類型: int
說明:
flags參數可以是0,表示默認行為。
常見的標志位包括:
MSG_DONTWAIT: 非阻塞模式,如果數據不可用,立即返回EAGAIN或EWOULDBLOCK。
MSG_OOB: 接收帶外數據(僅適用于支持帶外數據的協議,如TCP)。
MSG_PEEK: 查看數據而不從緩沖區中移除。
MSG_TRUNC: 返回實際接收的數據長度,即使數據被截斷。
MSG_WAITALL: 等待直到接收指定數量的數據(僅適用于面向連接的套接字,如TCP)。
address (源地址結構體指針):描述: 指向一個struct sockaddr類型的結構體,用于存儲發送方的地址信息。
類型: struct sockaddr *
說明:
如果不需要發送方的地址信息,可以將此參數設置為NULL。
如果需要發送方的地址信息,需要先定義一個適當的結構體(如struct sockaddr_in),然后將其強制轉換為struct sockaddr *類型。
例如,對于IPv4地址,可以使用struct sockaddr_in:struct sockaddr_in src_addr;
socklen_t src_addr_len = sizeof(src_addr);
ssize_t bytes_received = recvfrom(sockfd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&src_addr, &src_addr_len);
對于IPv6地址,可以使用struct sockaddr_in6:struct sockaddr_in6 src_addr;
socklen_t src_addr_len = sizeof(src_addr);
ssize_t bytes_received = recvfrom(sockfd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&src_addr, &src_addr_len);
address_len (源地址結構體長度指針):描述: 指向一個socklen_t類型的變量,用于指定address參數指向的地址結構體的長度。
類型: socklen_t *
說明:
在調用recvfrom之前,需要初始化address_len為地址結構體的實際大小。
例如,對于struct sockaddr_in,可以這樣做:struct sockaddr_in src_addr;
socklen_t src_addr_len = sizeof(src_addr);
ssize_t bytes_received = recvfrom(sockfd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&src_addr, &src_addr_len);
在recvfrom返回后,address_len會被設置為實際存儲的發送方地址信息的長度。
返回值說明
成功:返回實際接收的字節數(ssize_t類型)。
返回值可能小于length,表示部分數據已接收。
失敗:返回-1,并設置errno以指示錯誤類型。
常見的錯誤碼包括:
EBADF: socket不是一個有效的文件描述符。
ENOTSOCK: socket不是一個套接字。
EAGAIN 或 EWOULDBLOCK: 套接字是非阻塞的,并且當前沒有數據可讀。
EINTR: 接收操作被信號中斷。
EINVAL: flags參數無效。
ENOMEM: 內存不足,無法接收數據。
ENOTCONN: 套接字未連接(對于面向連接的套接字,如TCP)。
EFAULT: buffer或address指向的內存區域不可訪問。

2.1.14. close關閉套接字

????????關閉雙向通訊.

int close(int sockfd);
參數說明
sockfd (文件描述符):
描述: 表示要關閉的文件描述符。
類型: int
說明: 這個文件描述符可以是任何類型的文件描述符,包括套接字、文件、管道等。
返回值說明
成功:返回0,表示文件描述符關閉成功。
失敗:返回-1,并設置errno以指示錯誤類型。
常見的錯誤碼包括:
EBADF: sockfd不是一個有效的文件描述符。
EINTR: 關閉操作被信號中斷。

2.1.15. shutdown關閉套接字

????????TCP連接是雙向的(是可讀寫的),當我們使用close時,會把讀寫通道都關閉,有時侯我們希望只關閉一個方向,這個時候我們可以使用shutdown。 針對不同的howto,系統回采取不同的關閉方式。

int shutdown(int sockfd, int howto);
參數說明
sockfd (套接字描述符):描述: 表示要關閉的套接字的文件描述符。
類型: int
說明: 這個文件描述符通常是通過socket函數創建的,并且已經通過bind和listen函數設置為監聽狀態(對于TCP服務器),或者已經通過connect函數連接到遠程地址(對于TCP客戶端或UDP套接字)。
howto (關閉方式):描述: 指定關閉套接字的方式。
類型: int
說明:
howto參數可以是以下值之一:
SHUT_RD: 關閉套接字的接收端。后續對套接字的讀操作將立即返回0(表示EOF)。
SHUT_WR: 關閉套接字的發送端。后續對套接字的寫操作將返回EPIPE信號(對于TCP)。
SHUT_RDWR: 關閉套接字的接收端和發送端。等同于調用close(sockfd)。
返回值說明
成功:返回0,表示關閉操作成功。
失敗:返回-1,并設置errno以指示錯誤類型。
常見的錯誤碼包括:
EBADF: sockfd不是一個有效的文件描述符。
ENOTSOCK: sockfd不是一個套接字。
EINVAL: howto參數無效。
ENOTCONN: 套接字未連接(對于面向連接的套接字,如TCP)。

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

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

相關文章

藍橋杯 之 暴力回溯

文章目錄 數字接龍小u的最大連續移動次數問題迷宮 在藍橋杯中&#xff0c;十分喜歡考察對于網格的回溯的問題&#xff0c;對于這類的問題&#xff0c;常常會使用到這個DFS和BFS進行考察&#xff0c;不過無論怎么考察&#xff0c;都只是會在最基礎的模本的基礎上&#xff0c;根據…

微信小程序的業務域名配置(通過ingress網關的注解)

一、背景 微信小程序的業務域名配置&#xff08;通過kong網關的pre-function配置&#xff09;是依靠kong實現&#xff0c;本文將通過ingress網關實現。 而我們的服務是部署于阿里云K8S容器&#xff0c;當然內核與ingress無異。 找到k8s–>網絡–>路由 二、ingress注解 …

Python數據可視化工具:六西格瑪及其基礎工具概覽

在當今數據驅動的時代&#xff0c;數據分析和可視化工具成為了各行業優化流程、提升質量的關鍵手段。六西格瑪&#xff08;Six Sigma&#xff09;作為一種以數據為基礎、追求完美質量的管理理念&#xff0c;其實施依賴于一系列基礎工具的靈活運用。而Python&#xff0c;憑借其強…

集群環境下Redis 商品庫存系統設計

目錄 環境實現基本結構代碼業務代碼主體庫存管理模塊 后續問題高并發臨界值與樂觀鎖問題 完整代碼總結后話 環境 我們現在要做商品秒殺系統。功能很簡單&#xff0c;就是庫存刪減。用戶先下單減庫存&#xff0c;之后再進行扣款。 實現 基本結構代碼 那么我們先看下如何搭建…

Spring MVC響應數據

handler方法分析 /*** TODO: 一個controller的方法是控制層的一個處理器,我們稱為handler* TODO: handler需要使用RequestMapping/GetMapping系列,聲明路徑,在HandlerMapping中注冊,供DS查找!* TODO: handler作用總結:* 1.接收請求參數(param,json,pathVariable,共享域等…

基于圖像識別的醫學影像大數據診斷系統的設計與實現

標題:基于圖像識別的醫學影像大數據診斷系統的設計與實現 內容:1.摘要 隨著醫學影像技術的快速發展&#xff0c;醫學影像數據量呈爆炸式增長&#xff0c;傳統的人工診斷方式在處理海量數據時效率低下且容易出現誤差。本研究的目的是設計并實現一個基于圖像識別的醫學影像大數據…

Python散點圖(Scatter Plot):數據探索的“第一張圖表”

在數據可視化領域,散點圖是一種強大而靈活的工具,它能夠幫助我們直觀地理解和探索數據集中變量之間的關系。本文將深入探討散點圖的核心原理、應用場景以及如何使用Python進行高效繪制。 后續幾篇將介紹高級技巧、復雜應用場景。 Python散點圖(Scatter Plot):高階分析、散點…

【redis】在 Spring中操作 Redis

文章目錄 基礎設置依賴StringRedisTemplate庫的封裝 運行StringList刪庫 SetHashZset 基礎設置 依賴 需要選擇這個依賴 StringRedisTemplate // 后續 redis 測試的各種方法&#xff0c;都通過這個 Controller 提供的 http 接口來觸發 RestController public class MyC…

微服務》》Kubernetes (K8S) 集群 安裝

關閉交換空間 # 切換 超級管理員身份 # 查看交換空間 free -h # 關閉交換空間 swapoff -a避免開啟啟動交換空間 # 注釋swap開頭的行 vim /etc/fstab關閉防火墻 # 關閉防火墻 # 因為K8S 是集群形式存在的 至少三臺 一主二從 &#xff08;一個master 兩個node&#xff09…

HTTP和RPC的區別

RPC和 HTTP是兩種常見的通信方式&#xff0c;它們在設計目標、使用場景和技術實現上有顯著區別。以下是它們的詳細對比&#xff1a; 1. 定義與核心思想 特性RPCHTTPRemote Procedure Call遠程過程調用HyperText Transfer Protocol超文本傳輸協議定義一種協議或框架&#xff0…

MySQL 簡記

MySQL 簡記 mysql中的數據存儲的結構是B樹 其與B樹的相同點是&#xff0c;B樹一個節點也可以存放多條數據&#xff0c;并且從左到右依次增大&#xff1b;不同點是&#xff0c;B樹的葉子結點之間也能相互連接。那么實際上是采取利用空間換區時間的策略。 那么B樹的樹結構like…

十七、實戰開發 uni-app x 項目(仿京東)- 后端指南

前面我們已經用uniappx進行了前端實戰學習 一、實戰 開發uni-app x項目(仿京東)-規劃-CSDN博客 二、實戰 開發uni-app x項目(仿京東)-項目搭建-CSDN博客 三、實戰開發 uni-app x 項目(仿京東)- 技術選型-CSDN博客 四、實戰開發 uni-app x 項目(仿京東)- 頁面設計-C…

Infura 簡介

文章目錄 Infura 簡介Infura 的主要功能Infura 的替代方案&#xff08;類似服務&#xff09;AlchemyQuickNodeAnkrMoralisPocket Network 什么時候選擇 Infura&#xff1f; Infura 簡介 Infura 是一個 區塊鏈基礎設施即服務&#xff08;BaaS, Blockchain as a Service&#xf…

TouchSocket TcpService:構建高性能Tcp服務的終極利器

這里寫目錄標題 TouchSocket TCPService&#xff1a;構建高性能TCP服務的終極利器引言TCPService核心特性快速入門&#xff1a;5分鐘搭建TCP服務1. 創建基礎TCP服務2. 自定義插件處理數據 高級用法實戰1. 客戶端連接管理 性能與穩定性保障示例與源碼結語 TouchSocket TCPServic…

Android Fresco 框架緩存模塊源碼深度剖析(二)

一、引言 在 Android 應用開發中&#xff0c;圖片加載和處理是常見且重要的功能。頻繁的圖片加載不僅會消耗大量的網絡流量&#xff0c;還會影響應用的性能和響應速度。因此&#xff0c;有效的緩存機制對于提升圖片加載效率和用戶體驗至關重要。Fresco 是 Facebook 開源的一款…

springboot使用163發送自定義html格式的郵件

springboot使用163發送html格式的郵件 效果: 下面直接開始教學 注冊郵箱&#xff0c;生成授權碼 獲取163郵箱的授權碼&#xff0c;可以按照以下步驟操作&#xff1a; 登錄163郵箱 打開瀏覽器&#xff0c;訪問 163郵箱登錄頁面。 使用你的郵箱賬號和密碼登錄。進入郵箱設置 登…

【Kafka】深入了解Kafka

集群的成員關系 Kafka使用Zookeeper維護集群的成員信息。 每一個broker都有一個唯一的標識&#xff0c;這個標識可以在配置文件中指定&#xff0c;也可以自動生成。當broker在啟動時通過創建Zookeeper的臨時節點把自己的ID注冊到Zookeeper中。broker、控制器和其他一些動態系…

C#使用SnsPictureBox.dll繪制點,線段、圓、折線、多邊形、測量尺等多種圖形。

CSDN下載地址&#xff1a;https://download.csdn.net/download/sns1991sns/87726867 gitee下載地址:https://gitee.com/linsns/SnsPictrueBox 支持2種繪制方式&#xff1a;響應式和等待式。 一、使用響應式繪制圖形 1、在窗口構造函數里添加繪制圖形的完成響應函數 public…

Hugging Face預訓練GPT微調ChatGPT(微調入門!新手友好!)

Hugging Face預訓練GPT微調ChatGPT&#xff08;微調入門&#xff01;新手友好&#xff01;&#xff09; 在實戰中&#xff0c;?多數情況下都不需要從0開始訓練模型&#xff0c;?是使?“??”或者其他研究者開源的已經訓練好的?模型。 在各種?模型開源庫中&#xff0c;最…

Redis BitMap 用戶簽到

Redis Bitmap Bitmap&#xff08;位圖&#xff09;是 Redis 提供的一種用于處理二進制位&#xff08;bit&#xff09;的特殊數據結構&#xff0c;它基于 String 類型&#xff0c;每個 bit 代表一個布爾值&#xff08;0 或 1&#xff09;&#xff0c;可以用于存儲大規模的二值狀…