客户端发送消息并同步获取结果,其实是违背Netty的设计原则的,但是有时候不得不这么做的话,那么建议进行如下的设计:

比如我们的具体用法如下:

  NettyRequest request = new NettyRequest();
request.setRequestId(UUID.randomUUID().toString());
request.setClassName(method.getDeclaringClass().getName());
request.setMethodName(method.getName());
request.setParameterTypes(method.getParameterTypes());
request.setParameterValues(args); NettyMessage nettyMessage = new NettyMessage();
nettyMessage.setType(MessageType.SERVICE_REQ.value());
nettyMessage.setBody(request); if (serviceDiscovery != null) {
serverAddress = serviceDiscovery.discover();
}
String[] array = serverAddress.split(":");
String host = array[0];
int port = Integer.parseInt(array[1]); NettyClient client = new NettyClient(host, port);
NettyMessage nettyResponse = client.send(nettyMessage);
if (nettyResponse != null) {
return JSON.toJSONString(nettyResponse.getBody());
} else {
return null;
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

先来看看NettyClient的写法 和 send方法的写法:

public class NettyClient {

    /**
* 日志记录
*/
private static final Logger logger = LoggerFactory.getLogger(NettyClient.class); /**
* 客户端业务处理handler
*/
private ClientHandler clientHandler = new ClientHandler(); /**
* 事件池
*/
private EventLoopGroup group = new NioEventLoopGroup(); /**
* 启动器
*/
private Bootstrap bootstrap = new Bootstrap(); /**
* 客户端通道
*/
private Channel clientChannel; /**
* 客户端连接
* @param host
* @param port
* @throws InterruptedException
*/
public NettyClient(String host, int port) throws InterruptedException {
bootstrap.group(group)
.channel(NioSocketChannel.class)
.option(ChannelOption.TCP_NODELAY, true)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel channel) throws Exception {
channel.pipeline().addLast("idleStateHandler", new IdleStateHandler(5, 5, 12));
channel.pipeline().addLast("nettyMessageDecoder", new NettyMessageDecoder(1024 * 1024, 4, 4));
channel.pipeline().addLast("nettyMessageEncoder", new NettyMessageEncoder());
channel.pipeline().addLast("heartBeatHandler", new HeartBeatRequestHandler());
channel.pipeline().addLast("clientHandler", clientHandler);
channel.pipeline().addLast("loginAuthHandler", new LoginAuthRequestHandler());
}
}); //发起同步连接操作
ChannelFuture channelFuture = bootstrap.connect(host, port); //注册连接事件
channelFuture.addListener((ChannelFutureListener)future -> {
//如果连接成功
if (future.isSuccess()) {
logger.info("客户端[" + channelFuture.channel().localAddress().toString() + "]已连接...");
clientChannel = channelFuture.channel();
}
//如果连接失败,尝试重新连接
else{
logger.info("客户端[" + channelFuture.channel().localAddress().toString() + "]连接失败,重新连接中...");
future.channel().close();
bootstrap.connect(host, port);
}
}); //注册关闭事件
channelFuture.channel().closeFuture().addListener(cfl -> {
close();
logger.info("客户端[" + channelFuture.channel().localAddress().toString() + "]已断开...");
});
} /**
* 客户端关闭
*/
private void close() {
//关闭客户端套接字
if(clientChannel!=null){
clientChannel.close();
}
//关闭客户端线程组
if (group != null) {
group.shutdownGracefully();
}
} /**
* 客户端发送消息
* @param message
* @return
* @throws InterruptedException
* @throws ExecutionException
*/
public NettyMessage send(NettyMessage message) throws InterruptedException, ExecutionException {
ChannelPromise promise = clientHandler.sendMessage(message);
promise.await(3, TimeUnit.SECONDS);
return clientHandler.getResponse();
}
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

可以看出,我们使用了clientHandler来进行消息发送行为,通过promise阻塞来同步获取返回结果,接下来看看sendMessage的写法:

public class ClientHandler extends ChannelInboundHandlerAdapter {

    private static final Logger logger = LoggerFactory.getLogger(ClientHandler.class);

    private ChannelHandlerContext ctx;
private ChannelPromise promise;
private NettyMessage response; @Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
super.channelActive(ctx);
this.ctx = ctx;
} @Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
NettyMessage message = (NettyMessage) msg;
if (message != null && message.getType() == MessageType.SERVICE_RESP.value()) {
response = message;
promise.setSuccess();
} else {
ctx.fireChannelRead(msg);
}
} public synchronized ChannelPromise sendMessage(Object message) {
while (ctx == null) {
try {
TimeUnit.MILLISECONDS.sleep(1);
//logger.error("等待ChannelHandlerContext实例化");
} catch (InterruptedException e) {
logger.error("等待ChannelHandlerContext实例化过程中出错",e);
}
}
promise = ctx.newPromise();
ctx.writeAndFlush(message);
return promise;
} public NettyMessage getResponse(){
return response;
} }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

可以看到,在利用ChannelHanderContext进行发送消息前,我们先创建了一个promise并返回给send方法,那么send方法此时就会阻塞等待;当我们收到服务端消息后,promise.setSuccess就会解除send方法的等待行为,这样我们就能获取结果了。

