Docker 容器网络:C++ 客户端 — 服务器应用程序。
一、说明
在下面的文章中, 将向您概述 docker 容器之间的通信。docker 通信的验证将通过运行 C++ 客户端-服务器应用程序和标准“ping”命令来执行。将构建并运行两个单独的 Docker 映像。
由于我会关注 docker 网络方面,因此不会提供 C++ 详细信息。有一个文件和易于理解的程序。我还假设读者了解 docker 的主要概念。在本文中,我不会穷尽 docker 网络的完整概念。为了进一步学习,我建议使用文档,可以在此处找到。
简单来说,Docker 概念是一个开放平台,允许软件工程师在容器的帮助下开发、集成和运行应用程序,并根据 Dockerfile 中的规范进行构建。
Docker 开发策略使用户能够将应用程序与基础设施分离,有效利用资源并按构建和计划交付应用程序。
首先,我将解释并为您提供有关通信两个 docker 映像的完整信息,这些映像可以部署在一台主机上(这种类型的 docker 网络通信将使用 docker BRIDGE)。
其次,我将展示 docker 概念OVERLAY NETWORK,其中 docker 映像将部署在单独的主机(和单独的网络)上。
通信方法将由同一客户端 — 服务器 C++ 应用程序或命令 ping 进行验证。
请注意,网络配置(在下一篇文章中描述)必须被视为一个简单的示例。通常,在每种情况下,网络架构都可以以不同的方式组织并连接许多不同的容器。
我还验证了云中的覆盖网络,将云 Linode 服务器上的主机与我的本地计算机连接起来(本文中未描述,因为我必须发布所有 IP 地址)。
二、Docker 中的桥接网络
2.1 网络构建
考虑下图,请注意,当连接在一台 Host上运行的容器时,会使用这种类型的通信。在我们的示例中,我们将在一个容器中运行 C++ 客户端,在另一个容器中运行 C++ 服务器(本文中包含的程序)。通过支持 docker 桥(通信管道)可以实现容器之间的通信,该桥可以关联为内部 ETH 网络(仅适用于在同一主机上运行的映像)。
您可以根据 Dockerfile 构建容器(一个用于客户端,一个用于服务器)。在检查容器通信时,您需要启动第一个服务器(运行服务器容器)。服务器将等待客户端,您从第二个容器启动客户端。
客户端向服务器发送 0-100 之间的随机数。服务器收集从客户端发送的接收信息并(作为字符串)添加:3.1415 并将包重新发送到客户端。
以下示例(docker 图像和 C++ 文件管理器)代表了我对软件和硬件的具体设置。您必须(或不必)更改客户端中的 IP 地址。我使用的端口是5555(你可以根据自己的喜好调整)。
按作者
2.2 客户端C++
// Client inspired by GeeksforGeeks#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string>
#include <string.h>
#include <iostream>
#include <stdlib.h>
#include <time.h>#define PORT 5555int main()
{int sock = 0, valread;struct sockaddr_in serv_addr;srand(time(NULL));char buffer[1024] = {0};if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0){std::cout << "Socket creation error" << std::endl;return -1;}serv_addr.sin_family = AF_INET;serv_addr.sin_port = htons(PORT);if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) //LOCAL//if(inet_pton(AF_INET, "172.17.0.2", &serv_addr.sin_addr)<=0) //CLIENT DOES NOT RUN IS CONTAINER//if(inet_pton(AF_INET, "172.21.0.1", &serv_addr.sin_addr)<=0) //CONTAINER//if(inet_pton(AF_INET, "10.0.9.1", &serv_addr.sin_addr)<=0) //OVERLAY{std::cout << "Address is invalid ... " << std::endl;return -1;}if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0){std::cout << "Connection Failed. Try again! ..." << std::endl;return -1;}int number = rand() % 100;std::cout << "check : " << number << std::endl;std::string str = std::to_string(number);char *cstr = &str[0];send(sock, cstr, strlen(cstr), 0);std::cout << "Message sent " << std::endl;valread = read(sock, buffer, 1024);std::cout << buffer << std::endl;return 0;
}
Dockerfile 客户端
FROM ubuntu:bionic #pull ubuntu
FROM gcc:latest #pull gcc
#just in case, you can install gcc and cmake
#RUN apt-get update && apt-get -y install build-essentials gcc cmake
ADD . /usr/src # add (copy) all from local folder to /usr/src
WORKDIR /usr/src
EXPOSE 5555
RUN g++ medium_client.cpp -o medium_client
# comment this and un - comment other if you would like to run your # program manually from shell
CMD ["./medium_client"]
#CMD ["/bin/bash"]
在终端(构建容器)上执行以下命令。
sudo docker build . -t client:1
2.3 服务器C++
// Server side C/C++ program to demonstrate Socket programming
// Server - inspired by GeeksforGeeks
#include <iostream>
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string>
#include <string.h>#define PORT 5555int main()
{int server_fd, new_socket, valread;struct sockaddr_in address;int opt = 1;int addrlen = sizeof(address);char buffer[1024] = {0};if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0){std::cout << "socket failed" << std::endl;exit(EXIT_FAILURE);}if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT,&opt, sizeof(opt))){std::cout << "socket failed" << std::endl;exit(EXIT_FAILURE);}address.sin_family = AF_INET;address.sin_addr.s_addr = INADDR_ANY;address.sin_port = htons(PORT);if (bind(server_fd, (struct sockaddr *)&address,sizeof(address)) < 0){std::cout << "bind failed" << std::endl;exit(EXIT_FAILURE);}if (listen(server_fd, 3) < 0){std::cout << "listen" << std::endl;exit(EXIT_FAILURE);}if ((new_socket = accept(server_fd, (struct sockaddr *)&address,(socklen_t *)&addrlen)) < 0){std::cout << "accept" << std::endl;exit(EXIT_FAILURE);}double pi = 3.1415;std::string str1 = "server => ";std::string str2 = std::to_string(pi);valread = read(new_socket, buffer, 1024);std::cout << buffer << std::endl;std::string str = str1 + " : " + str2 + " and " + buffer;char *cstr = &str[0];send(new_socket, cstr, strlen(cstr), 0);std::cout << "Message hass been sent!" << std::endl;return 0;
}
服务器 Dockerfile
FROM ubuntu:bionic
FROM gcc:latest
ADD . /usr/src
WORKDIR /usr/src
EXPOSE 5555
RUN g++ medium_server.cpp -o medium_server
# comment this and un - comment other if you would like to run your # program manually from shell
CMD ["./medium_server"]
#CMD ["/bin/bash"]
在终端上执行以下命令(构建容器)。
sudo docker build . -t server:1
执行以下命令创建桥接并检查通信。我假设您在容器(客户端和服务器)之前构建。
// inspect available docker networks (here is my setup) - see bridge is running as default
sudo docker network ls
接下来,您需要检查您的网桥并捕获网桥(容器)的 IP 地址。子网网络是您的服务器 cpp 程序内部需要的网络。如果您有其他的,请更改并重新运行容器构建。
现在你需要创建自己的网络(bridge是一个提供者)并指定你的名字,这里我使用home_net。
sudo docker network create –-driver bridge home_net
// confirm creation running again
sudo docker network ls
您的网络已创建,但为了为容器提供通信,两个容器都必须连接(到网络)。执行以下命令以运行容器并附加到您的网络 home_net。
请注意,您应该为 /bin/bash 构建两个容器(请参阅 Dockerfile 中的注释),以便首先使用命令行运行容器(而不运行构建容器时已编译的程序)。
sudo docker run -it -p 5555:5555 --network=home_net server:1
接下来再次检查您的网络。查看您的容器已连接到您的网络。
sudo docker network inspect home_net
对其他容器执行相同操作。
sudo docker run -it --network=home_net client:1
并检查(运行以下命令)。
sudo docker network inspect home_net
现在您的两个容器正在运行并连接到您的网络。
现在,执行以下命令(在正在运行的容器中)。从服务器启动表单。
./server_medium # container with server
./client_medium # container with client
现在您可以看到容器之间的一些通信。
三、Docker 中的覆盖网络
当您想要运行的 docker 容器位于不同的物理位置(在不同的物理主机上运行)时,您仍然可以将容器连接到其他容器。这里我们将在 Docker 中使用覆盖网络概念。
您可以想象,docker 容器可以与桥接通信类似,跨独立的虚拟网络(称为覆盖网络)发送和接收信息。
这意味着我们可以为容器构建私有虚拟网络,并且可以完全透明地交互。请考虑下图。在此示例中,我们可以重用图像和 C++ 客户端-服务器应用程序(IP 地址必须相应更改)。
请注意,在这两种情况下(桥接网络和覆盖网络),容器之间的通信也可以通过运行命令来验证:ping <host_IP_address>。对于当前网络(覆盖网络)将执行此类测试。然而,作者也在这种类型的 docker 架构中运行 C++ 应用程序(客户端 - 服务器)。当主机服务器部署在云端(Linode服务器)时,也验证了有关应用程序的验证。
对于这两种情况(桥接、覆盖),您有 4 种可能的选择来运行您的应用程序(取决于客户端的“位置”)。
在构建客户端映像之前,请考虑以下需要为medium_client.cpp 提供的IP 地址规范。
//CLIENT AND SERVER RUN LOCAL (NOT IN CONTAINERS)
if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0)
//CLIENT DOES NOT RUN IN CONTAINER. SERVER IN CONTAINER
//if(inet_pton(AF_INET, "172.17.0.2", &serv_addr.sin_addr)<=0)
//BRIDGE COMMUNICATION
//if(inet_pton(AF_INET, "172.21.0.1", &serv_addr.sin_addr)<=0)
//OVERLAY COMMUNICATION
//if(inet_pton(AF_INET, "10.0.9.1", &serv_addr.sin_addr)<=0)
使用覆盖网络的容器之间的通信将通过命令 ping 进行验证,但是正如我之前提到的,之前的 C++ 应用程序也可以工作。
运行以下命令(#Host 1 和 #Host 2)
3.1 主机1
首先使用主机 1 网络的 IP 地址初始化网络管理器。
sudo docker swarm init --advertise-addr 192.168.0.101
就我而言,我收到的输出如下。
3.2 主机1(内部主持人)
复制并运行命令:
docker swarm join --token SWMTKN-1-4pmk157a83i2nungc6jdtmh7vp4ujqich1pho141kox1dzxeiu-c6usd1wik2kl6p3ot7fhx4pd1 192.168.0.101:2377
您应该收到如下信息。
3.2 #主机1(其它)
运行以下命令并验证 swarm 管理器(上图之一显示了 swarm 和网桥)
sudo docker network ls
现在创建覆盖网络,这里我们的名字是overnet。
sudo docker network create -d overlay overnet
检查您创建的网络。验证身份等
sudo docker network inspect overnet
拉取两个 Ubuntu 映像(副本),激活网络并创建一个新服务 myservice。以下命令还发送 # Host 2 的图像
sudo docker service create --name myservice --network overnet --replicas 2 ubuntu sleep
运行以下命令确认您已完成的操作。
sudo docker service ls
sudo docker service ps myservice
现在确认您是否正确创建了覆盖网络并且两个容器都已连接。# 主机 1 的 IP 地址为 10.0.1.4。
运行命令
sudo docker network inspect overnet
3.3 主机2
运行相同的操作(我不显示图像,因为它与上面类似)。该主机收到地址IP 10.0.1.5
sudo docker network inspect overnet
3.4 #主机1和#主机2
运行以下命令来安装“ping 命令”。
apt-get update && apt-get install -y iputils-ping
在 #Host 1 和 2 上运行命令来捕获容器名称
sudo docker ps
并连接到 docker shell 以运行 ping
sudo docker exec -it 94835734987 sh
ping 10.0.1.5 # from host 1
ping 10.0.1.4 # from host 2
感谢您的阅读。
四、参考资源
凡本文遇到的代码资源可在下述地址下:
Networking overview | Docker Docs
相关文章:

Docker 容器网络:C++ 客户端 — 服务器应用程序。
一、说明 在下面的文章中, 将向您概述 docker 容器之间的通信。docker 通信的验证将通过运行 C 客户端-服务器应用程序和标准“ping”命令来执行。将构建并运行两个单独的 Docker 映像。 由于我会关注 docker 网络方面,因此不会提供 C 详细信息。…...

Android 识别车牌信息
打开我们心爱的Android Studio 导入需要的资源 gradle //开源车牌识别安卓SDK库implementation("com.github.HyperInspire:hyperlpr3-android-sdk:1.0.3")button.setOnClickListener(v -> {Log.d("Test", "");try (InputStream file getAs…...

C#在窗体正中输出文字以及输出文字的画刷使用
为了在窗体正中输出文字,需要获得输出文字区域的宽和高,这使用MeasureString方法,方法返回值为Size类型; 然后计算输出的起点的x和y坐标,就可以输出了; using System; using System.Collections.Generic; …...

二十、K8S-1-权限管理RBAC详解
目录 k8s RBAC 权限管理详解 一、简介 二、用户分类 1、普通用户 2、ServiceAccount 三、k8s角色&角色绑定 1、授权介绍: 1.1 定义角色: 1.2 绑定角色: 1.3主体(subject) 2、角色(Role和Cluster…...

【PTA|期末复习|编程题】数组相关编程题(一)
目录 7-1 乘法口诀数列 (20分) 输入格式: 输出格式: 输入样例: 输出样例: 样例解释: 代码 7-2 矩阵列平移(20分) 输入格式: 输出格式: 输入样例: 输出样例: …...

[office] 怎么在Excel2003菜单栏自定义一个选项卡 #其他#微信#知识分享
怎么在Excel2003菜单栏自定义一个选项卡 怎么在Excel2003菜单栏自定义一个选项卡 ①启动Excel2003,单击菜单栏--工具--自定义。 ②在自定义界面,我们单击命令标签,在类别中选择新菜单,鼠标左键按住新菜单,拖放到菜单栏…...
面试 JavaScript 框架八股文十问十答第六期
面试 JavaScript 框架八股文十问十答第六期 作者:程序员小白条,个人博客 相信看了本文后,对你的面试是有一定帮助的!关注专栏后就能收到持续更新! ⭐点赞⭐收藏⭐不迷路!⭐ 1)use strict是什么…...

【Web】小白友好的Java内存马基础学习笔记
目录 简介 文件马与内存马的比较 文件马原理 内存马原理 内存马使用场景 内存马分类 内存马注入方式 这篇文章主要是概念性的,具体技术细节不做探究,重点在祛魅。 简介 内存马(Memory Shellcode)是一种恶意攻击技术&…...
Rust猜数字游戏
Rust进阶:猜数字游戏 Rust是一门现代的系统级编程语言,注重内存安全、并发性能以及表达力。在这篇博客中,我们将深入介绍一个更加复杂的猜数字游戏代码,展示Rust语言的一些高级特性。 代码示例 以下是一个升级版的Rust猜数字游…...
.gitlab-ci.yml文件参数配置和使用
天行健,君子以自强不息;地势坤,君子以厚德载物。 每个人都有惰性,但不断学习是好好生活的根本,共勉! 文章均为学习整理笔记,分享记录为主,如有错误请指正,共同学习进步。…...
Go语言从基础到高级-目录
一、编程入门和Go语言简介 什么是编程和为什么要学习编程计算机编程的基本概念Go语言简介为什么选择Go语言 二、设置Go语言开发环境 如何安装Go语言设置环境变量Go语言的工作空间配置 三、Go语言基础 Hello, World!初体验变量和常量数据类型(整数、浮点数、字符…...
Linux CentOS stream 9 alias
alias命令在Linux中用于创建命令别名。它允许用户为常用的命令或命令组合创建短而易记的别名,从而提高工作效率。 alias命令与windows中的快捷方式相同,执行别名时,终端解释器就进行查询与转换,进而执行原来的完整命令。 熟练使用alias命令可以使我们将一长串命令或者一些…...
WebSocketServer+redis实时更新页面数据
redis 实现发布订阅功能具体实现_redis convertandsend-CSDN博客 主要看上面这个 使用redis做websocket分布式消息推送服务_websocket redis-CSDN博客 ClassCastException: java.lang.String cannot be cast to com.alibaba.fastjson.JSONObject 的解决办法_java.lang.class…...
快速掌握Vue.js框架:从入门到实战
一、引言 Vue.js,作为一款广受欢迎的渐进式JavaScript框架,以其轻量级、易用性和高效性在前端开发领域占据了一席之地。Vue.js遵循MVVM(Model-View-ViewModel)设计模式,它通过双向数据绑定机制简化了开发者对用户界面与底层数据模型之间关系的处理,使得构建现代Web应用变…...

###C语言程序设计-----C语言学习(11)#数据的存储和基本数据类型
前言:感谢您的关注哦,我会持续更新编程相关知识,愿您在这里有所收获。如果有任何问题,欢迎沟通交流!期待与您在学习编程的道路上共同进步。 一. 数据的存储 1.整型数据的存储 计算机处理的所有信息都以二进制形式表示…...
机器学习案例1:利用 Python 将语音转换为文本
目录 内容简介 基本环境配置 Python库安装 麦克风语音识别 音频文件的语音识别 长音频源语音识别 内容简介 语音识别是机器或程序识别口语中的单词和短语并将其转换为文本信息的能力。 大多数对于语音识别技术的应用场景就是Siri、Cortana和Google Assistant等个人助理,…...

杨辉三角的变形(数学)
题目 import java.util.Scanner;public class Main {public static void main(String[] args) { // 1 // 1 1 1 // 1 2 3 2 1 // 1 3 6 7 6 3 1 // 1 4 10 16 19 16 10 4 1Scanner sc new Scanner(System.in);int n sc.nextInt();int[][] res new int[n1][2*n];for(i…...
YOLOv5改进 | 融合改进篇 | 华为VanillaNet + BiFPN突破涨点极限
一、本文介绍 本文给大家带来的改进机制是华为VanillaNet主干配合BiFPN实现融合涨点,这个主干是一种注重极简主义和效率的神经网络我也将其进行了实验, 其中的BiFPN不用介绍了从其发布到现在一直是比较热门的改进机制,其主要思想是通过多层级的特征金字塔和双向信息传递来提…...

C++初阶篇----新手进村
目录 一、什么是C二、C关键字三、命名空间3.1命名空间的定义3.2命名空间的使用 四、C输入和输出五、缺省参数5.1缺省参数的概念5.2缺省参数的分类 六、函数重载6.1函数重载的概念6.2函数重载的原理----名字修饰 七、引用7.1引用概念7.2引用特性7.3常引用7.4引用的使用7.5传值、…...

假期刷题打卡--Day26
1、MT1212乘法表 请编写一个简单程序,输出九九乘法表。输入n,就输出乘法表到n的地方。 格式 输入格式: 输入整型 输出格式: 输出整型。形式如:1*11 样例 1 输入: 5输出: 1*11 2*12 …...

SpringBoot-17-MyBatis动态SQL标签之常用标签
文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...

铭豹扩展坞 USB转网口 突然无法识别解决方法
当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...

Chapter03-Authentication vulnerabilities
文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...

从WWDC看苹果产品发展的规律
WWDC 是苹果公司一年一度面向全球开发者的盛会,其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具,对过去十年 WWDC 主题演讲内容进行了系统化分析,形成了这份…...

关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案
问题描述:iview使用table 中type: "index",分页之后 ,索引还是从1开始,试过绑定后台返回数据的id, 这种方法可行,就是后台返回数据的每个页面id都不完全是按照从1开始的升序,因此百度了下,找到了…...

HTML 列表、表格、表单
1 列表标签 作用:布局内容排列整齐的区域 列表分类:无序列表、有序列表、定义列表。 例如: 1.1 无序列表 标签:ul 嵌套 li,ul是无序列表,li是列表条目。 注意事项: ul 标签里面只能包裹 li…...
质量体系的重要
质量体系是为确保产品、服务或过程质量满足规定要求,由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面: 🏛️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限,形成层级清晰的管理网络…...
生成 Git SSH 证书
🔑 1. 生成 SSH 密钥对 在终端(Windows 使用 Git Bash,Mac/Linux 使用 Terminal)执行命令: ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" 参数说明: -t rsa&#x…...
相机Camera日志分析之三十一:高通Camx HAL十种流程基础分析关键字汇总(后续持续更新中)
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:有对最普通的场景进行各个日志注释讲解,但相机场景太多,日志差异也巨大。后面将展示各种场景下的日志。 通过notepad++打开场景下的日志,通过下列分类关键字搜索,即可清晰的分析不同场景的相机运行流程差异…...

什么是Ansible Jinja2
理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具,可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板,允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板,并通…...