欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 新闻 > 国际 > 10、Linux C 网络编程(完整版)

10、Linux C 网络编程(完整版)

2025/4/3 2:57:02 来源:https://blog.csdn.net/m0_66405876/article/details/146874052  浏览:    关键词: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系列文章完毕,会不断的优化完整。文章仅用于分享学习以及自己复习使用,若有什么问题,麻烦指出,谢谢】

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com