当前位置: 首页 > news >正文

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系列文章完毕,会不断的优化完整。文章仅用于分享学习以及自己复习使用,若有什么问题,麻烦指出,谢谢】

相关文章:

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

1、网络发展历史和分层 1.1 Internet 的历史 起源&#xff1a; 1957 年&#xff1a;苏联发射第一颗人造卫星 "Sputnik"。 1958 年&#xff1a;美国总统艾森豪威尔成立 DARPA&#xff08;国防部高级研究计划署&#xff09;。 1968 年&#xff1a;DARPA 提出 "…...

拼多多 anti-token unidbg 分析

声明: 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01; 逆向分析 版本7.3-7.4 都试过加密没什…...

Swoole 的 Hyperf 框架和 Go 的 Gin 框架高并发原理以及技术实现对比分析

Swoole 的 Hyperf 框架和 Go 的 Gin 框架虽然都支持高并发&#xff0c;但它们的实现原理、底层机制和适用场景有显著差异。以下从 高并发原理、技术实现区别、优缺点 三个方面详细分析&#xff1a; 一、高并发实现原理 1. Hyperf (PHP Swoole) Hyperf 的高并发能力基于 Swoo…...

CSS3学习教程,从入门到精通,CSS3 媒体查询实现响应式布局语法指南(21)

CSS3 媒体查询实现响应式布局语法指南 一、媒体查询核心语法 1. 基础语法结构 media 媒体类型 and (媒体特性) {/* 匹配条件时应用的CSS规则 */ }2. 媒体类型&#xff08;可省略&#xff09; 类型值说明all所有设备&#xff08;默认值&#xff09;screen屏幕设备print打印机…...

C#中,什么是委托,什么是事件及它们之间的关系

1. 委托&#xff08;Delegate&#xff09; 定义与作用 ‌委托‌是类型安全的函数指针&#xff0c;用于封装方法&#xff0c;支持多播&#xff08;链式调用&#xff09;。‌核心能力‌&#xff1a;将方法作为参数传递或异步回调。 使用场景 回调机制&#xff08;如异步操作完…...

【LeetCode 热题100】347:前 K 个高频元素(详细解析)(Go语言版)

&#x1f680; 力扣热题 347&#xff1a;前 K 个高频元素&#xff08;详细解析&#xff09; &#x1f4cc; 题目描述 力扣 347. 前 K 个高频元素 给你一个整数数组 nums 和一个整数 k&#xff0c;请你返回其中出现频率 前 k 高的元素。你可以按 任意顺序 返回答案。 &#x1f…...

②EtherCAT/Ethernet/IP/Profinet/ModbusTCP协议互转工业串口网关

型号 协议转换通信网关 EtherCAT 转 Modbus TCP 配置说明 网线连接电脑到模块上的 WEB 网页设置网口&#xff0c;电脑所连网口的网段设置成 192.168.1.X&#xff08;X 是除 8 外的任一数值&#xff09;后&#xff0c;打开浏览器&#xff0c;地址栏输入 192.168.1.8 &#xff…...

微服务集成测试 -华为OD机试真题(A卷、Python)

题目描述 现在有n个容器服务&#xff0c;服务的启动可能有一定的依赖性&#xff08;有些服务启动没有依赖&#xff09;&#xff0c;其次&#xff0c;服务自身启动加载会消耗一些时间。 给你一个n n 的二维矩阵useTime&#xff0c;其中useTime[i][i]10表示服务i自身启动加载需…...

k8s常用总结

1. Kubernetes 架构概览 主节点&#xff08;Master&#xff09;&#xff1a; 负责集群管理&#xff0c;包括 API Server、Controller Manager、Scheduler 和 etcd 存储。 工作节点&#xff08;Node&#xff09;&#xff1a; 运行 Pod 和容器&#xff0c;包含 kubelet、kube-pr…...

【算法】并查集基础讲解

一、定义 一种树型的数据结构&#xff0c;用于处理一些不相交集合的合并及查询问题。思想是用一个数组表示了整片森林&#xff08;parent&#xff09;&#xff0c;树的根节点唯一标识了一个集合&#xff0c;只要找到了某个元素的的树根&#xff0c;就能确定它在哪个集合里。 …...

