1、網絡發展歷史和分層
1.1 Internet 的歷史
-
起源:
-
1957 年:蘇聯發射第一顆人造衛星 "Sputnik"。
-
1958 年:美國總統艾森豪威爾成立 DARPA(國防部高級研究計劃署)。
-
1968 年:DARPA 提出 "資源共享計算機網絡"(ARPAnet),成為 Internet 的雛形。
-
-
TCP/IP 協議的誕生:
-
1973 年:Robert Kahn 和 Vinton Cerf 開發了新的互聯協議。
-
1974 年:TCP 協議首次發布,但存在數據包丟失時無法有效糾正的問題。
-
1974 年后:TCP 協議拆分為 TCP 和 IP 兩個獨立協議。
-
1983 年:ARPAnet 停止使用 NCP,全面采用 TCP/IP 協議。
-
1.2 網絡的體系結構
-
分層設計:將網絡功能劃分為不同模塊,每層實現特定功能,對外部透明。
-
兩種體系結構:
-
OSI 模型:七層模型(物理層、數據鏈路層、網絡層、傳輸層、會話層、表示層、應用層)。
-
TCP/IP 模型:四層模型(網絡接口層、網絡層、傳輸層、應用層)。
-
1.3 TCP/IP 協議通信模型
-
數據封裝與傳遞過程:
-
應用層數據 → 傳輸層(TCP/UDP)→ 網絡層(IP)→ 數據鏈路層(以太網幀)→ 物理層。
-
-
數據包結構:
-
包含以太網頭部、IP 頭部、TCP/UDP 頭部、應用層頭部和用戶數據。
-
2、TCP 和 UDP 協議特點
2.1 TCP 協議特點
-
面向連接:提供高可靠性通信(無丟失、無失序、無重復)。
-
適用場景:
-
傳輸大量數據或對質量要求較高的場景。
-
即時通訊軟件的用戶登錄管理。
-
2.2 UDP 協議特點
-
無連接:高效傳輸,但不可靠。
-
適用場景:
-
小數據量傳輸(如 DNS 查詢)。
-
廣播/組播通信。
-
實時數據傳輸(如流媒體、VoIP)。
-
3、網絡編程預備知識
3.1 Socket 簡介
-
定義:Socket 是一種編程接口,用于網絡通信。
-
類型:
-
流式套接字(SOCK_STREAM):面向連接,可靠。
-
數據報套接字(SOCK_DGRAM):無連接,不可靠。
-
原始套接字(SOCK_RAW):直接訪問底層協議。
-
3.2 IP 地址
-
IPv4:32 位,點分十進制表示(如 192.168.1.1)。
-
IPv6:128 位。
-
子網掩碼:用于區分網絡部分和主機部分。
3.3 端口號
-
范圍:
-
眾所周知端口:1~1023。
-
注冊端口:1024~49150。
-
動態端口:49151~65535。
-
-
TCP 和 UDP 端口獨立。
3.4 字節序
-
主機字節序(HBO):因 CPU 架構不同而不同(如 Intel 為小端序,ARM 為大端序)。
-
網絡字節序(NBO):統一為大端序。
-
轉換函數:
-
htonl()
、htons()
:主機字節序轉網絡字節序。 -
ntohl()
、ntohs()
:網絡字節序轉主機字節序。
-
3.5 IP 地址轉換
-
inet_aton()
:字符串轉 32 位網絡字節序。 -
inet_ntoa()
:32 位網絡字節序轉點分十進制字符串。
4、TCP/IP 網絡編程
4.1 網絡編程 API
4.1.1 socket()
函數
-
作用:創建一個套接字。
-
原型:
int socket(int domain, int type, int protocol);
-
參數:
-
domain
:協議族(如AF_INET
表示 IPv4,AF_INET6
表示 IPv6)。 -
type
:套接字類型(如SOCK_STREAM
表示 TCP,SOCK_DGRAM
表示 UDP)。 -
protocol
:協議類型(通常為 0,表示默認協議)。
-
-
返回值:成功返回套接字描述符,失敗返回 -1。
-
示例:
int sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd == -1) {perror("創建套接字失敗");return -1; } printf("創建套接字成功\n");
4.1.2 bind()
函數
-
作用:將套接字綁定到指定的地址和端口。
-
原型:
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
-
參數:
-
sockfd
:套接字描述符。 -
addr
:指向sockaddr
結構的指針,包含地址信息。 -
addrlen
:addr
的長度。
-
-
返回值:成功返回 0,失敗返回 -1。
-
示例:
struct sockaddr_in server_addr; memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(8888); server_addr.sin_addr.s_addr = INADDR_ANY; ? if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {perror("綁定失敗");close(sockfd);return -1; } printf("綁定成功\n");
4.1.3 listen()
函數
-
作用:將套接字設置為監聽狀態。
-
原型:
int listen(int sockfd, int backlog);
-
參數:
-
sockfd
:套接字描述符。 -
backlog
:最大連接請求數。
-
-
返回值:成功返回 0,失敗返回 -1。
-
示例:
if (listen(sockfd, 5) == -1) {perror("監聽失敗");close(sockfd);return -1; } printf("開始監聽\n");
4.1.4 accept()
函數
-
作用:接受客戶端連接請求。
-
原型:
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
-
參數:
-
sockfd
:監聽套接字描述符。 -
addr
:指向sockaddr
結構的指針,用于存儲客戶端地址。 -
addrlen
:addr
的長度。
-
-
返回值:成功返回新套接字描述符,失敗返回 -1。
-
示例:
struct sockaddr_in client_addr; socklen_t client_len = sizeof(client_addr); int clientfd = accept(sockfd, (struct sockaddr *)&client_addr, &client_len); if (clientfd == -1) {perror("接受連接失敗");close(sockfd);return -1; } printf("客戶端連接成功\n");
4.1.5 connect()
函數
-
作用:主動連接服務器。
-
原型:
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
-
參數:
-
sockfd
:套接字描述符。 -
addr
:指向sockaddr
結構的指針,包含服務器地址信息。 -
addrlen
:addr
的長度。
-
-
返回值:成功返回 0,失敗返回 -1。
-
示例:
struct sockaddr_in server_addr; memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(8888); server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");if (connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {perror("連接失敗");close(sockfd);return -1; } printf("連接服務器成功\n");
4.1.6 send()
和 recv()
函數
-
send()
作用:發送數據。 -
send()
原型:ssize_t send(int sockfd, const void *buf, size_t len, int flags);
-
recv()
作用:接收數據。 -
recv()
原型:ssize_t recv(int sockfd, void *buf, size_t len, int flags);
-
參數:
-
sockfd
:套接字描述符。 -
buf
:數據緩沖區。 -
len
:緩沖區長度。 -
flags
:控制標志。
-
-
返回值:成功返回發送/接收的字節數,失敗返回 -1。
-
示例:
char buffer[1024]; memset(buffer, 0, sizeof(buffer)); strcpy(buffer, "你好,服務器"); if (send(sockfd, buffer, strlen(buffer), 0) == -1) {perror("發送失敗");close(sockfd);return -1; } printf("發送數據成功\n");int bytes_read = recv(sockfd, buffer, sizeof(buffer), 0); if (bytes_read <= 0) {perror("接收失敗");close(sockfd);return -1; } printf("收到服務器回復:%s\n", buffer);
4.1.7 close()
和 shutdown()
函數
-
close()
作用:關閉套接字。 -
close()
原型:int close(int sockfd);
-
shutdown()
作用:關閉套接字的讀或寫操作。 -
shutdown()
原型:int shutdown(int sockfd, int how);
-
參數:
-
how
:SHUT_RD
表示關閉讀,SHUT_WR
表示關閉寫,SHUT_RDWR
表示關閉讀和寫。
-
-
返回值:成功返回 0,失敗返回 -1。
-
示例:
close(sockfd); printf("關閉套接字成功\n");
5、TCP 編程模型
5.1 循環服務器
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>int main() {int sockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd == -1) {perror("創建套接字失敗");return -1;}printf("創建套接字成功\n");struct sockaddr_in server_addr;memset(&server_addr, 0, sizeof(server_addr));server_addr.sin_family = AF_INET;server_addr.sin_port = htons(8888);server_addr.sin_addr.s_addr = INADDR_ANY;if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {perror("綁定失敗");close(sockfd);return -1;}printf("綁定成功\n");if (listen(sockfd, 5) == -1) {perror("監聽失敗");close(sockfd);return -1;}printf("開始監聽\n");while (1) {struct sockaddr_in client_addr;socklen_t client_len = sizeof(client_addr);int clientfd = accept(sockfd, (struct sockaddr *)&client_addr, &client_len);if (clientfd == -1) {perror("接受連接失敗");close(sockfd);return -1;}printf("客戶端連接成功\n");char buffer[1024];while (1) {int bytes_read = recv(clientfd, buffer, sizeof(buffer), 0);if (bytes_read <= 0) {if (bytes_read == 0) {printf("客戶端斷開連接\n");} else {perror("接收失敗");}break;}buffer[bytes_read] = '\0';printf("收到客戶端消息:%s\n", buffer);send(clientfd, buffer, bytes_read, 0);}close(clientfd);printf("關閉客戶端連接\n");}close(sockfd);return 0;
}
5.2 多進程/多線程并發服務器
-
多進程示例:
#include <stdio.h> #include <sys/socket.h> #include <netinet/in.h> #include <string.h> #include <unistd.h> #include <stdlib.h>void handle_client(int clientfd) {char buffer[1024];while (1) {int bytes_read = recv(clientfd, buffer, sizeof(buffer), 0);if (bytes_read <= 0) {if (bytes_read == 0) {printf("客戶端斷開連接\n");} else {perror("接收失敗");}break;}buffer[bytes_read] = '\0';printf("收到客戶端消息:%s\n", buffer);send(clientfd, buffer, bytes_read, 0);}close(clientfd);printf("關閉客戶端連接\n");exit(0); }int main() {int sockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd == -1) {perror("創建套接字失敗");return -1;}printf("創建套接字成功\n");struct sockaddr_in server_addr;memset(&server_addr, 0, sizeof(server_addr));server_addr.sin_family = AF_INET;server_addr.sin_port = htons(8888);server_addr.sin_addr.s_addr = INADDR_ANY;if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {perror("綁定失敗");close(sockfd);return -1;}printf("綁定成功\n");if (listen(sockfd, 5) == -1) {perror("監聽失敗");close(sockfd);return -1;}printf("開始監聽\n");while (1) {struct sockaddr_in client_addr;socklen_t client_len = sizeof(client_addr);int clientfd = accept(sockfd, (struct sockaddr *)&client_addr, &client_len);if (clientfd == -1) {perror("接受連接失敗");close(sockfd);return -1;}printf("客戶端連接成功\n");if (fork() == 0) {close(sockfd);handle_client(clientfd);} else {close(clientfd);}}close(sockfd);return 0; }
6、UDP 編程模型
6.1 循環服務器
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>int main() {int sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd == -1) {perror("創建套接字失敗");return -1;}printf("創建套接字成功\n");struct sockaddr_in server_addr;memset(&server_addr, 0, sizeof(server_addr));server_addr.sin_family = AF_INET;server_addr.sin_port = htons(8888);server_addr.sin_addr.s_addr = INADDR_ANY;if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {perror("綁定失敗");close(sockfd);return -1;}printf("綁定成功\n");char buffer[1024];struct sockaddr_in client_addr;socklen_t client_len = sizeof(client_addr);while (1) {int bytes_read = recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr *)&client_addr, &client_len);if (bytes_read <= 0) {perror("接收失敗");continue;}buffer[bytes_read] = '\0';printf("收到客戶端消息:%s\n", buffer);sendto(sockfd, buffer, bytes_read, 0, (struct sockaddr *)&client_addr, client_len);}close(sockfd);return 0;
}
7、網絡調試和協議分析
7.1 工具
-
Wireshark:圖形化網絡抓包工具,用于分析網絡封包。
-
tcpdump:命令行網絡抓包工具。
8、I/O 模型和多路復用模型
8.1 I/O 模型
-
阻塞 I/O:
-
套接字默認為阻塞模式。
-
讀寫操作(如
read
、write
、accept
、connect
)會阻塞進程,直到操作完成。
-
-
非阻塞 I/O:
-
套接字設置為非阻塞模式后,I/O 操作無法立即完成時會立即返回錯誤。
-
需要輪詢(polling)檢查 I/O 是否就緒,浪費 CPU 資源。
-
-
I/O 多路復用:
-
同時監控多個文件描述符的 I/O 狀態。
-
使用
select()
或poll()
函數實現。
-
-
信號驅動 I/O:
-
異步通信模型,通過信號通知 I/O 事件。
-
8.2 阻塞 I/O 的問題
-
讀操作:如果套接字接收緩沖區沒有數據,
read
會阻塞,直到數據到達。 -
寫操作:如果發送緩沖區空間不足,
write
會阻塞,直到緩沖區有足夠空間。 -
UDP 協議中不存在發送緩沖區滿的情況,寫操作不會阻塞。
8.3 非阻塞模式的實現
-
使用
fcntl()
或ioctl()
函數將套接字設置為非阻塞模式。 -
示例代碼:
int flag = fcntl(sockfd, F_GETFL, 0); flag |= O_NONBLOCK; fcntl(sockfd, F_SETFL, flag);
8.4 I/O 多路復用
-
select()
函數:-
監控多個文件描述符的讀、寫和異常事件。
-
參數:
-
maxfd
:監控的文件描述符中最大的值加 1。 -
read_fds
、write_fds
、except_fds
:文件描述符集合。 -
timeout
:超時時間。
-
-
-
poll()
函數:-
類似
select()
,但更節省空間,適合監控大量文件描述符。
-
9、網絡分析測試工具
9.1 常用工具
-
Wireshark:圖形化網絡抓包工具,用于分析網絡封包。
-
tcpdump:命令行網絡抓包工具。
-
telnet:測試 TCP 服務器端。
-
netstat:顯示網絡連接、路由表等信息。
-
lsof:列出當前系統打開的文件和網絡連接。
-
sniffer:網絡協議分析工具。
9.2 網絡封包格式
-
以太網頭:包含源和目的 MAC 地址。
-
IP 頭:包含源和目的 IP 地址、協議類型等。
-
TCP/UDP 頭:包含源和目的端口號、序列號等。
-
應用層數據:用戶數據。
10、TCP 握手過程
10.1 三次握手
-
客戶端發送 SYN 包到服務器。
-
服務器回復 SYN-ACK 包。
-
客戶端發送 ACK 包,建立連接。
10.2 四次揮手
-
客戶端發送 FIN 包,請求關閉連接。
-
服務器回復 ACK 包,確認收到 FIN。
-
服務器發送 FIN 包,請求關閉連接。
-
客戶端回復 ACK 包,確認收到 FIN。
11、網絡信息檢索和設置
11.1 網絡信息檢索函數
-
gethostname()
:獲取主機名。 -
getpeername()
:獲取遠程協議地址。 -
getsockname()
:獲取本地套接口地址。 -
gethostbyname()
:根據主機名獲取主機信息。 -
getservbyname()
:根據服務名獲取服務信息。
11.2 網絡屬性設置
-
使用
setsockopt()
和getsockopt()
設置和獲取套接字選項。 -
常見選項:
-
SO_REUSEADDR
:允許重用本地地址和端口。 -
SO_KEEPALIVE
:保持連接。 -
SO_RCVTIMEO
和SO_SNDTIMEO
:設置接收和發送超時。
-
11.3 網絡超時檢測
-
方法一:設置 socket 屬性
SO_RCVTIMEO
。 -
方法二:使用
select()
檢測 socket 是否就緒。 -
方法三:設置定時器捕獲
SIGALRM
信號。
12、思考與應用
12.1 如何動態檢查網絡連接狀態?
-
應用層:使用心跳檢測機制。
-
內核層:啟用周期性檢查定時器(如 2.6 內核)。
-
硬件層:通過網卡硬件或 GPIO 檢測網線插拔。
13、廣播和組播
13.1 廣播
-
定義:將數據包發送給局域網中的所有主機。
-
實現方式:使用 UDP 協議套接字。
-
廣播地址:
-
以 192.168.1.0 網段為例,廣播地址為 192.168.1.255。
-
255.255.255.255 代表所有網段的廣播地址。
-
-
發送廣播:
-
創建 UDP 套接字。
-
使用
setsockopt()
設置套接字為廣播模式。 -
指定廣播地址和端口。
-
使用
sendto()
發送數據包。
-
-
接收廣播:
-
創建 UDP 套接字。
-
綁定本機 IP 地址和端口。
-
使用
recvfrom()
接收數據。
-
13.2 組播
-
定義:將數據包發送給特定多播組中的主機。
-
優勢:避免廣播風暴,減少網絡負載。
-
組播地址范圍:224.0.0.1 – 239.255.255.255。
-
發送組播:
-
創建 UDP 套接字。
-
指定組播地址和端口。
-
使用
sendto()
發送數據包。
-
-
接收組播:
-
創建 UDP 套接字。
-
加入多播組(使用
setsockopt()
)。 -
綁定本機 IP 地址和端口。
-
使用
recvfrom()
接收數據。
-
-
加入多播組示例:
struct ip_mreq mreq; bzero(&mreq, sizeof(mreq)); mreq.imr_multiaddr.s_addr = inet_addr("235.10.10.3"); mreq.imr_interface.s_addr = htonl(INADDR_ANY); setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
14、UNIX 域套接字
14.1 定義
-
用于本地進程間通信的套接字。
14.2 類型
-
流式套接字:提供可靠、有序的通信。
-
數據報套接字:提供無連接、不可靠的通信。
14.3 地址結構
-
struct sockaddr_un
:struct sockaddr_un {sa_family_t sun_family;char sun_path[108]; // 套接字文件的路徑 };
-
填充地址結構示例:
struct sockaddr_un myaddr; bzero(&myaddr, sizeof(myaddr)); myaddr.sun_family = AF_UNIX; strcpy(myaddr.sun_path, "/tmp/mysocket");
14.4 流式套接字使用示例
-
服務器端:
int sockfd = socket(AF_UNIX, SOCK_STREAM, 0); struct sockaddr_un server_addr; bzero(&server_addr, sizeof(server_addr)); server_addr.sun_family = AF_UNIX; strcpy(server_addr.sun_path, "/tmp/mysocket");if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {perror("綁定失敗");close(sockfd);return -1; } printf("綁定成功\n");if (listen(sockfd, 5) == -1) {perror("監聽失敗");close(sockfd);return -1; } printf("開始監聽\n");struct sockaddr_un client_addr; socklen_t client_len = sizeof(client_addr); int clientfd = accept(sockfd, (struct sockaddr *)&client_addr, &client_len); if (clientfd == -1) {perror("接受連接失敗");close(sockfd);return -1; } printf("客戶端連接成功\n");char buffer[1024]; while (1) {int bytes_read = recv(clientfd, buffer, sizeof(buffer), 0);if (bytes_read <= 0) {if (bytes_read == 0) {printf("客戶端斷開連接\n");} else {perror("接收失敗");}break;}buffer[bytes_read] = '\0';printf("收到客戶端消息:%s\n", buffer);send(clientfd, buffer, bytes_read, 0); }close(clientfd); close(sockfd); unlink("/tmp/mysocket"); printf("關閉連接并刪除套接字文件\n");
-
客戶端:
int sockfd = socket(AF_UNIX, SOCK_STREAM, 0); struct sockaddr_un server_addr; bzero(&server_addr, sizeof(server_addr)); server_addr.sun_family = AF_UNIX; strcpy(server_addr.sun_path, "/tmp/mysocket");if (connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {perror("連接失敗");close(sockfd);return -1; } printf("連接服務器成功\n");char buffer[1024]; while (1) {printf("請輸入消息:");fgets(buffer, sizeof(buffer), stdin);int len = strlen(buffer);if (buffer[len - 1] == '\n') {buffer[len - 1] = '\0';}if (send(sockfd, buffer, strlen(buffer), 0) == -1) {perror("發送失敗");close(sockfd);return -1;}printf("發送消息:%s\n", buffer);int bytes_read = recv(sockfd, buffer, sizeof(buffer), 0);if (bytes_read <= 0) {if (bytes_read == 0) {printf("服務器斷開連接\n");} else {perror("接收失敗");}break;}buffer[bytes_read] = '\0';printf("收到服務器回復:%s\n", buffer); }close(sockfd); printf("關閉連接\n");
14.5 數據報套接字使用示例
-
服務器端:
int sockfd = socket(AF_UNIX, SOCK_DGRAM, 0); struct sockaddr_un server_addr; bzero(&server_addr, sizeof(server_addr)); server_addr.sun_family = AF_UNIX; strcpy(server_addr.sun_path, "/tmp/mysocket");if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {perror("綁定失敗");close(sockfd);return -1; } printf("綁定成功\n");char buffer[1024]; struct sockaddr_un client_addr; socklen_t client_len = sizeof(client_addr);while (1) {int bytes_read = recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr *)&client_addr, &client_len);if (bytes_read <= 0) {perror("接收失敗");continue;}buffer[bytes_read] = '\0';printf("收到客戶端消息:%s\n", buffer);sendto(sockfd, buffer, bytes_read, 0, (struct sockaddr *)&client_addr, client_len); }close(sockfd); unlink("/tmp/mysocket"); printf("關閉連接并刪除套接字文件\n");
-
客戶端:
int sockfd = socket(AF_UNIX, SOCK_DGRAM, 0); struct sockaddr_un server_addr; bzero(&server_addr, sizeof(server_addr)); server_addr.sun_family = AF_UNIX; strcpy(server_addr.sun_path, "/tmp/mysocket");struct sockaddr_un client_addr; bzero(&client_addr, sizeof(client_addr)); client_addr.sun_family = AF_UNIX; strcpy(client_addr.sun_path, "/tmp/myclientsocket");if (bind(sockfd, (struct sockaddr *)&client_addr, sizeof(client_addr)) == -1) {perror("綁定失敗");close(sockfd);return -1; } printf("綁定成功\n");if (connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {perror("連接失敗");close(sockfd);return -1; } printf("連接服務器成功\n");char buffer[1024]; while (1) {printf("請輸入消息:");fgets(buffer, sizeof(buffer), stdin);int len = strlen(buffer);if (buffer[len - 1] == '\n') {buffer[len - 1] = '\0';}if (sendto(sockfd, buffer, strlen(buffer), 0, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {perror("發送失敗");close(sockfd);return -1;}printf("發送消息:%s\n", buffer);struct sockaddr_un from_addr;socklen_t from_len = sizeof(from_addr);int bytes_read = recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr *)&from_addr, &from_len);if (bytes_read <= 0) {perror("接收失敗");continue;}buffer[bytes_read] = '\0';printf("收到服務器回復:%s\n", buffer); }close(sockfd); unlink("/tmp/myclientsocket"); printf("關閉連接并刪除套接字文件\n");
15、網絡總結
15.1 網絡編程的關鍵點
-
Socket 編程:掌握不同類型的套接字及其使用方法。
-
I/O 模型:理解阻塞、非阻塞、多路復用等模型。
-
網絡工具:熟練使用 Wireshark、tcpdump 等工具。
-
網絡協議:熟悉 TCP/IP 協議族及其應用。
15.2 應用場景
-
單播:點對點通信。
-
廣播:局域網內所有主機通信。
-
組播:特定多播組內的主機通信。
-
UNIX 域套接字:本地進程間通信。
【至此Linux C系列文章完畢,會不斷的優化完整。文章僅用于分享學習以及自己復習使用,若有什么問題,麻煩指出,謝謝】