社区
Java SE
帖子详情
netty服务端如何向客户端发送消息
qq_36865470
2018-09-06 08:32:39
问题描述:
希望通过管理后台控制客户端的行为,比如:升级、断电等。通讯框架采用Netty,现在遇见的问题是 服务器端(即管理后台)怎么向客户端发送消息(网上大部分说缓存客户端的Channel),但是项目的后台、前台、以及Netty Server都是分离的。 这个时候该怎么做呢?请大家给点意见!
...全文
2247
2
打赏
收藏
netty服务端如何向客户端发送消息
问题描述: 希望通过管理后台控制客户端的行为,比如:升级、断电等。通讯框架采用Netty,现在遇见的问题是 服务器端(即管理后台)怎么向客户端发送消息(网上大部分说缓存客户端的Channel),但是项目的后台、前台、以及Netty Server都是分离的。 这个时候该怎么做呢?请大家给点意见!
复制链接
扫一扫
分享
转发到动态
举报
写回复
配置赞助广告
用AI写文章
2 条
回复
切换为时间正序
请发表友善的回复…
发表回复
打赏红包
爱码叔
2018-09-24
打赏
举报
回复
netty server肯定持有和前台(客户端)连接的所有channel。所以你的后台要不搭在netty server上,要不然也作为一个特殊的客户端链接到netty server,netty server接到此客户端的消息后,转发(广播)给所有的客户端。
qq_35358818
2018-09-14
打赏
举报
回复
1.普通字符串消息传递
服务器端:
public void startServer(int port) throws InterruptedException{
EventLoopGroup work=new NioEventLoopGroup();
EventLoopGroup boss=new NioEventLoopGroup();
ServerBootstrap bootStrap=new ServerBootstrap();
bootStrap.group(boss, work);
bootStrap.channel(NioServerSocketChannel.class);
bootStrap.option(ChannelOption.SO_BACKLOG,1024);
bootStrap.childHandler(new ChannelInitializer<SocketChannel>(){
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline=ch.pipeline();
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
pipeline.addLast(new ServerHandler());
}
});
//绑定端口,同步等待成功.
ChannelFuture future=bootStrap.bind(port).sync();
//等待服务端监听端口关闭
future.channel().closeFuture().sync();
boss.shutdownGracefully();
work.shutdownGracefully();
}
public class ServerHandler extends ChannelHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg)
throws Exception {
System.out.println("msg:"+msg);
/*ByteBuf buf=(ByteBuf)msg;
byte[] req=new byte[buf.readableBytes()];
buf.readBytes(req);
String body=new String(req,"UTF-8");
System.out.println("body:"+body);
ctx.pipeline().writeAndFlush(buf);*///手动解析收到的数据
ctx.pipeline().writeAndFlush("hi......");
}
}
客户端:
public void startClient(String host,int port) throws InterruptedException{
EventLoopGroup group=new NioEventLoopGroup();
Bootstrap bootStrap=new Bootstrap();
bootStrap.group(group);
bootStrap.channel(NioSocketChannel.class);
bootStrap.option(ChannelOption.SO_KEEPALIVE,true);
bootStrap.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel sc) throws Exception {
ChannelPipeline pipeline=sc.pipeline();
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
pipeline.addLast(new ClientHandler());
}
});
//绑定端口,同步等待成功.
ChannelFuture future=bootStrap.connect(host,port).sync();
future.channel().writeAndFlush("hello");
//等待服务端监听端口关闭
future.channel().closeFuture().sync();
group.shutdownGracefully();
}
public class ClientHandler extends ChannelHandlerAdapter{
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg)
throws Exception {
System.out.println("msg:"+msg);
}
}
2.对象类型消息传递(传递对象直接实现Serializable)
服务器端(与普通字符串不同的部分标红):
public void startServer(int port) throws InterruptedException{
EventLoopGroup work=new NioEventLoopGroup();
EventLoopGroup boss=new NioEventLoopGroup();
ServerBootstrap bootStrap=new ServerBootstrap();
bootStrap.group(boss, work);
bootStrap.channel(NioServerSocketChannel.class);
bootStrap.option(ChannelOption.SO_BACKLOG,1024);
bootStrap.childHandler(new ChannelInitializer<SocketChannel>(){
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline=ch.pipeline();
pipeline.addLast(new ObjectEncoder());//将String类型转化为ByteBuf类型,解析发送出去的
pipeline.addLast(new ObjectDecoder(ClassResolvers.cacheDisabled(this.getClass().getClassLoader())));//将收到的ByteBuf转化为String类型,解析收到的
pipeline.addLast(new ServerHandler());
}
});
//绑定端口,同步等待成功.
ChannelFuture future=bootStrap.bind(port).sync();
//等待服务端监听端口关闭
future.channel().closeFuture().sync();
boss.shutdownGracefully();
work.shutdownGracefully();
}
ServerHandler处理器代码一样。
客户端:
public void startClient(String host,int port) throws InterruptedException{
EventLoopGroup group=new NioEventLoopGroup();
Bootstrap bootStrap=new Bootstrap();
bootStrap.group(group);
bootStrap.channel(NioSocketChannel.class);
bootStrap.option(ChannelOption.SO_KEEPALIVE,true);
bootStrap.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel sc) throws Exception {
ChannelPipeline pipeline=sc.pipeline();
pipeline.addLast(new ObjectEncoder());//将String类型转化为ByteBuf类型,解析发送出去的
pipeline.addLast(new ObjectDecoder(ClassResolvers.cacheDisabled(this.getClass().getClassLoader())));//将收到的ByteBuf转化为String类型,解析收到的
pipeline.addLast(new ClientHandler());
}
});
//绑定端口,同步等待成功.
ChannelFuture future=bootStrap.connect(host,port).sync();
Student student=new Student("user","psw");
future.channel().writeAndFlush(student);
//等待服务端监听端口关闭
future.channel().closeFuture().sync();
group.shutdownGracefully();
}
ClientHandler处理器代码一样。
对象Student(必须实现Serializable接口):
public class Student implements Serializable{
private String name;
private String psw;
public Student(String name,String psw){
this.name=name;
this.psw=psw;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPsw() {
return psw;
}
public void setPsw(String psw) {
this.psw = psw;
}
@Override
public String toString() {
return "[name:"+name+";password:"+psw+"]";
}
}
2.对象类型消息传递(protostuff实现序列化)
服务端:
bootStrap.childHandler(new ChannelInitializer<SocketChannel>(){
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline=ch.pipeline();
pipeline.addLast(new MyDecoder(Student.class));
pipeline.addLast(new MyEncoder(Student.class));
pipeline.addLast(new ServerHandler());
}
客户端:
bootStrap.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel sc) throws Exception {
ChannelPipeline pipeline=sc.pipeline();
pipeline.addLast(new MyDecoder(Student.class));
pipeline.addLast(new MyEncoder(Student.class));
pipeline.addLast(new ClientHandler());
传递对象:
public class Student{
private String name;
private String psw;
解码器:
public class MyDecoder extends ByteToMessageDecoder{
private Class<?> genericClass;
public MyDecoder(Class<?> genericClass) {
this.genericClass = genericClass;
}
@Override
public final void decode(ChannelHandlerContext ctx, ByteBuf buf, List<Object> out) throws Exception {
int dataLength = buf.readInt();//这边读取的第一个是长度字段
byte[] data = new byte[dataLength];
buf.readBytes(data);//将in中的数据写入data
Object obj = ProtoStuffUtil.deserialize(data, genericClass);
out.add(obj);
}
}
编码器:
public class MyEncoder extends MessageToByteEncoder{
private Class<?> genericClass;
public MyEncoder(Class<?> genericClass) {
this.genericClass = genericClass;
}
@Override
public void encode(ChannelHandlerContext ctx, Object in, ByteBuf out) throws Exception {
if (genericClass.isInstance(in)) {
byte[] data = ProtoStuffUtil.serialize(in);
out.writeInt(data.length);//这边设置的第一个是长度字段
out.writeBytes(data);
}
}
}
序列化工具类:
public class ProtoStuffUtil {
private static Map<Class<?>, Schema<?>> cachedSchema = new ConcurrentHashMap<>();
//对象转字节数组序列化
public static <T> byte[] serialize(T obj) {
Class<T> cls = (Class<T>) obj.getClass();//获取对象的类
LinkedBuffer buffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);//使用LinkedBuffer分配一块默认大小的buffer空间
try {
Schema<T> schema = getSchema(cls);//通过对象的类构建对象的schema
return ProtostuffIOUtil.toByteArray(obj, schema, buffer);//使用给定的schema将对象序列化为一个byte数组,并返回
} catch (Exception e) {
throw new IllegalStateException(e.getMessage(), e);
} finally {
buffer.clear();
}
}
//字节数组转对象反序列化
public static <T> T deserialize(byte[] data, Class<T> cls) {
try {
T message = cls.newInstance();
Schema<T> schema = getSchema(cls);
ProtostuffIOUtil.mergeFrom(data, message, schema);//使用给定的schema将byte数组和对象合并
return message;
} catch (Exception e) {
throw new IllegalStateException(e.getMessage(), e);
}
}
private static <T> Schema<T> getSchema(Class<T> cls) {
Schema<T> schema = (Schema<T>) cachedSchema.get(cls);
if (schema == null) {
schema = RuntimeSchema.createFrom(cls);
if (schema != null) {
cachedSchema.put(cls, schema);
}
}
return schema;
}
}
Netty
系列(三):
Netty
服务端
发送
消息
到
客户端
本文介绍如何利用
Netty
实现
服务端
向
客户端
推送
消息
的功能。通过保存
客户端
连接通道并检查其状态,确保
消息
能够准确地
发送
给在线的
客户端
。
Netty
实现长连接,
客户端
随时
发送
消息
给
服务端
,可在任意代码位置
发送
消息
给
服务端
本文介绍如何使用
Netty
实现
客户端
与服务器之间的长连接及心跳机制,并通过用户ID
发送
消息
到
服务端
。涵盖
Netty
服务端
与
客户端
的搭建过程,包括依赖配置、代码解析及
客户端
消息
发送
示例。
netty
客户端
发送
,
服务端
接收不到
消息
本文档详细描述了在使用
Netty
作为
客户端
时遇到的一个问题,即通过`channelFuture.channel().writeAndFlush()`
发送
ByteBuf,
服务端
无法正确接收。原因在于`RTUOutHandler`中未适配ByteBuf类型的处理,导致在`RTUInHandler`中接收数据时出现类型不匹配。解决方案是检查并调整handler链中
消息
类型的处理,确保在`RTUOutHandler`中正确处理Integer和ByteBuf类型的转换。此外,还展示了如何在`RTUInHandler`中判断并处理不同类型的输入。
Netty
服务端
(采集服务)
发送
消息
(指令)到
客户端
(设备、上位机)
本文介绍了如何使用
Netty
在
服务端
主动向
客户端
,如设备或上位机,
发送
消息
,包括连接管理、Channel存储与查找、心跳机制以及
消息
推送的实现细节。
netty
获取玩家chanel_基于
netty
的TCP
服务端
如何给
客户端
发送
消息
,但是如何拿到
客户端
连接时的SocketChannel呢,菜鸟求助?...
本文介绍了一种方法来解决
Netty
服务端
如何在不同类中获取
客户端
SocketChannel并
发送
消息
的问题。通过在SessionManager中保存每个
客户端
的SocketChannel,当
客户端
连接时,将SocketChannel与session关联。然而,当前方案限制了SocketChannel的访问,只在TCPServerHandler类内可用。为了解决这个问题,可以考虑将SessionManager设计为单例模式,并提供公共方法以在
服务端
的其他组件中获取和使用SocketChannel。
Java SE
62,622
社区成员
307,257
社区内容
发帖
与我相关
我的任务
Java SE
Java 2 Standard Edition
复制链接
扫一扫
分享
社区描述
Java 2 Standard Edition
社区管理员
加入社区
获取链接或二维码
近7日
近30日
至今
加载中
查看更多榜单
社区公告
暂无公告
试试用AI创作助手写篇文章吧
+ 用AI写文章