本文主要是介绍【网络编程】ZeroMQ的网络通信,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
文章目录
- 1、概述
- 2、通信效果
- 2.1、Request-Reply(请求-响应模式)
- 2.2、Publish-Subscribe(订阅-发布模式)
- 3、方式选择
- 3.1、准备用 Visual Studio-C++ 方式
- 3.1.1、找到 Builds 文件夹
- 3.1.2、查看 deprecated-msvc 下的 libzmq.sln 文件
- 3.1.3、使用 Visual Studio 打开 libzmq.sln 解决方案
- 3.1.4、修改 libzmq.import.props 文件
- 3.1.5、编译生成
- 3.2、准备用 PyCharm-Python 方式
- 3.2.1、安装
- 3.2.1.1、命令安装
- 3.2.1.2、IDE安装
- 3.2.2、查看是否安装成功
- 4、Request-Reply(请求响应模式)
- 4.1、Request-Reply模式概述
- 4.2、Client 源代码
- 4.3、Server 源代码
- 5、Publish/Subscribe(订阅-发布模式)
- 5.1、Pub-Subs模式概述
- 5.2、发布者 源代码
- 5.3、订阅者 源代码
1、概述
在前一篇文章中提到了 ØMQ (ZeroMQ) ,是一个基于消息队列的多线程网络库,它封装了网络通信、消息队列、线程调度等功能,向上层提供简洁的API,应用程序通过加载库文件,调用API函数来实现高性能网络通信。
本篇文章重点讲述下,在客户端上如何使用 ZeroMQ 与 服务端的 ZeroMQ 进行通信,主要讲述两种常用模式:
1.Request-Reply(请求响应模式)
2.Publish-Subscribe(订阅-发布模式)
相关文章:
- 【Qt 学习之路】在 Qt 使用 ZeroMQ:https://shazhenyu.blog.csdn.net/article/details/136051050?spm=1001.2014.3001.5502
2、通信效果
2.1、Request-Reply(请求-响应模式)
Client:
Server:
2.2、Publish-Subscribe(订阅-发布模式)
发布者:
订阅者:
3、方式选择
3.1、准备用 Visual Studio-C++ 方式
3.1.1、找到 Builds 文件夹
在 ZeroMQ 的 builds 文件夹下,有很多种编译方法,为了方便演示,本文选择msvc进行演示。
3.1.2、查看 deprecated-msvc 下的 libzmq.sln 文件
3.1.3、使用 Visual Studio 打开 libzmq.sln 解决方案
3.1.4、修改 libzmq.import.props 文件
用 Notepad++ 打开 libzmq.import.props 文件,修改 5处 路径,全部改成…\bin【注意:去掉“…\libzmq\”】
- 原:
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"><PropertyGroup Label="Globals"><_PropertySheetDisplayName>ZMQ Import Settings</_PropertySheetDisplayName></PropertyGroup><!-- User Interface --><ItemGroup Label="BuildOptionsExtension"><PropertyPageSchema Include="$(MSBuildThisFileDirectory)libzmq.import.xml" /></ItemGroup><!-- Configuration --><ItemDefinitionGroup><ClCompile><PreprocessorDefinitions Condition="'$(Option-sodium)' == 'true'">ZMQ_USE_LIBSODIUM;%(PreprocessorDefinitions)</PreprocessorDefinitions><PreprocessorDefinitions Condition="'$(Option-openpgm)' == 'true'">ZMQ_HAVE_OPENPGM;%(PreprocessorDefinitions)</PreprocessorDefinitions><PreprocessorDefinitions Condition="'$(Option-gssapi)' == 'true'">HAVE_LIBGSSAPI_KRB5;%(PreprocessorDefinitions)</PreprocessorDefinitions><PreprocessorDefinitions Condition="'$(Option-draftapi)' == 'true'">ZMQ_BUILD_DRAFT_API;%(PreprocessorDefinitions)</PreprocessorDefinitions></ClCompile></ItemDefinitionGroup><!-- Linkage --><ItemDefinitionGroup><ClCompile><AdditionalIncludeDirectories>$(ProjectDir)..\..\..\..\..\libzmq\include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories><PreprocessorDefinitions Condition="'$(Linkage-libzmq)' == 'static' Or '$(Linkage-libzmq)' == 'ltcg'">ZMQ_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions></ClCompile><Link><AdditionalDependencies Condition="'$(Linkage-libzmq)' != ''">libzmq.lib;%(AdditionalDependencies)</AdditionalDependencies><AdditionalLibraryDirectories Condition="$(Configuration.IndexOf('Debug')) != -1">$(ProjectDir)..\..\..\..\..\libzmq\bin\$(PlatformName)\Debug\$(PlatformToolset)\$(Linkage-libzmq)\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories><AdditionalLibraryDirectories Condition="$(Configuration.IndexOf('Release')) != -1">$(ProjectDir)..\..\..\..\..\libzmq\bin\$(PlatformName)\Release\$(PlatformToolset)\$(Linkage-libzmq)\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories></Link></ItemDefinitionGroup><!-- Copy --><Target Name="Linkage-libzmq-dynamic" AfterTargets="AfterBuild" Condition="'$(Linkage-libzmq)' == 'dynamic'"><Copy Condition="$(Configuration.IndexOf('Debug')) != -1"SourceFiles="$(ProjectDir)..\..\..\..\..\libzmq\bin\$(PlatformName)\Debug\$(PlatformToolset)\dynamic\libzmq.dll"DestinationFiles="$(TargetDir)libzmq.dll"SkipUnchangedFiles="true" /><Copy Condition="$(Configuration.IndexOf('Debug')) != -1"SourceFiles="$(ProjectDir)..\..\..\..\..\libzmq\bin\$(PlatformName)\Debug\$(PlatformToolset)\dynamic\libzmq.pdb"DestinationFiles="$(TargetDir)libzmq.pdb"SkipUnchangedFiles="true" /><Copy Condition="$(Configuration.IndexOf('Release')) != -1"SourceFiles="$(ProjectDir)..\..\..\..\..\libzmq\bin\$(PlatformName)\Release\$(PlatformToolset)\dynamic\libzmq.dll"DestinationFiles="$(TargetDir)libzmq.dll"SkipUnchangedFiles="true" /></Target><!-- Messages --><Target Name="libzmq-info" BeforeTargets="AfterBuild" Condition="'$(Linkage-libzmq)' == 'dynamic'"><Message Text="Copying libzmq.dll -> $(TargetDir)libzmq.dll" Importance="high"/><Message Text="Copying libzmq.pdb -> $(TargetDir)libzmq.pdb" Importance="high" Condition="$(Configuration.IndexOf('Debug')) != -1" /></Target></Project>
- 改:
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"><PropertyGroup Label="Globals"><_PropertySheetDisplayName>ZMQ Import Settings</_PropertySheetDisplayName></PropertyGroup><!-- User Interface --><ItemGroup Label="BuildOptionsExtension"><PropertyPageSchema Include="$(MSBuildThisFileDirectory)libzmq.import.xml" /></ItemGroup><!-- Configuration --><ItemDefinitionGroup><ClCompile><PreprocessorDefinitions Condition="'$(Option-sodium)' == 'true'">ZMQ_USE_LIBSODIUM;%(PreprocessorDefinitions)</PreprocessorDefinitions><PreprocessorDefinitions Condition="'$(Option-openpgm)' == 'true'">ZMQ_HAVE_OPENPGM;%(PreprocessorDefinitions)</PreprocessorDefinitions><PreprocessorDefinitions Condition="'$(Option-gssapi)' == 'true'">HAVE_LIBGSSAPI_KRB5;%(PreprocessorDefinitions)</PreprocessorDefinitions><PreprocessorDefinitions Condition="'$(Option-draftapi)' == 'true'">ZMQ_BUILD_DRAFT_API;%(PreprocessorDefinitions)</PreprocessorDefinitions></ClCompile></ItemDefinitionGroup><!-- Linkage --><ItemDefinitionGroup><ClCompile><AdditionalIncludeDirectories>$(ProjectDir)..\..\..\..\..\libzmq\include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories><PreprocessorDefinitions Condition="'$(Linkage-libzmq)' == 'static' Or '$(Linkage-libzmq)' == 'ltcg'">ZMQ_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions></ClCompile><Link><AdditionalDependencies Condition="'$(Linkage-libzmq)' != ''">libzmq.lib;%(AdditionalDependencies)</AdditionalDependencies><AdditionalLibraryDirectories Condition="$(Configuration.IndexOf('Debug')) != -1">$(ProjectDir)..\..\..\..\bin\$(PlatformName)\Debug\$(PlatformToolset)\$(Linkage-libzmq)\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories><AdditionalLibraryDirectories Condition="$(Configuration.IndexOf('Release')) != -1">$(ProjectDir)..\..\..\..\bin\$(PlatformName)\Release\$(PlatformToolset)\$(Linkage-libzmq)\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories></Link></ItemDefinitionGroup><!-- Copy --><Target Name="Linkage-libzmq-dynamic" AfterTargets="AfterBuild" Condition="'$(Linkage-libzmq)' == 'dynamic'"><Copy Condition="$(Configuration.IndexOf('Debug')) != -1"SourceFiles="$(ProjectDir)..\..\..\..\bin\$(PlatformName)\Debug\$(PlatformToolset)\dynamic\libzmq.dll"DestinationFiles="$(TargetDir)libzmq.dll"SkipUnchangedFiles="true" /><Copy Condition="$(Configuration.IndexOf('Debug')) != -1"SourceFiles="$(ProjectDir)..\..\..\..\bin\$(PlatformName)\Debug\$(PlatformToolset)\dynamic\libzmq.pdb"DestinationFiles="$(TargetDir)libzmq.pdb"SkipUnchangedFiles="true" /><Copy Condition="$(Configuration.IndexOf('Release')) != -1"SourceFiles="$(ProjectDir)..\..\..\..\bin\$(PlatformName)\Release\$(PlatformToolset)\dynamic\libzmq.dll"DestinationFiles="$(TargetDir)libzmq.dll"SkipUnchangedFiles="true" /></Target><!-- Messages --><Target Name="libzmq-info" BeforeTargets="AfterBuild" Condition="'$(Linkage-libzmq)' == 'dynamic'"><Message Text="Copying libzmq.dll -> $(TargetDir)libzmq.dll" Importance="high"/><Message Text="Copying libzmq.pdb -> $(TargetDir)libzmq.pdb" Importance="high" Condition="$(Configuration.IndexOf('Debug')) != -1" /></Target></Project>
3.1.5、编译生成
按照官网的方式,这一步应该是成功了,但是目前是失败,还少文件,可能是包有问题
3.2、准备用 PyCharm-Python 方式
3.2.1、安装
3.2.1.1、命令安装
pip install pyzmq
3.2.1.2、IDE安装
安装图种方法安装 pyzmq25.1.2 版本
3.2.2、查看是否安装成功
直接打印 zmq 版本号 试试
import zmq
print(zmq.__version__)
由于 Python 相对快捷,本文后续以 Python 进行讲述
4、Request-Reply(请求响应模式)
4.1、Request-Reply模式概述
消息双向的,有来有往。
Client请求的消息,Server必须答复给Client。
Client在请求后,Server必须回响应,注意:Server不返回响应会报错。
Server和Client都可以是1:N的模型。通常把1认为是Server,N认为是Client。
更底层的端点地址是对上层隐藏的,每个请求都隐含回应地址,而应用则不关心它。
ZMQ 可以很好的支持路由功能(实现路由功能的组件叫做 Device),把 1:N 扩展为 N:M(只需要加入若干路由节点)。
4.2、Client 源代码
# client.pyimport zmqcontext = zmq.Context()# Socket to talk to server
print("Connecting to 5555 server…")
socket = context.socket(zmq.REQ)
socket.connect("tcp://localhost:5555")
socket.send(b"Hello, I'm Mr.Sha Client.")
# Get the reply.
message = socket.recv()
print(f"Received reply [ {message} ]")
4.3、Server 源代码
# server.py
import time
import zmqcontext = zmq.Context()
socket = context.socket(zmq.REP)
socket.bind("tcp://*:5555")while True:# Wait for next request from clientmessage = socket.recv()print("Received request: %s" % message)# Do some 'work'time.sleep(1)# Send reply back to clientsocket.send(b"Hello, I'm server.")
5、Publish/Subscribe(订阅-发布模式)
5.1、Pub-Subs模式概述
消息单向,有去无回
一个发布端,多个订阅端;发布端只管产生数据,发布端发布一条消息,可被多个订阅端同时收到。
发布者不必关心订阅者的加入和离开,消息会以 1:N 的方式扩散到每个订阅者。
广播所有client,没有队列缓存,断开连接数据将永远丢失。
如果Publish端开始发布信息时,Subscribe端尚未连接进来,则这些信息会被直接丢弃。
PUB和SUB谁bind谁connect并无严格要求(虽本质并无区别),但仍建议PUB使用bind,SUB使用connect
使用SUB设置一个订阅时,必须使用zmq_setsockopt()对消息进行过滤
这里直接引用官方文档的例子,订阅者再稍作改装!
5.2、发布者 源代码
类似于一个天气更新服务器,向订阅者发送天气更新,内容包括邮政编码、温度、湿度等信息
# Publisher.py
import zmq
from random import randrangecontext = zmq.Context()
socket = context.socket(zmq.PUB)
socket.bind("tcp://*:5556")while True:zipcode = randrange(1, 100000)temperature = randrange(-80, 135)relhumidity = randrange(10, 60)socket.send_string("%i %i %i" % (zipcode, temperature, relhumidity))
5.3、订阅者 源代码
它监听发布者更新的数据流,过滤只接收与特定邮政编码相关的天气信息,默认接收接收10条数据
# Subscribe.py
import sys
import zmq# Socket to talk to server
context = zmq.Context()
socket = context.socket(zmq.SUB)print("Collecting updates from weather server...")
socket.connect("tcp://localhost:5556")# Subscribe to zipcode, default is NYC, 10001
zip_filter = sys.argv[1] if len(sys.argv) > 1 else "10001"# Python 2 - ascii bytes to unicode str
if isinstance(zip_filter, bytes):zip_filter = zip_filter.decode('ascii')
socket.setsockopt_string(zmq.SUBSCRIBE, zip_filter)# Process 5 updates
total_temp = 0
for update_nbr in range(5):string = socket.recv_string()zipcode, temperature, relhumidity = string.split()total_temp += int(temperature)print("zipcode, temperature, relhumidity:" + string)print("Average temperature for zipcode '%s' was %dF"% (zip_filter, total_temp / (update_nbr + 1))
)
这篇关于【网络编程】ZeroMQ的网络通信的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!