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 …...
【Oracle APEX开发小技巧12】
有如下需求: 有一个问题反馈页面,要实现在apex页面展示能直观看到反馈时间超过7天未处理的数据,方便管理员及时处理反馈。 我的方法:直接将逻辑写在SQL中,这样可以直接在页面展示 完整代码: SELECTSF.FE…...
《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》
引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...
前端倒计时误差!
提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...
遍历 Map 类型集合的方法汇总
1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...
深入浅出:JavaScript 中的 `window.crypto.getRandomValues()` 方法
深入浅出:JavaScript 中的 window.crypto.getRandomValues() 方法 在现代 Web 开发中,随机数的生成看似简单,却隐藏着许多玄机。无论是生成密码、加密密钥,还是创建安全令牌,随机数的质量直接关系到系统的安全性。Jav…...
Java面试专项一-准备篇
一、企业简历筛选规则 一般企业的简历筛选流程:首先由HR先筛选一部分简历后,在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如:Boss直聘(招聘方平台) 直接按照条件进行筛选 例如:…...
什么是Ansible Jinja2
理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具,可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板,允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板,并通…...
智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制
在数字化浪潮席卷全球的今天,数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具,在大规模数据获取中发挥着关键作用。然而,传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时,常出现数据质…...
从面试角度回答Android中ContentProvider启动原理
Android中ContentProvider原理的面试角度解析,分为已启动和未启动两种场景: 一、ContentProvider已启动的情况 1. 核心流程 触发条件:当其他组件(如Activity、Service)通过ContentR…...
uniapp 集成腾讯云 IM 富媒体消息(地理位置/文件)
UniApp 集成腾讯云 IM 富媒体消息全攻略(地理位置/文件) 一、功能实现原理 腾讯云 IM 通过 消息扩展机制 支持富媒体类型,核心实现方式: 标准消息类型:直接使用 SDK 内置类型(文件、图片等)自…...