探索PHP的未来发展与应用趋势

PHP&#xff0c;作为Web开发领域的常青树&#xff0c;自1995年诞生以来&#xff0c;始终在动态网页开发中占据重要席位。随着技术的不断演进&#xff0c;PHP也在持续更新&#xff0c;以适应现代开发需求。本文将深入探讨PHP的最新发展动态及其在2025年的应用趋势。 PHP 8&…...

C#调用ACCESS数据库,解决“Microsoft.ACE.OLEDB.12.0”未注册问题

C#调用ACCESS数据库&#xff0c;解决“Microsoft.ACE.OLEDB.12.0”未注册问题 解决方法&#xff1a; 1.将C#采用的平台从AnyCpu改成X64 2.将官网下载的“Microsoft Access 2010 数据库引擎可再发行程序包AccessDatabaseEngine_X64”文件解压 3.安装解压后的文件 点击下载安…...

ubuntu22.04.5安装docker,解决安装出现的错误,解决Docker hello-world没打印出来

文章目录 前言一 安装失败解决1结合具体报错分析2 首先怀疑是VPN的问题3 直接百度报错信息4最终解决问题 二 验证Docker hello-world没打印出来总结 前言 先说一下前面的情况&#xff0c;使用的是公司的工作站&#xff0c;登录公司一个帐号使用的公司网络&#xff0c;使用网上…...

HMTL+JS+CSS实现贪吃蛇游戏,包含有一般模式,困难模式,还有无敌模式

HMTLJSCSS实现贪吃蛇游戏&#xff0c;包含有一般模式&#xff0c;困难模式&#xff0c;还有无敌模式&#xff08;可以穿墙死不了&#xff0c;从左边进去可以从右边出来&#xff09;&#xff0c;显示当前分数和最高分&#xff0c;吃到的球颜色可以叠加到蛇身体上 为了适配手机端…...

vue将页面导出成word

方法一&#xff1a;使用 html-docx-js html-docx-js 是一个轻量级的库&#xff0c;可以将 HTML 转换为 Word 文档。 安装依赖 首先安装 html-docx-js&#xff1a; Bash深色版本 npm install html-docx-js --save创建导出逻辑 在 Vue 组件中实现导出功能的代码如下&#xff1…...

Spring MVC 页面跳转方案与区别

SpringMVC 的页面跳转方案主要分为 ‌转发&#xff08;Forward&#xff09;‌ 和 ‌重定向&#xff08;Redirect&#xff09;‌ 两类&#xff0c;具体实现方式和区别如下&#xff1a; 一、页面跳转方案 1. ‌转发&#xff08;Forward&#xff09;‌ 默认方式‌&#xff1a;直…...

Open GL ES ->纹理贴图,顶点坐标和纹理坐标组合到同一个顶点缓冲对象中进行解析

XML文件 <?xml version"1.0" encoding"utf-8"?> <com.example.myapplication.MyGLSurfaceView2 xmlns:android"http://schemas.android.com/apk/res/android"android:id"id/glSurfaceView"android:layout_width"matc…...

题解:AT_arc050_c [ARC050C] LCM 111

一道比较简单的题。&#xff08;我绝对不会告诉你这题我改了很久&#xff09; 题目意思很简单&#xff0c;我就不过多解释了&#xff0c;我们直接进入正题。 题目要我们求 a a a 个 1 1 1 组成的数与 b b b 个 1 1 1 组成的数的最小公倍数除以 m m m 后的余数。先不考虑…...

【408--考研复习笔记】计算机网络----知识点速览

目录 一、计算机网络体系结构 1.计算机网络的定义与功能&#xff1a; 2.网络体系结构相关概念&#xff1a; 3.OSI 七层模型与 TCP/IP 模型&#xff1a; 4.通信方式与交换技术&#xff1a; 电路交换 报文交换 分组交换 5.端到端通信和点到点通信&#xff1a; 6.计算机…...

ISIS报文

IS-IS 报文 目录 IS-IS 报文 一、报文类型与功能 二、报文结构解析 三、核心功能特性 四、典型应用场景 五、抓包数据分析 六、总结 IS-IS&#xff08;中间系统到中间系统&#xff09;协议报文是用于链路状态路由协议中网络设备间交换路由信息的关键载体&#xff0c;其设…...

