2024 - 两台CentOS服务器上的1000个Docker容器(每台500个)之间实现UDP通 ...

守听  金牌会员 | 2024-11-4 23:45:04 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 811|帖子 811|积分 2433

两台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。如果还未安装,请按照以下步调进行:
  1. # 更新包索引
  2. sudo yum update -y
  3. # 安装必要的包
  4. sudo yum install -y yum-utils device-mapper-persistent-data lvm2
  5. # 添加Docker仓库
  6. sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
  7. # 安装Docker CE
  8. sudo yum install -y docker-ce docker-ce-cli containerd.io
  9. # 启动Docker服务
  10. sudo systemctl start docker
  11. # 设置Docker开机自启
  12. sudo systemctl enable docker
复制代码
留意:


  • 权限题目:默认情况下,只有root用户或docker组的用户才能运行Docker命令。为了方便,您可以将当前用户添加到docker组:
    1. sudo usermod -aG docker $(whoami)
    复制代码
    然退却出并重新登录以使更改生效。
1.2 检查网络连通性(但是 我们必要 检测两台服务器是否可以走的通的!⚠️)(从这一步出发 ❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️)

确保两台服务器之间可以互相访问。


  • 测试连接
    1. # 在服务器B上,尝试ping服务器A
    2. ping <服务器A的IP地址>
    复制代码
  • 留意:如果ping不通,可能必要检查网络配置或联系网络管理员。

2. 编写UDP服务器程序 (下面是 重点了,请您仔细阅读,一步一步来,不要着急)

在服务器A上,创建一个目录来存放代码:
  1. mkdir ~/udp_project
  2. cd ~/udp_project
复制代码
2.1 代码示例

创建一个名为udp_server.c的文件,内容如下:
  1. // udp_server.c
  2. /*
  3. * UDP服务器程序
  4. * 监听指定的UDP端口并接收消息。
  5. *
  6. * 编译:
  7. *   gcc -o udp_server udp_server.c
  8. *
  9. * 用法:
  10. *   ./udp_server <端口号>
  11. */
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <unistd.h>
  15. #include <string.h>
  16. #include <sys/types.h>
  17. #include <sys/socket.h>
  18. #include <arpa/inet.h>
  19. #define BUFFER_SIZE 1024  // 接收消息的最大缓冲区大小
  20. int main(int argc, char *argv[]) {
  21.     int sockfd;                        // 套接字文件描述符
  22.     int port;                          // 监听的端口号
  23.     struct sockaddr_in server_addr;    // 服务器地址结构
  24.     struct sockaddr_in client_addr;    // 客户端地址结构
  25.     char buffer[BUFFER_SIZE];          // 接收消息的缓冲区
  26.     socklen_t addr_len;                // 客户端地址结构的大小
  27.     ssize_t recv_len;                  // 接收到的消息长度
  28.     // 检查参数数量是否正确
  29.     if (argc != 2) {
  30.         fprintf(stderr, "用法: %s <端口号>\n", argv[0]);
  31.         exit(1);
  32.     }
  33.     // 将端口号从字符串转换为整数
  34.     port = atoi(argv[1]);
  35.     // 创建UDP套接字
  36.     if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
  37.         perror("socket 创建失败");
  38.         exit(1);
  39.     }
  40.     // 将服务器地址结构清零
  41.     memset(&server_addr, 0, sizeof(server_addr));
  42.     // 设置地址族为AF_INET(IPv4)
  43.     server_addr.sin_family = AF_INET;
  44.     // 监听所有可用的网络接口
  45.     server_addr.sin_addr.s_addr = INADDR_ANY;
  46.     // 设置端口号(将主机字节序转换为网络字节序)
  47.     server_addr.sin_port = htons(port);
  48.     // 将套接字绑定到指定的端口上
  49.     if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
  50.         perror("绑定失败");
  51.         close(sockfd);
  52.         exit(1);
  53.     }
  54.     printf("UDP服务器正在监听端口 %d\n", port);
  55.     // 无限循环,持续接收消息
  56.     while (1) {
  57.         addr_len = sizeof(client_addr);
  58.         // 接收消息
  59.         recv_len = recvfrom(sockfd, buffer, BUFFER_SIZE - 1, 0,
  60.                             (struct sockaddr *)&client_addr, &addr_len);
  61.         if (recv_len < 0) {
  62.             perror("接收失败");
  63.             continue;
  64.         }
  65.         // 在接收到的数据末尾添加字符串结束符
  66.         buffer[recv_len] = '\0';
  67.         // 打印客户端信息和消息内容
  68.         printf("从 %s:%d 收到消息:%s\n",
  69.                inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port), buffer);
  70.     }
  71.     // 关闭套接字(实际上不会到达这里)
  72.     close(sockfd);
  73.     return 0;
  74. }
