Mina、Netty、Twisted一起学(七):发布/订阅(Publish/Subscribe)

论文阅读笔记(一)细粒度图像检索 0、参考文献 [1]见微知著 http://geek.youkuaiyun.com/news/detail/191718 [2]Xiu-Shen Wei 《Selective Convolutional Descriptor Aggregation for Fine-Grained Image Retrieval》 [3]Lingxi Xie 《Fine-Grained Image Search》 1... 阅读详情
消息传递有很多种方式,请求/响应(Request/Reply)是最常用的。在前面的博文的例子中,很多都是采用请求/响应的方式,当服务器接收到消息后,会立即write回写一条消息到客户端。HTTP协议也是基于请求/响应的方式。 但是请求/响应并不能满足所有的消息传递的需求,有些需求可能需要服务端主动推送消息到客户端,而不是被动的等待请求后再给出响应。 发布/订阅(Publish/Subscribe)是一种服务器主动发送消息到客户端的消息传递方式。订阅者Subscriber连接到服务器客户端后,相当于开始订阅发布者Publisher发布的消息,当发布者发布了一条消息后,所有订阅者都会接收到这条消息。 网络聊天室一般就是基于发布/订阅模式来实现。例如加入一个QQ群,就相当于订阅了这个群的所有消息,当有新的消息,服务器会主动将消息发送给所有的客户端。只不过聊天室里的所有人既是发布者又是订阅者。 下面分别用MINA、Netty、Twisted分别实现简单的发布/订阅模式的服务器程序,连接到服务器的所有客户端都是订阅者,当发布者发布一条消息后,服务器会将消息转发给所有客户端。 MINA: 在MINA中,通过IoService的getManagedSessions()方法可以获取这个IoService当前管理的所有IoSession,即所有连接到服务器的客户端集合。当服务器接收到发布者发布的消息后,可以通过IoService的getManagedSessions()方法获取到所有客户端对应的IoSession并将消息发送到这些客户端。 复制代码 public class TcpServer { public static void main(String[] args) throws IOException { IoAcceptor acceptor = new NioSocketAcceptor(); acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8"), "\r\n", "\r\n"))); acceptor.setHandler(new TcpServerHandle()); acceptor.bind(new InetSocketAddress(8080)); } } class TcpServerHandle extends IoHandlerAdapter { @Override public void exceptionCaught(IoSession session, Throwable cause) throws Exception { cause.printStackTrace(); } @Override public void messageReceived(IoSession session, Object message) throws Exception { // 获取所有正在连接的IoSession Collection sessions = session.getService().getManagedSessions().values(); // 将消息写到所有IoSession IoUtil.broadcast(message, sessions); } } 复制代码 Netty: Netty提供了ChannelGroup来用于保存Channel组,ChannelGroup是一个线程安全的Channel集合,它提供了一些列Channel批量操作。当一个TCP连接关闭后,对应的Channel会自动从ChannelGroup移除,所以不用手动去移除关闭的Channel。 Netty文档关于ChannelGroup的解释: A thread-safe Set that contains open Channels and provides various bulk operations on them. Using ChannelGroup, you can categorize Channels into a meaningful group (e.g. on a per-service or per-state basis.) A closed Channel is automatically removed from the collection, so that you don't need to worry about the life cycle of the added Channel. A Channel can belong to more than one ChannelGroup. 当有新的客户端连接到服务器,将对应的Channel加入到一个ChannelGroup中,当发布者发布消息时,服务器可以将消息通过ChannelGroup写入到所有客户端。 复制代码 public class TcpServer { public static void main(String[] args) throws InterruptedException { EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .childHandler(new ChannelInitializer() { @Override public void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast(new LineBasedFrameDecoder(80)); pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8)); pipeline.addLast(new StringEncoder(CharsetUtil.UTF_8)); pipeline.addLast(new TcpServerHandler()); } }); ChannelFuture f = b.bind(8080).sync(); f.channel().closeFuture().sync(); } finally { workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } } } class TcpServerHandler extends ChannelInboundHandlerAdapter { // ChannelGroup用于保存所有连接的客户端,注意要用static来保证只有一个ChannelGroup实例,否则每new一个TcpServerHandler都会创建一个ChannelGroup private static ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); @Override public void channelActive(ChannelHandlerContext ctx) { channels.add(ctx.channel()); // 将新的连接加入到ChannelGroup,当连接断开ChannelGroup会自动移除对应的Channel } @Override public void channelRead(ChannelHandlerContext ctx, Object msg) { channels.writeAndFlush(msg + "\r\n"); // 接收到消息后,将消息发送到ChannelGroup中的所有客户端 } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { // cause.printStackTrace(); 暂时把异常打印注释掉,因为PublishClient发布一条消息后会立即断开连接,而服务器也会向PublishClient发送消息,所以会抛出异常 ctx.close(); } } 复制代码 Twisted: 在Twisted中,全局的数据一般会放在Factory,而每个连接相关的数据会放在Protocol中。所以这里可以在Factory中加入一个属性,来存放Protocol集合,表示所有连接服务器的客户端。当有新的客户端连接到服务器时,将对应的Protocol实例放入集合,当连接断开,将对应的Protocol从集合中移除。当服务器接收到发布者发布的消息后,遍历所有客户端并发送消息。 复制代码 # -*- coding:utf-8 –*- from twisted.protocols.basic import LineOnlyReceiver from twisted.internet.protocol import Factory from twisted.internet import reactor class TcpServerHandle(LineOnlyReceiver): def __init__(self, factory): self.factory = factory def connectionMade(self): self.factory.clients.add(self) # 新连接添加连接对应的Protocol实例到clients def connectionLost(self, reason): self.factory.clients.remove(self) # 连接断开移除连接对应的Protocol实例 def lineReceived(self, line): # 遍历所有的连接,发送数据 for c in self.factory.clients: c.sendLine(line) class TcpServerFactory(Factory): def __init__(self): self.clients = set() # set集合用于保存所有连接到服务器的客户端 def buildProtocol(self, addr): return TcpServerHandle(self) reactor.listenTCP(8080, TcpServerFactory()) reactor.run() 复制代码下面分别是两个客户端程序,一个是用于发布消息的客户端,一个是订阅消息的客户端。 发布消息的客户端很简单,就是向服务器write一条消息即可: 复制代码 public class PublishClient { public static void main(String[] args) throws IOException { Socket socket = null; OutputStream out = null; try { socket = new Socket("localhost", 8080); out = socket.getOutputStream(); out.write("Hello\r\n".getBytes()); // 发布信息到服务器 out.flush(); } finally { // 关闭连接 out.close(); socket.close(); } } } 复制代码订阅消息的客户端连接到服务器后,会阻塞等待接收服务器发送的发布消息: 复制代码 public class SubscribeClient { public static void main(String[] args) throws IOException { Socket socket = null; BufferedReader in = null; try { socket = new Socket("localhost", 8080); in = new BufferedReader(new InputStreamReader(socket.getInputStream())); while (true) { String line = in.readLine(); // 阻塞等待服务器发布的消息 System.out.println(line); } } finally { // 关闭连接 in.close(); socket.close(); } } } 复制代码分别针对MINA、Netty、Twisted服务器进行测试: 1、测试时首先开启服务器; 2、然后再运行订阅消息的客户端SubscribeClient,SubscribeClient可以开启多个; 3、最后运行发布消息的客户端PublishClient,可以多次运行查看所有SubscribeClient的输出结果。 运行结果可以发现,当运行发布消息的客户端PublishClient发布一条消息到服务器时,服务器会主动将这条消息转发给所有的TCP连接,所有的订阅消息的客户端SubscribeClient都会接收到这条消息并打印出来。
覆冰监测系统服务器,基于分布式光纤振动传感的电缆覆冰舞动监测系统 监测意义我国高压输电网络已经形成了全国联网的格局,总规模世界第一。2018年底,全国发电装机容量已达19.0亿千瓦,全国 220kV及以上输电线路回路长度超过71万公里。我国电力能源集中在西北,而用户则集中在华东华南,所以高压输电网络的特点是长距离,大跨度,途径的自然环境多种多样。在高湿高寒的恶劣环境中,输电线非常容易发生覆冰舞动事故,由于覆冰形成的规则的非圆断面的缆线在风的激励下形成谐振,造成低... 阅读详情

相关推荐

解锁笔记智能对话:手把手配置 Obsidian Copilot 插件与硅基流动模型

本文详细介绍了如何为Obsidian笔记软件配置Copilot插件,并接入硅基流动AI模型,从而为个人知识库添加智能对话能力。通过手把手教程,指导用户完成插件安装、API Key获取、模型配置及索引构建,最终实现基于个人笔记内容的深度语义问答,提升知识管理效率。

corn8的博客 616

发布Twist消息类型的话题订阅异常报错

报错类型 用python写的一个键盘检测程序: #!/usr/bin/env python #coding=utf-8 import rospy from geometry_msgs.msg import Twist import sys, select, termios, tty msg = “”" Control The Robot! Moving around: u i o j k l m , . q/z : increase/decrease max speeds

blue_skyLZW的博客 1013

技能伤害继承英雄属性【War3地图编辑器】

风暴之锤跟随山丘之王的力量增长

ArYe 2313

mina框架详解(一)

mina框架详解 ​ Apache Mina Server 是一个网络通信应用框架,也就是说,它主要是对基于TCP/IP、UDP/IP协议栈的通信框架(当然,也可以提供JAVA 对象的序列化服务、虚拟机管道通信服务等),Mina 可以帮助我们快速开发高性能、高扩展性的网络通信应用,Mina 提供了事件驱动、异步(Mina 的异步IO 默认使用的是JAVA NIO 作为底层支持)操作的编程模型。M...

Jasonzhou 2450

Windows安装Pytorch3d

pytorch和pytorch3d版本对应关系如下:https://github.com/facebookresearch/pytorch3d/releasescuda和NVIDIA CUB版本对应关系如下:https://github.com/NVIDIA/cub/releases?page=1本人配置如下:GPU:1050TiCUDA:11.1python:3.8。

Snakewood的博客 4287

C#开发者必备:VSPD虚拟串口快速配置指南(附汉化教程)

本文为C#开发者提供了VSPD虚拟串口的快速配置与汉化教程。详细介绍了如何安装、汉化VSPD,并创建稳定的虚拟串口对,重点讲解了如何将其集成到C#开发工作流中,使用SerialPort类进行数据通信测试、协议模拟及故障排查,有效提升硬件通信开发的效率。

weixin_29224529的博客 258

Mina如何保持一个客户对应一个session

对于客户端通讯来说,断线重连是非常有必要的。但是如何做到,重连之时断开同用户前面还链接的session呢,也就是说做到一个客户始终只有一个session与之对应呢。 //获取当前session的token String token = request.getToken(); //获取所有的session Map<Long,IoSession> sess

zhuwei_clark的博客 4743

【SpringBoot】1、创建第一个SpringBoot项目

创建SpringBoot项目可以通过两种方式,1、通过访问:https://start.spring.io/,SpringBoot的官方网站进行创建SpringBoot项目;2、通过工具(例如:Idea)创建SpringBoot项目。本次使用开发工具:Idea创建我的第一个SpringBoot项目。 首先,打开我们的Idea开发工具 选择Create New Poject(创建一个新的项目) ...

JACKAL 21万+

《Apache MINA 2.0 用户指南》第三章:IO 服务

本章对 IoService 进行了深入讨论,分别从服务器端和客户端的实现进行了详细分析,并有示例说明。

Defonds 的专栏 7921

嵌入式工程师必学(52):储能系统ESS

能量存储系统(ESS,Energystoragesystems)存在于各种各样的尺寸、形状和技术中。储能系统的技术,即基本的储能机制,自然会影响其重要特性,包括成本、安全性、性能、可靠性和寿命。然而,尽管基础技术很重要,但一个成功的储能项目依赖于对该技术的彻底和深思熟虑的实施,以实现项目的目标。成功的实施取决于储能系统的架构和组装情况。系统的体系结构可以决定其性能和可靠性,与它所使用的技术一致,甚至与之无关。

码农17年的博客 1444

第95章 安全工程师:Shell 脚本实现安全扫描、漏洞检测、日志审计

随着网络安全威胁日益复杂,传统的手动安全管理已无法满足现代企业的安全需求。Shell 脚本为安全工程师提供了强大的自动化能力,能够实现 7×24 小时的安全监控、快速漏洞扫描、智能日志分析和实时威胁响应。本章将系统介绍如何使用 Shell 脚本构建完整的安全防护体系,从基线检查到实时监控,帮助你打造自动化的安全运维能力。

猪猪侠 91

MINA、Netty、Twisted一起学(七):发布/订阅(Publish/Subscribe)

消息传递有很多种方式,请求/响应(Request/Reply)是最常用的。在前面的博文的例子中,很多都是采用请求/响应的方式,当服务器接收到消息后,会立即write回写一条消息到客户端。HTTP协议也是基于请求/响应的方式。 但是请求/响应并不能满足所有的消息传递的需求,有些需求可能需要服务端主动推送消息到客户端,而不是被动的等待请求后再给出响应。 发布/订阅(Publish/Subscrib...

KHOST的博客 258

修改 Alist 密码时报错?看看这个坑怎么解决!

启动服务后,再修改密码”。以后再遇到类似问题,先检查服务是否正常运行,说不定就能少踩不少坑。如果还有其他 Alist 的问题,欢迎在评论区留言交流~

代码简单说 Vue、JAVA、PHP、Node.js 熟练运用,接口、架构、性能全搞定。 1155

Mina、Netty、Twisted一起学(七):公布/订阅(Publish/Subscribe)

消息传递有非常多种方式。请求/响应(Request/Reply)是最经常使用的。在前面的博文的样例中。非常多都是採用请求/响应的方式。当server接收到消息后,会马上write回写一条消息到client。HTTP协议也是基于请求/响应的方式。可是请求/响应并不能满足全部的消息传递的需求,有些需求可能须要服务端主动推送消息到client,而不是被动的等待请求后再给出响应。公布/订阅(...

diandingyin9417的博客 186

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

ROS中用Twist消息控制机器人

ROS中用Twist消息控制机器人INSTALLING THE ROS-BY-EXAMPLE CODE是书中第五章的内容,如果我们按照上一篇教程执行过了,就可以直接进入第五章,安装一个叫rbx1的包。这个包里面包括了本书中用到的所有例子的源码,包括路径规划,视觉,语音识别等功能。这本书基本就围绕这个包来学习ROS的使用方法。 基本包的功能介绍 从终端发布Twist消息控制机器人 从节点发布Twist

lizilpl的专栏 4万+

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

有关mina的session管理及客户端断线重连的问题

http://chwshuang.iteye.com/blog/2028951

jhope的专栏 5791

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

上一篇: CSRF攻击与防御
下一篇: QRadioButton分组且无边框的简单实现
lin91o7c
博客等级 码龄12年 1粉丝 26原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值