FPGA——分秒计数器

文章目录 一、实验任务二、系统模块三、工程源码四、管脚信息五、运行结果参考资料总结 一、实验任务 在DE2-115板子上用 Verilog编程实现一个分秒计数器&#xff0c;并具备按键暂停、按键消抖功能。 二、系统模块 分频模块 高频时钟&#xff08;如50MHz&#xff09;分频得到…...

【Java】JVM

一、JVM体系结构 1、虚拟机概述 虚拟机&#xff08;Virtual Machine&#xff09;&#xff1a;一台虚拟的计算机&#xff0c;指一种特殊的软件&#xff0c;他可以在计算机平台和终端用户之间创建一种环境&#xff0c;而终端用户则是基于这个软件所创建的环境来操作软件。虚拟机…...

vue中使用geoscene无法出现弹窗

项目场景&#xff1a; 平日对地图加载使用不复杂的情况下&#xff0c;我通常采用leaflet去加载地图做一些简单的操作。但是最近需要用到arcgis发布的地图服务加载三维场景&#xff0c;于是又用回了geoscene&#xff08;arcgis国产化&#xff09;。这下暴露出很多的问题&#x…...

【Go】数组

数组Array 重点&#xff1a; 数组是值类型 注意点: 1. 数组&#xff1a;是同一种数据类型的固定长度的序列。2. 数组定义&#xff1a;var a [len]int&#xff0c;比如&#xff1a;var a [5]int&#xff0c;数组长度必须是常量&#xff0c;且是类型的组成部分。一旦定义&…...

【运维】Centos硬盘满导致开机时处于加载状态无法开机解决办法

Centos硬盘存储过满导致无法加载 一、准备1.现象2.根因分析3.制定救援方案问题1&#xff1a;无法进入系统确定分析结论 问题2&#xff1a;磁盘数据过多 4.后处理 一、准备 1.现象 Centos虚拟机界面卡顿&#xff0c;随后进行了重启操作&#xff0c;发现重新启动界面一直卡在加…...

JVM——模型分析、回收机制

方法区&#xff1a;存储已被虚拟机加载的类元数据信息(元空间) 堆&#xff1a;存放对象实例&#xff0c;几乎所有的对象实例都在这里分配内存 虚拟机栈&#xff1a;虚拟机栈描述的是|ava方法执行的内存模型:每个方法被执行的时候都会同时创建一个栈帧(Stack Frame)用于存储局…...

kafka 4.x docker启动kafka4.0.0 docker-compose启动最新版kafka 如何使用docker容器启动最新版kafka

1. 镜像选择标签&#xff1a; https://hub.docker.com/r/bitnami/kafka/tags 2. 命令&#xff1a; docker pull bitnami/kafka:4.0.0 3. docker-compose.yml 启动kafka4.0.0&#xff1a; version: 3services:kafka:image: bitnami/kafka:4.0.0container_name: kafkaports:- &…...

BUUCTF-web刷题篇(6)

15.PHP 知识点&#xff1a; ①__wakeup()//将在反序列化之后立即调用&#xff08;当反序列化时变量个数与实际不符是会绕过&#xff09;我们可以通过一个cve来绕过:CVE-2016-7124。将Object中表示数量的字段改成比实际字段大的值即可绕过wakeup函数。条件&#xff1a;PHP5<…...

MySQL篇(一):慢查询定位及索引、B树相关知识详解

MySQL篇&#xff08;一&#xff09;&#xff1a;慢查询定位及索引、B树相关知识详解 MySQL篇&#xff08;一&#xff09;&#xff1a;慢查询定位及索引、B树相关知识详解一、MySQL中慢查询的定位&#xff08;一&#xff09;慢查询日志的开启&#xff08;二&#xff09;慢查询日…...

QT之QML(简单示例)

需求一&#xff1a;点击按钮弹出菜单&#xff0c;并且自定义菜单弹出位置。 mouse.x 和 mouse.y 获取的是相对于 MouseArea&#xff08;在这个例子中是 Button&#xff09;左上角的局部坐标。如果你想要在鼠标点击位置显示 Menu&#xff0c;你需要将这个局部坐标转换为相对于应…...