复制代码
2.2 详细注释



  • 头文件包罗:包罗了网络编程和基本的C库函数所需的头文件。
  • 宏定义:定义了缓冲区巨细BUFFER_SIZE。
  • main函数参数检查:确保运行程序时传入了正确的参数(端口号)。
  • 套接字创建:使用socket()函数创建一个UDP套接字。
  • 地址布局初始化:使用memset()清零,然后设置地址族、IP地址和端口号。
  • 绑定套接字:使用bind()函数将套接字绑定到指定的IP和端口上。
  • 接收循环:使用recvfrom()函数接收来自客户端的消息,并打印出来。

3. 编写UDP客户端程序

在服务器B上,同样创建一个目录:
  1. mkdir ~/udp_project
  2. cd ~/udp_project
复制代码
3.1 代码示例

创建一个名为udp_client.c的文件,内容如下:
  1. // udp_client.c
  2. /*
  3. * UDP客户端程序
  4. * 向指定的IP地址和UDP端口发送消息。
  5. *
  6. * 编译:
  7. *   gcc -o udp_client udp_client.c
  8. *
  9. * 用法:
  10. *   ./udp_client <服务器IP> <服务器端口> <消息>
  11. */
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <unistd.h>
  15. #include <string.h>
  16. #include <sys/types.h>
  17. #include <sys/socket.h>
  18. #include <arpa/inet.h>
  19. #define BUFFER_SIZE 1024  // 消息的最大缓冲区大小
  20. int main(int argc, char *argv[]) {
  21.     int sockfd;                        // 套接字文件描述符
  22.     char *server_ip;                   // 服务器IP地址
  23.     int server_port;                   // 服务器端口号
  24.     struct sockaddr_in server_addr;    // 服务器地址结构
  25.     char *message;                     // 要发送的消息
  26.     ssize_t sent_len;                  // 发送的消息长度
  27.     // 检查参数数量是否正确
  28.     if (argc != 4) {
  29.         fprintf(stderr, "用法: %s <服务器IP> <服务器端口> <消息>\n", argv[0]);
  30.         exit(1);
  31.     }
  32.     // 获取服务器IP、端口和消息
  33.     server_ip = argv[1];
  34.     server_port = atoi(argv[2]);
  35.     message = argv[3];
  36.     // 创建UDP套接字
  37.     if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
  38.         perror("socket 创建失败");
  39.         exit(1);
  40.     }
  41.     // 将服务器地址结构清零
  42.     memset(&server_addr, 0, sizeof(server_addr));
  43.     // 设置地址族为AF_INET(IPv4)
  44.     server_addr.sin_family = AF_INET;
  45.     // 将IP地址从文本转换为二进制形式
  46.     if (inet_pton(AF_INET, server_ip, &server_addr.sin_addr) <= 0) {
  47.         fprintf(stderr, "无效的IP地址:%s\n", server_ip);
  48.         close(sockfd);
  49.         exit(1);
  50.     }
  51.     // 设置端口号(网络字节序)
  52.     server_addr.sin_port = htons(server_port);
  53.     // 发送消息到服务器
  54.     sent_len = sendto(sockfd, message, strlen(message), 0,
  55.                       (struct sockaddr *)&server_addr, sizeof(server_addr));
  56.     if (sent_len < 0) {
  57.         perror("发送失败");
  58.         close(sockfd);
  59.         exit(1);
  60.     }
  61.     printf("已向 %s:%d 发送消息:%s\n", server_ip, server_port, message);
  62.     // 关闭套接字
  63.     close(sockfd);
  64.     return 0;
  65. }
复制代码
3.2 详细注释



  • 参数检查:确保提供了服务器IP、端口和消息。
  • 套接字创建:同样使用socket()函数创建UDP套接字。
  • 地址布局设置:将服务器的IP和端口填入server_addr布局。
  • 发送消息:使用sendto()函数发送消息到服务器。

4. 创建Docker镜像

4.1 编写Dockerfile

在两台服务器的udp_project目录下,创建一个名为Dockerfile的文件,内容如下:
  1. # 使用官方的GCC镜像作为基础镜像
  2. FROM gcc:latest
  3. # 在容器内创建工作目录
  4. WORKDIR /usr/src/app
  5. # 将源代码复制到容器内
  6. COPY udp_server.c udp_client.c ./
  7. # 编译UDP服务器和客户端程序
  8. RUN gcc -o udp_server udp_server.c
  9. RUN gcc -o udp_client udp_client.c
  10. # 暴露默认端口(可在运行时覆盖)
  11. EXPOSE 5000/udp
  12. # 设置默认命令(可在运行容器时覆盖)
  13. 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镜像:
  1. docker build -t udp_app .
复制代码
留意:


  • 镜像名称:udp_app是镜像的名称,您可以根据必要更改。
  • 构建过程:Docker会根据Dockerfile的指令一步步构建镜像。

