10、Linux C 網絡編程(完整版)

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 結構的指針,包含地址信息。

    • addrlenaddr 的長度。

  • 返回值:成功返回 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 結構的指針,用于存儲客戶端地址。

    • addrlenaddr 的長度。

  • 返回值:成功返回新套接字描述符,失敗返回 -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 結構的指針,包含服務器地址信息。

    • addrlenaddr 的長度。

  • 返回值:成功返回 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);
    
  • 參數

    • howSHUT_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

    • 套接字默認為阻塞模式。

    • 讀寫操作(如 readwriteacceptconnect)會阻塞進程,直到操作完成。

  • 非阻塞 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_fdswrite_fdsexcept_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 三次握手
  1. 客戶端發送 SYN 包到服務器。

  2. 服務器回復 SYN-ACK 包。

  3. 客戶端發送 ACK 包,建立連接。

10.2 四次揮手
  1. 客戶端發送 FIN 包,請求關閉連接。

  2. 服務器回復 ACK 包,確認收到 FIN。

  3. 服務器發送 FIN 包,請求關閉連接。

  4. 客戶端回復 ACK 包,確認收到 FIN。

11、網絡信息檢索和設置

11.1 網絡信息檢索函數
  • gethostname():獲取主機名。

  • getpeername():獲取遠程協議地址。

  • getsockname():獲取本地套接口地址。

  • gethostbyname():根據主機名獲取主機信息。

  • getservbyname():根據服務名獲取服務信息。

11.2 網絡屬性設置
  • 使用 setsockopt()getsockopt() 設置和獲取套接字選項。

  • 常見選項:

    • SO_REUSEADDR:允許重用本地地址和端口。

    • SO_KEEPALIVE:保持連接。

    • SO_RCVTIMEOSO_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系列文章完畢,會不斷的優化完整。文章僅用于分享學習以及自己復習使用,若有什么問題,麻煩指出,謝謝】

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

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

相關文章

前端:開源軟件鏡像站 / 清華大學開源軟件鏡像站 / 阿里云 / 網易 / 搜狐

一、理解開源軟件鏡像站 開源軟件鏡像是指開源軟件在遠程服務器上的備份副本&#xff0c;允許用戶通過互聯網快速下載和安裝所需的軟件。在國內&#xff0c;有多個知名的開源軟件鏡像站&#xff0c;為開發者提供穩定、快速的開源軟件下載服務。 二、常見開源軟件鏡像站 序號…

Oracle 數據庫中優化 INSERT INTO 操作的性能

在 Oracle 數據庫中優化 INSERT INTO 操作的性能&#xff0c;尤其是在處理大批量數據時&#xff0c;可以通過以下方法顯著提升效率。 使用直接路徑插入&#xff08;Direct-Path Insert&#xff09; 通過 APPEND 提示繞過緩沖區緩存&#xff0c;直接寫入數據文件&#xff0c;減…

嵌入式硬件篇---嘉立創PCB繪制

文章目錄 前言一、PCB繪制簡介1.1繪制步驟1.1.1前期準備1.1.2原理圖設計1.1.3原理圖轉PCB1.1.4PCB布局1.1.5布線1.1.6布線優化和絲印1.1.7制版 1.2原理1.2.1電氣連接原理1.2.2信號傳輸原理1.2.3電源和接地原理 1.3注意事項1.3.1元件封裝1.3.2布局規則1.3.3過孔設計1.3.4DRC檢查…

ideal自動生成類圖的方法

在 IntelliJ IDEA 中&#xff0c;“**在項目資源管理器中選擇以下類**” 是指通過 **項目資源管理器&#xff08;Project Tool Window&#xff09;** 找到并選中你需要生成類圖的類文件&#xff08;如 .java 文件&#xff09;&#xff0c;然后通過右鍵菜單或快捷鍵操作生成類圖…

【零基礎入門unity游戲開發——2D篇】2D物理關節 —— Joint2D相關組件

考慮到每個人基礎可能不一樣,且并不是所有人都有同時做2D、3D開發的需求,所以我把 【零基礎入門unity游戲開發】 分為成了C#篇、unity通用篇、unity3D篇、unity2D篇。 【C#篇】:主要講解C#的基礎語法,包括變量、數據類型、運算符、流程控制、面向對象等,適合沒有編程基礎的…

在Vue 3 + TypeScript + Vite 項目中安裝和使用 SCSS

在Vue 3 TypeScript Vite 項目中安裝和使用 SCSS 1、安裝 SCSS 的相關依賴 npm install sass --save-dev2、配置 Vite 對于 Vue 3&#xff0c;Vite 已經內置了對 SCSS 的支持&#xff0c;通常不需要額外的配置。但是&#xff0c;如果需要自定義配置&#xff0c;可以在路徑…

【滲透測試】Vulnhub靶機-FSoft Challenges VM: 1-詳細通關教程

下載地址&#xff1a;https://www.vulnhub.com/entry/fsoft-challenges-vm-1,402/ 目錄 前言 信息收集 目錄掃描 wpscan掃描 修改密碼 反彈shell 提權 思路總結 前言 開始前注意靶機簡介&#xff0c;當第一次開機時會報apache錯誤&#xff0c;所以要等一分鐘后重啟才…

Redis 6.2.6 生產環境單機配置詳解redis.conf