自动化释放linux服务器内存脚本

脚本说明 使用Linux的Cron定时任务结合Shell脚本来实现自动化的内存释放。 脚本用到sync系统命令 sync的作用&#xff1a;sync 是一个 Linux 系统命令&#xff0c;用于将文件系统缓存中的数据强制写入磁盘。 在你执行reboot、poweroff、shutdown命令时&#xff0c;系统会默认执…...

Linux中的权限管理

一、权限的概念 在 Linux 系统的架构里&#xff0c;权限是构建安全堡垒的基石&#xff0c;精准界定了不同用户对文件与目录的操作边界&#xff0c;对系统安全的维护以及数据完整性的保障起着决定性作用。 1.权限的三种基础类别&#xff1a; 权限对文件的影响对目录的影响 读(r…...

Java对象与JSON字符串的互转

最近&#xff0c;工作中会涉及到Java对象与JSON字符串相互转换&#xff0c;虽然说并不难&#xff0c;但打算还是梳理一番&#xff0c;主要内容有&#xff1a; JSON 字符串 转 普通对象 普通对象 转 JSON 字符串 JSON 字符串数组 转 List 集合对象 List 集合对象 转 JSON 字符串…...

[笔记.AI]向量化

&#xff08;借助 DeepSeek-V3 辅助生成&#xff09; 向量化的定义 向量化&#xff08;Vectorization&#xff09; 是将文本、图像、音频等非结构化数据转换为高维数值向量&#xff08;即一组数字&#xff09;的过程。这些向量能够捕捉数据的语义、特征或上下文信息&#x…...

NSSCTF(MISC)—[justCTF 2020]pdf

相应的做题地址&#xff1a;https://www.nssctf.cn/problem/920 binwalk分离 解压文件2AE59A.zip mutool 得到一张图片 B5F31内容 B5FFD内容 转换成图片 justCTF{BytesAreNotRealWakeUpSheeple}...

Angular的理解

Angular 是一个由 Google 维护的全功能前端框架&#xff0c;适合构建复杂的企业级应用。它采用 TypeScript 作为首选语言&#xff0c;提供了一套完整的解决方案&#xff0c;包括数据绑定、依赖注入、路由、表单处理等。 1. Angular 的核心概念 1.1 组件化架构 Angular 应用由…...

广告推荐算法:COSMO算法与A9算法的对比

COSMO算法与A9算法的概念解析 1. A9算法 定义与背景&#xff1a; A9算法是亚马逊早期为电商平台研发的核心搜索算法&#xff0c;主要用于优化商品搜索结果的排序和推荐&#xff0c;其核心逻辑围绕产品属性与关键词匹配展开。自2003年推出以来&#xff0c;A9通过分析商品标题…...

10. 七大排序(含四种版本快排及优化) ******

排序算法时间复杂度(平均)时间复杂度(最坏)时间复杂度(最好)空间复杂度稳定性主要使用场景直接插入排序O(n)O(n)O(n)O(1)稳定小规模数据或基本有序数据希尔排序O(n^1.3)O(n)O(n log n)O(1)不稳定中等规模数据&#xff0c;对稳定性无要求选择排序O(n)O(n)O(n)O(1)不稳定小规模数…...

以下是C/C++后台开发常见的高概率面试题

一、语言基础 多态的实现 通过虚函数表&#xff08;vtable&#xff09;实现动态绑定&#xff0c;运行时根据对象类型调用对应的函数。虚函数通过virtual关键字声明&#xff0c;子类可重写基类虚函数112。 指针与引用的区别 指针是变量&#xff0c;存储地址&#xff0c;支持多…...

CentOS-查询实时报错日志-查询前1天业务报错gz压缩日志

最新版本更新 https://code.jiangjiesheng.cn/article/364?from=csdn 推荐 《高并发 & 微服务 & 性能调优实战案例100讲 源码下载》 1. 查询实时报错日志 物理路径(带*的放在靠后,或者不用*) cd /home/logs/java-gz-log-dir && tail -2000f java-gz-l…...

破界·共生:生成式人工智能(GAI)认证重构普通人的AI进化图谱

