安庆网站建设为,网站一片空白,智邦国际的crm系统,太原跨境电商两台CentOS服务器上的1000个Docker容器#xff08;每台500个#xff09;之间实现UDP通信(C语言版本) 给女朋友对象写得#xff0c;她不会#xff0c;我就写了一个 为了帮助您在两台CentOS服务器上的1000个Docker容器#xff08;每台500个#xff09;之间实现UDP通信…两台CentOS服务器上的1000个Docker容器每台500个之间实现UDP通信(C语言版本) 给女朋友对象写得她不会我就写了一个 为了帮助您在两台CentOS服务器上的1000个Docker容器每台500个之间实现UDP通信我将详细地逐步指导您完成整个过程。我们将使用C语言编写UDP服务器和客户端程序并使用Docker来管理容器和网络配置。 我会在每个步骤中明确指出您需要修改的地方以及需要特别注意的事项。由于您是初学者我会尽量以简单易懂的方式来解释。 请您一步一步来看 仔细阅读里面相关的注意事项哦~~
重点
❤️你拿到过后你先仔细的全部浏览一遍再去动手操作哦~ 目录
环境准备 安装Docker检查网络连通性 编写UDP服务器程序 代码示例详细注释 编写UDP客户端程序 代码示例详细注释 创建Docker镜像 编写Dockerfile构建镜像 运行服务器容器服务器A 编写运行脚本解释脚本内容 运行客户端容器服务器B 编写运行脚本解释脚本内容 网络和防火墙配置 修改防火墙设置检查网络连接 验证通信 检查服务器日志确认消息接收 注意事项和可能的问题 系统资源限制防火墙和安全性日志和监控 总结 1. 环境准备
1.1 安装Docker 这个我们安装了可以 跳过了❤️
在两台CentOS服务器上都需要安装Docker。如果还未安装请按照以下步骤进行
# 更新包索引
sudo yum update -y# 安装必要的包
sudo yum install -y yum-utils device-mapper-persistent-data lvm2# 添加Docker仓库
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo# 安装Docker CE
sudo yum install -y docker-ce docker-ce-cli containerd.io# 启动Docker服务
sudo systemctl start docker# 设置Docker开机自启
sudo systemctl enable docker注意 权限问题默认情况下只有root用户或docker组的用户才能运行Docker命令。为了方便您可以将当前用户添加到docker组 sudo usermod -aG docker $(whoami)然后退出并重新登录以使更改生效。
1.2 检查网络连通性但是 我们需要 检测两台服务器是否可以走的通的⚠️从这一步出发 ❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️
确保两台服务器之间可以互相访问。 测试连接 # 在服务器B上尝试ping服务器A
ping 服务器A的IP地址注意如果ping不通可能需要检查网络配置或联系网络管理员。 2. 编写UDP服务器程序 下面是 重点了请您仔细阅读一步一步来不要着急
在服务器A上创建一个目录来存放代码
mkdir ~/udp_project
cd ~/udp_project2.1 代码示例
创建一个名为udp_server.c的文件内容如下
// udp_server.c/** UDP服务器程序* 监听指定的UDP端口并接收消息。** 编译* gcc -o udp_server udp_server.c** 用法* ./udp_server 端口号*/#include stdio.h
#include stdlib.h
#include unistd.h
#include string.h
#include sys/types.h
#include sys/socket.h
#include arpa/inet.h#define BUFFER_SIZE 1024 // 接收消息的最大缓冲区大小int main(int argc, char *argv[]) {int sockfd; // 套接字文件描述符int port; // 监听的端口号struct sockaddr_in server_addr; // 服务器地址结构struct sockaddr_in client_addr; // 客户端地址结构char buffer[BUFFER_SIZE]; // 接收消息的缓冲区socklen_t addr_len; // 客户端地址结构的大小ssize_t recv_len; // 接收到的消息长度// 检查参数数量是否正确if (argc ! 2) {fprintf(stderr, 用法: %s 端口号\n, argv[0]);exit(1);}// 将端口号从字符串转换为整数port atoi(argv[1]);// 创建UDP套接字if ((sockfd socket(AF_INET, SOCK_DGRAM, 0)) 0) {perror(socket 创建失败);exit(1);}// 将服务器地址结构清零memset(server_addr, 0, sizeof(server_addr));// 设置地址族为AF_INETIPv4server_addr.sin_family AF_INET;// 监听所有可用的网络接口server_addr.sin_addr.s_addr INADDR_ANY;// 设置端口号将主机字节序转换为网络字节序server_addr.sin_port htons(port);// 将套接字绑定到指定的端口上if (bind(sockfd, (struct sockaddr *)server_addr, sizeof(server_addr)) 0) {perror(绑定失败);close(sockfd);exit(1);}printf(UDP服务器正在监听端口 %d\n, port);// 无限循环持续接收消息while (1) {addr_len sizeof(client_addr);// 接收消息recv_len recvfrom(sockfd, buffer, BUFFER_SIZE - 1, 0,(struct sockaddr *)client_addr, addr_len);if (recv_len 0) {perror(接收失败);continue;}// 在接收到的数据末尾添加字符串结束符buffer[recv_len] \0;// 打印客户端信息和消息内容printf(从 %s:%d 收到消息%s\n,inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port), buffer);}// 关闭套接字实际上不会到达这里close(sockfd);return 0;
}2.2 详细注释
头文件包含包含了网络编程和基本的C库函数所需的头文件。宏定义定义了缓冲区大小BUFFER_SIZE。main函数参数检查确保运行程序时传入了正确的参数端口号。套接字创建使用socket()函数创建一个UDP套接字。地址结构初始化使用memset()清零然后设置地址族、IP地址和端口号。绑定套接字使用bind()函数将套接字绑定到指定的IP和端口上。接收循环使用recvfrom()函数接收来自客户端的消息并打印出来。 3. 编写UDP客户端程序
在服务器B上同样创建一个目录
mkdir ~/udp_project
cd ~/udp_project3.1 代码示例
创建一个名为udp_client.c的文件内容如下
// udp_client.c/** UDP客户端程序* 向指定的IP地址和UDP端口发送消息。** 编译* gcc -o udp_client udp_client.c** 用法* ./udp_client 服务器IP 服务器端口 消息*/#include stdio.h
#include stdlib.h
#include unistd.h
#include string.h
#include sys/types.h
#include sys/socket.h
#include arpa/inet.h#define BUFFER_SIZE 1024 // 消息的最大缓冲区大小int main(int argc, char *argv[]) {int sockfd; // 套接字文件描述符char *server_ip; // 服务器IP地址int server_port; // 服务器端口号struct sockaddr_in server_addr; // 服务器地址结构char *message; // 要发送的消息ssize_t sent_len; // 发送的消息长度// 检查参数数量是否正确if (argc ! 4) {fprintf(stderr, 用法: %s 服务器IP 服务器端口 消息\n, argv[0]);exit(1);}// 获取服务器IP、端口和消息server_ip argv[1];server_port atoi(argv[2]);message argv[3];// 创建UDP套接字if ((sockfd socket(AF_INET, SOCK_DGRAM, 0)) 0) {perror(socket 创建失败);exit(1);}// 将服务器地址结构清零memset(server_addr, 0, sizeof(server_addr));// 设置地址族为AF_INETIPv4server_addr.sin_family AF_INET;// 将IP地址从文本转换为二进制形式if (inet_pton(AF_INET, server_ip, server_addr.sin_addr) 0) {fprintf(stderr, 无效的IP地址%s\n, server_ip);close(sockfd);exit(1);}// 设置端口号网络字节序server_addr.sin_port htons(server_port);// 发送消息到服务器sent_len sendto(sockfd, message, strlen(message), 0,(struct sockaddr *)server_addr, sizeof(server_addr));if (sent_len 0) {perror(发送失败);close(sockfd);exit(1);}printf(已向 %s:%d 发送消息%s\n, server_ip, server_port, message);// 关闭套接字close(sockfd);return 0;
}3.2 详细注释
参数检查确保提供了服务器IP、端口和消息。套接字创建同样使用socket()函数创建UDP套接字。地址结构设置将服务器的IP和端口填入server_addr结构。发送消息使用sendto()函数发送消息到服务器。 4. 创建Docker镜像
4.1 编写Dockerfile
在两台服务器的udp_project目录下创建一个名为Dockerfile的文件内容如下
# 使用官方的GCC镜像作为基础镜像
FROM gcc:latest# 在容器内创建工作目录
WORKDIR /usr/src/app# 将源代码复制到容器内
COPY udp_server.c udp_client.c ./# 编译UDP服务器和客户端程序
RUN gcc -o udp_server udp_server.c
RUN gcc -o udp_client udp_client.c# 暴露默认端口可在运行时覆盖
EXPOSE 5000/udp# 设置默认命令可在运行容器时覆盖
CMD [./udp_server, 5000]解释
FROM指定基础镜像为官方的gcc镜像包含了GCC编译器。WORKDIR设置工作目录为/usr/src/app。COPY将udp_server.c和udp_client.c复制到容器内的工作目录。RUN编译服务器和客户端程序。EXPOSE暴露5000端口的UDP协议可在运行时指定其他端口。CMD设置容器启动时默认执行的命令。
4.2 构建镜像
在两个服务器的udp_project目录下执行以下命令构建Docker镜像
docker build -t udp_app .注意
镜像名称udp_app是镜像的名称您可以根据需要更改。构建过程Docker会根据Dockerfile的指令一步步构建镜像。 5. 运行服务器容器服务器A
5.1 编写运行脚本
在服务器A的udp_project目录下创建一个名为run_servers.sh的脚本内容如下
#!/bin/bash# 要运行的服务器容器数量
NUM_CONTAINERS500# 服务器的基础端口号
BASE_PORT5000for (( i1; iNUM_CONTAINERS; i ))
doCONTAINER_NAMEserver_$iHOST_PORT$((BASE_PORT i))CONTAINER_PORT$((BASE_PORT i))# 运行服务器容器docker run -d --name $CONTAINER_NAME -p $HOST_PORT:$CONTAINER_PORT/udp udp_app ./udp_server $CONTAINER_PORTecho 已在端口 $HOST_PORT 启动服务器容器 $CONTAINER_NAME
done5.2 解释脚本内容
循环从1到500依次启动500个容器。容器名称server_1、server_2、…、server_500。端口设置 主机端口HOST_PORT从5001到5500。容器端口CONTAINER_PORT与主机端口相同。 运行容器 -d后台运行容器。--name指定容器名称。-p将主机的UDP端口映射到容器的UDP端口。udp_app使用之前构建的镜像。./udp_server $CONTAINER_PORT在容器内执行的命令指定监听的端口。
需要您修改的地方
NUM_CONTAINERS如果您想运行不同数量的容器可以修改这个值。 6. 运行客户端容器服务器B
6.1 编写运行脚本
在服务器B的udp_project目录下创建一个名为run_clients.sh的脚本内容如下
#!/bin/bash# 要运行的客户端容器数量
NUM_CONTAINERS500# 客户端的基础端口号用于区分消息
BASE_PORT5000# 服务器A的IP地址
SERVER_A_IP请替换为服务器A的实际IP地址for (( i1; iNUM_CONTAINERS; i ))
doCONTAINER_NAMEclient_$iSERVER_PORT$((BASE_PORT i))MESSAGE来自客户端 $i 的问候# 运行客户端容器docker run -d --name $CONTAINER_NAME udp_app ./udp_client $SERVER_A_IP $SERVER_PORT $MESSAGEecho 已启动客户端容器 $CONTAINER_NAME发送到 $SERVER_A_IP:$SERVER_PORT
done6.2 解释脚本内容
服务器IP地址需要将SERVER_A_IP替换为服务器A的实际IP地址。循环启动500个客户端容器。容器名称client_1、client_2、…、client_500。服务器端口与服务器容器的端口对应从5001到5500。消息内容每个客户端发送一条包含自己编号的消息。运行容器 -d后台运行。--name容器名称。udp_app使用同样的镜像。./udp_client $SERVER_A_IP $SERVER_PORT $MESSAGE在容器内执行的命令指定服务器IP、端口和消息。
需要您修改的地方
SERVER_A_IP❤️一定要替换为服务器A的实际IP地址否则客户端无法连接到服务器❤️。NUM_CONTAINERS如果需要可以修改客户端容器的数量❤️。 7. 网络和防火墙配置
7.1 修改防火墙设置服务器A
为了允许UDP流量通过指定的端口需要修改防火墙设置。
# 添加端口范围的UDP规则
sudo firewall-cmd --zonepublic --add-port5001-5500/udp --permanent# 重新加载防火墙
sudo firewall-cmd --reload注意
防火墙软件如果使用的是firewalld上述命令适用。如果使用其他防火墙需要使用相应的命令。端口范围确保与您在脚本中使用的端口范围一致。
7.2 检查网络连接
在服务器B上测试是否可以连接到服务器A的指定端口。
# 使用ncnetcat工具测试UDP端口
echo 测试 | nc -u -v 服务器A的IP地址 5001如果连接成功说明网络连通性正常。 8. 验证通信
8.1 检查服务器日志
在服务器A上查看某个服务器容器的日志例如server_1
docker logs server_1您应该看到类似以下的输出
UDP服务器正在监听端口 5001
从 客户端IP:端口 收到消息来自客户端 1 的问候8.2 确认消息接收
多个容器日志可以检查其他服务器容器的日志确认是否收到了对应客户端的消息。故障排查如果没有收到消息请检查以下内容 服务器A的防火墙设置确保开放了必要的UDP端口。服务器IP地址是否正确在run_clients.sh脚本中。网络连通性使用ping或nc测试。 9. 注意事项和可能的问题
9.1 系统资源限制 CPU和内存运行大量容器会占用大量系统资源。请监控系统的CPU和内存使用情况。 文件描述符限制可能需要增加系统的文件描述符限制。 # 临时增加限制
ulimit -n 655359.2 防火墙和安全性
安全策略确保只允许可信任的流量。对于生产环境建议使用VPN或设置访问控制。端口范围开放大量端口可能存在安全风险务必确保网络的安全性。
9.3 日志和监控
日志收集考虑使用日志收集工具如ELK堆栈来集中管理容器日志。监控工具使用监控工具如Prometheus和Grafana监控系统性能和容器状态。 10. 总结
通过以上步骤您已经成功在两台CentOS服务器上的1000个Docker容器之间建立了UDP通信。我们使用C语言编写了简单的UDP服务器和客户端程序并利用Docker来管理容器的部署。
您需要注意的关键点
IP地址和端口号确保在脚本和代码中使用正确的IP地址和端口号。防火墙配置确保防火墙允许必要的UDP流量通过。系统资源监控系统的资源使用防止过载。代码编译如果修改了C代码需要重新构建Docker镜像。