此法针对真正需要同步等待获取结果的场景,如非必要,还是建议利用future来改造。

benchmark测试表明,此种同步获取结果的行为,表现挺稳定的,但是ops 在 150 左右, 真是性能太差了。高性能场合禁用此法。

Netty客户端发送消息并同步获取结果的更多相关文章

  1. 使用Java客户端发送消息和消费的应用

    体验链接:https://developer.aliyun.com/adc/scenario/fb1b72ee956a4068a95228066c3a40d6 实验简介 本教程将Demo演示使用jav ...

  2. 基于NIO的同步非阻塞编程完整案例,客户端发送请求,服务端获取数据并返回给客户端数据,客户端获取返回数据

    这块还是挺复杂的,挺难理解,但是多练几遍,多看看研究研究其实也就那样,就是一个Selector轮询的过程,这里想要双向通信,客户端和服务端都需要一个Selector,并一直轮询, 直接贴代码: Ser ...

  3. mina客户端发送消息延迟问题分析

    原文:http://www.cnblogs.com/haiq/archive/2011/08/01/2124292.html (写的蛮好,保存下来) 由于项目需要,用到了 mina 框架进行 tcp ...

  4. Spring Boot+Socket实现与html页面的长连接,客户端给服务器端发消息,服务器给客户端轮询发送消息,附案例源码

    功能介绍 客户端给所有在线用户发送消息 客户端给指定在线用户发送消息 服务器给客户端发送消息(轮询方式) 项目搭建 项目结构图 pom.xml <?xml version="1.0&q ...

  5. java socket 一个服务器对应多个客户端,可以互相发送消息

    直接上代码,这是网上找的demo,然后自己根据需求做了一定的修改.代码可以直接运行 服务器端: package socket; import java.io.BufferedReader; impor ...

  6. ActiveMQ producer同步/异步发送消息

    http://activemq.apache.org/async-sends.html producer发送消息有同步和异步两种模式,可以通过代码配置: ((ActiveMQConnection)co ...

  7. Socket通讯-C#客户端与Java服务端通讯(发送消息和文件)

    设计思路 使用websocket通信,客户端采用C#开发界面,服务端使用Java开发,最终实现Java服务端向C#客户端发送消息和文件,C#客户端实现语音广播的功能. Java服务端设计 packag ...

  8. 2.技巧: 用 JAXM 发送和接收 SOAP 消息—Java API 使许多手工生成和发送消息方面必需的步骤自动化

    转自:https://www.cnblogs.com/chenying99/archive/2013/05/23/3094128.html 技巧: 用 JAXM 发送和接收 SOAP 消息—Java ...

  9. server-sent-event使用流信息向客户端发送数据

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

随机推荐

  1. Qt框架及模块认识

    小白自工作就接触Qt,一直都在使用Qt5.3.1版本,所以没有经历过大牛们把项目从Qt4程序到Qt5的烦恼,没准以后会碰到.对Qt所有的丰富的API表示惊叹,对于Qt的框架及模块认识也是极为模糊的,文 ...

  2. java0422 wen 集合框架

  3. 自制操作系统Antz(7)——实现内核 (上)

    Antz系统更新地址: https://www.cnblogs.com/LexMoon/category/1262287.html Linux内核源码分析地址:https://www.cnblogs. ...

  4. Scrum Meeting 合集

    一.Alpha [Alpha]Scrum meeting 1 [Alpha]Scrum meeting 2 [Alpha]Scrum meeting 3 [Alpha]Scrum meeting 4 ...

  5. SpringMVC,SpringBoot利用ajax上传文件到后台

    1.传递单文件 首先html文件中有个<input type=”file” name=”file” id=”file”/>元素. 前台js写法: var formData=new Form ...

  6. wireshark基础学习—第二部分wireshark的基础操作

    抓取报文: 下载和安装好Wireshark之后,启动Wireshark并且在接口列表中选择接口名,然后开始在此接口上抓包.例如,如果想要在无线网络上抓取流量,点击无线接口.点击Capture Opti ...

  7. Yum安装时出现 The program yum-complete-transaction is found in the yum-utils package

    yum安装时出现 The program yum-complete-transaction is found in the yum-utils package yum之后,会显示上信息,并且最终执行结 ...

  8. OpenVPN部署,实现访问云服务器的内网

    本教程不描述如何FQ 一.OpenVPN服务端部署 $ yum -y install net-tools lzo lzo-devel openssl-devel pam-devel gcc gcc-c ...

  9. ACM:日历本

    题目描述 我们经常需要使用日历,所以需要一个能生成日历的程序. 先要求你写一个程序,只需要输入年份,就能生成正确的日历. 输入 输入包含多组测试数据.每组输入一个整数Y(1800<=Y<= ...

  10. UVA - 11468 (AC自动机+动态规划)

    建立AC自动机,把AC自动机当做一张图,在上面跑L个节点就行了. 参考了刘汝佳的代码,发现可能有一个潜在的Bug--如果模式串中出现了没有指定的字符,AC自动机可能会建立出错. 提供一组关于这个BUG ...