5. 运行服务器容器(服务器A)

5.1 编写运行脚本

在服务器A的udp_project目录下,创建一个名为run_servers.sh的脚本,内容如下:
  1. #!/bin/bash
  2. # 要运行的服务器容器数量
  3. NUM_CONTAINERS=500
  4. # 服务器的基础端口号
  5. BASE_PORT=5000
  6. for (( i=1; i<=NUM_CONTAINERS; i++ ))
  7. do
  8.     CONTAINER_NAME="server_$i"
  9.     HOST_PORT=$((BASE_PORT + i))
  10.     CONTAINER_PORT=$((BASE_PORT + i))
  11.     # 运行服务器容器
  12.     docker run -d --name $CONTAINER_NAME -p $HOST_PORT:$CONTAINER_PORT/udp udp_app ./udp_server $CONTAINER_PORT
  13.     echo "已在端口 $HOST_PORT 启动服务器容器 $CONTAINER_NAME"
  14. done
复制代码
5.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的脚本,内容如下:
  1. #!/bin/bash
  2. # 要运行的客户端容器数量
  3. NUM_CONTAINERS=500
  4. # 客户端的基础端口号(用于区分消息)
  5. BASE_PORT=5000
  6. # 服务器A的IP地址
  7. SERVER_A_IP="请替换为服务器A的实际IP地址"
  8. for (( i=1; i<=NUM_CONTAINERS; i++ ))
  9. do
  10.     CONTAINER_NAME="client_$i"
  11.     SERVER_PORT=$((BASE_PORT + i))
  12.     MESSAGE="来自客户端 $i 的问候"
  13.     # 运行客户端容器
  14.     docker run -d --name $CONTAINER_NAME udp_app ./udp_client $SERVER_A_IP $SERVER_PORT "$MESSAGE"
  15.     echo "已启动客户端容器 $CONTAINER_NAME,发送到 $SERVER_A_IP:$SERVER_PORT"
  16. done
复制代码
6.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流量通过指定的端口,必要修改防火墙设置。
  1. # 添加端口范围的UDP规则
  2. sudo firewall-cmd --zone=public --add-port=5001-5500/udp --permanent
  3. # 重新加载防火墙
  4. sudo firewall-cmd --reload
复制代码
留意:


  • 防火墙软件:如果使用的是firewalld,上述命令实用。如果使用其他防火墙,必要使用相应的命令。
  • 端口范围:确保与您在脚本中使用的端口范围同等。
7.2 检查网络连接

在服务器B上,测试是否可以连接到服务器A的指定端口。
  1. # 使用nc(netcat)工具测试UDP端口
  2. echo "测试" | nc -u -v <服务器A的IP地址> 5001
复制代码
如果连接乐成,说明网络连通性正常。

8. 验证通信

8.1 检查服务器日志

在服务器A上,检察某个服务器容器的日志,比方server_1:
  1. docker logs server_1
复制代码
您应该看到类似以下的输出:
  1. UDP服务器正在监听端口 5001
  2. 从 <客户端IP>:<端口> 收到消息:来自客户端 1 的问候
复制代码
8.2 确认消息接收



  • 多个容器日志:可以检查其他服务器容器的日志,确认是否收到了对应客户端的消息。
  • 故障排查:如果没有收到消息,请检查以下内容:

    • 服务器A的防火墙设置:确保开放了必要的UDP端口。
    • 服务器IP地址是否正确:在run_clients.sh脚本中。
    • 网络连通性:使用ping或nc测试。


9. 留意事项和可能的题目

9.1 体系资源限制



  • CPU和内存:运行大量容器会占用大量体系资源。请监控体系的CPU和内存使用情况。
  • 文件形貌符限制:可能必要增加体系的文件形貌符限制。
    1. # 临时增加限制
    2. ulimit -n 65535
    复制代码
9.2 防火墙和安全性



  • 安全策略:确保只允允许信任的流量。对于生产情况,发起使用VPN或设置访问控制。
  • 端口范围:开放大量端口可能存在安全风险,务必确保网络的安全性。
9.3 日志和监控



  • 日志收集:考虑使用日志收集工具,如ELK堆栈,来集中管理容器日志。
  • 监控工具:使用监控工具,如Prometheus和Grafana,监控体系性能和容器状态。

10. 总结

通过以上步调,您已经乐成在两台CentOS服务器上的1000个Docker容器之间创建了UDP通信。我们使用C语言编写了简单的UDP服务器和客户端程序,并使用Docker来管理容器的部署。
您必要留意的关键点:


  • IP地址和端口号:确保在脚本和代码中使用正确的IP地址和端口号。
  • 防火墙配置:确保防火墙允许必要的UDP流量通过。
  • 体系资源:监控体系的资源使用,防止过载。
  • 代码编译:如果修改了C代码,必要重新构建Docker镜像。


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

守听

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表