文章目錄 Redis 生產環境配置詳解配置文件示例基礎網絡與進程管理RDB 持久化配置復制&#xff08;主從同步&#xff09;設置內存管理AOF 持久化性能優化設置限制與監控其他參數完整配置總結 Redis 生產環境配置詳解 在實際生產環境中&#xff0c;為了保障 Redis 的穩定性和高性…

SpringBoot實戰:Excel文件上傳、數據驗證與存儲全流程解析

一、需求場景與技術選型 在企業管理、數據中臺等系統中&#xff0c;Excel文件處理是常見需求。本文將基于SpringBoot實現以下核心功能&#xff1a; 支持.xls/.xlsx文件上傳數據完整性驗證&#xff08;非空、格式等&#xff09;業務數據驗證&#xff08;關聯數據庫校驗&#x…

使用Java爬蟲按關鍵字搜索淘寶商品?

在電商領域&#xff0c;通過關鍵字搜索商品是獲取商品信息的常見需求。Java爬蟲技術可以幫助我們自動化地獲取這些信息&#xff0c;提高工作效率。本文將詳細介紹如何使用Java爬蟲按關鍵字搜索淘寶商品&#xff0c;并提供完整的代碼示例。 一、準備工作 1. 注冊淘寶開放平臺賬…

【Git】5 個分區的切換方式及示例

目錄 1. **工作區&#xff08;Working Directory&#xff09;**2. **緩存區&#xff08;Stage/Index&#xff09;**3. **本地倉庫&#xff08;Local Repository&#xff09;**4. **遠程倉庫&#xff08;Remote Repository&#xff09;**5. **貯藏區&#xff08;Stash&#xff0…

【計算機視覺】YOLO語義分割

一、語義分割簡介 1. 定義 語義分割&#xff08;Semantic Segmentation&#xff09;是計算機視覺中的一項任務&#xff0c;其目標是對圖像中的每一個像素賦予一個類別標簽。與目標檢測只給出目標的邊界框不同&#xff0c;語義分割能夠在像素級別上區分不同類別&#xff0c;從…

MATLAB之數據分析圖系列:從二維到三維(直接套用)

MATLAB以其強大的矩陣運算和可視化功能&#xff0c;成為科研、工程領域的標配工具。本文提供從基礎二維圖形到復雜三維模型的即用代碼塊&#xff0c;涵蓋數據標注、多圖排版、動態演示等核心技巧 所有代碼均經過MATLAB 2023a實測&#xff0c;替換數據即可生成專業級圖表。” …

HTTP響應數據包全面解析:結構、原理與最佳實踐

目錄 HTTP響應概述 HTTP響應數據包結構 2.1 狀態行 2.2 響應頭 2.3 空行 2.4 響應體 HTTP狀態碼詳解 3.1 1xx信息響應 3.2 2xx成功響應 3.3 3xx重定向 3.4 4xx客戶端錯誤 3.5 5xx服務器錯誤 常見HTTP響應頭字段 響應體內容類型 緩存控制機制 實際HTTP響應示例分…

H.264編碼解析與C++實現詳解

一、H.264編碼核心概念 1.1 分層編碼結構 H.264采用分層設計&#xff0c;包含視頻編碼層&#xff08;VCL&#xff09;和網絡抽象層&#xff08;NAL&#xff09;。VCL處理核心編碼任務&#xff0c;NAL負責封裝網絡傳輸數據。 1.2 NALU單元結構 // NAL單元頭部結構示例 struc…

快速入手-基于Django-rest-framework的自身組件權限認證(九)

1、在對應的視圖函數里增加認證&#xff08;局部起作用&#xff0c;不全局生效&#xff09; 導入類&#xff1a; from rest_framework.authentication import ( BasicAuthentication, SessionAuthentication, ) from rest_framework.permissions import IsAuthentica…

受控組件和非受控組件的區別

在 React 中&#xff0c;?受控組件&#xff08;Controlled Components&#xff09;? 和 ?非受控組件&#xff08;Uncontrolled Components&#xff09;? 是處理表單元素的兩種不同方式&#xff0c;它們的核心區別在于 ?數據管理的方式 和 ?與 React 的交互模式。 受控組件…

邁向云原生:理想汽車 OLAP 引擎變革之路

在如今數據驅動的時代&#xff0c;高效的分析引擎對企業至關重要。理想汽車作為智能電動汽車的領軍企業&#xff0c;面臨著海量數據分析的挑戰。本文將展開介紹理想汽車 OLAP 引擎從存算一體向云原生架構演進的變革歷程&#xff0c;以及在此過程中面臨的挑戰&#xff0c;以及是…

ZLMediaKit 源碼分析——[3] ZLToolKit 中EventPoller之網絡事件處理

系列文章目錄 第一篇 基于SRS 的 WebRTC 環境搭建 第二篇 基于SRS 實現RTSP接入與WebRTC播放 第三篇 centos下基于ZLMediaKit 的WebRTC 環境搭建 第四篇 WebRTC學習一&#xff1a;獲取音頻和視頻設備 第五篇 WebRTC學習二&#xff1a;WebRTC音視頻數據采集 第六篇 WebRTC學習三…

【分布式】分布式限流方案解析

文章目錄 固定窗口限流方案?實現方式?優點?缺點? 滑動窗口限流方案?實現方式?優點?缺點? 令牌桶限流方案?實現方式?優點?缺點? 漏斗限流方案?實現方式?優點?缺點? 在分布式系統蓬勃發展的當下&#xff0c;系統面臨的流量挑戰日益復雜。為確保系統在高并發場景下…