在当今这个科技日新月异的时代,人工智能(AI)正以惊人的速度改变着我们的世界。从智能家居到自动驾驶,从医疗诊断到金融分析,AI的应用已经渗透到社会生活的方方面面。面对如此迅猛的发展态势,我们不禁要问:人工智能的未来将走向何方?普通人又该如何把握这一历史机遇,学…...

HTTP代理:网页加速的隐形引擎

目录 引言&#xff1a;网页加载速度为何至关重要&#xff1f; 一、HTTP代理的核心加速原理 二、四大加速黑科技详解 三、实战场景性能对比 四、代理加速的隐藏代价 五、未来发展趋势 结语&#xff1a;智能代理的选型指南 引言&#xff1a;网页加载速度为何至关重要&#…...

Unity 常见报错 定位和查找方法

1.控制台 直接看报错信息 2.打log 例子&#xff1a; for(int i 0;i < 8;i) {Debug.Log(i);//这是打的log,看看到底i是几的时候出问题gameObject.name strs[i];} 3.断点调试 &#xff08;1&#xff09;在你想打断点的行&#xff0c;左边空白处点击可以打断点&#xff…...

人工智能之数学基础:初等反射阵

本文重点 在线性代数中,初等反射阵(Householder矩阵)作为一类特殊的正交矩阵,在矩阵变换、特征值计算及几何变换等领域具有广泛应用。其简洁的构造方式和丰富的数学性质,使其成为数值分析和几何处理中的重要工具。 什么是初等反射阵(豪斯霍尔德变换) I为单位矩阵,wwT…...

《Linux运维总结:基于银河麒麟V10操作系统+ARM64架构CPU二进制部署单机ACL版consul v1.18.1》

总结:整理不易,如果对你有帮助,可否点赞关注一下? 更多详细内容请参考:《Linux运维篇:Linux系统运维指南》 一、简介 1、什么是consul Consul是HashiCorp公司推出的开源工具,用于实现 分布式系统的服务发现与配置。 Consul是分布式的、高可用的、可横向扩展的。 架构图…...

web网站页面测试点---添加功能测试

添加 一、创建新的申请时&#xff0c;关闭网络查看数据是否存在&#xff0c;并提示网络错位相关提示语 二、在文本框内输入数据 1.在文本框内输入空格&#xff0c;查看文本内容前后是否存在空格 2.在文本框内输入最大长度&#xff0c;查看能否正确提交 3.在文本框内输入最大长…...

实操自动生成接口自动化测试用例

​这期抽出来的问题是关于如何使用Eolinker自动生成接口自动化测试用例&#xff0c;也就是将API文档变更同步到测试用例&#xff0c;下面是流程的示例解析。 导入并关联API文档和自动化测试用例 首先是登陆Eolinker&#xff0c;可以直接在线使用。 进入流程测试用例详情页&am…...

【华为OD技术面试真题 - 技术面】- Java面试题(17)

华为OD面试真题精选 专栏:华为OD面试真题精选 目录: 2024华为OD面试手撕代码真题目录以及八股文真题目录 文章目录 华为OD面试真题精选虚拟机分区1. **虚拟磁盘分区**2. **虚拟机的内存分区**3. **CPU分配**4. **虚拟网络分区**5. **存储虚拟化和分区**6. **虚拟机分区管理**…...

mapState 函数的用法

mapState 是 Vuex 提供的一个辅助函数&#xff0c;其主要作用是将 Vuex 仓库中的状态映射到组件的计算属性中&#xff0c;这样在组件里就能像访问本地计算属性一样访问 Vuex 仓库中的状态。以下为你详细介绍 mapState 函数的不同用法。 1. 基本用法&#xff1a;对象形式 当使…...

【学Rust写CAD】17 通用2D仿射变换矩阵结构体(matrix/generic.rs)

源代码 // matrix.rs use std::ops::{Add, Mul};use std::ops::{Add, Mul};/// 通用2D仿射变换矩阵&#xff08;元素仅需Copy&#xff09; #[derive(Clone, Copy, Debug, PartialEq)] pub struct Matrix<X, Y, Xx, Xy, Yx, Yy> {pub x: X, pub y: Y,pub xx: Xx, pub xy:…...