java Netty 之消息收发次数不匹配额问题
问题
在前面代码中,分三次发送信息:
private void sendMessageByFrame(ChannelStateEvent e) { String msgOne = "Hello, "; String msgTwo = "I'm "; String msgThree = "client."; e.getChannel().write(tranStr2Buffer(msgOne)); e.getChannel().write(tranStr2Buffer(msgTwo)); e.getChannel().write(tranStr2Buffer(msgThree)); }
这样的方式,连续返送三次消息。但是如果你在服务端进行接收计数的话,你会发现,大部分时候都是接收到两次的事件请求。不过消息都是完整的。
检查方法二
笔者从开始就怀疑是连续写入过快导致的问题,所以测试过每次write后停顿1秒。再write下一次。结果一切正常。
猜想原因
出现这样的现象,最大的原因就是缓存,连续发送太快,数据会进入到缓存,然后再定时在缓存中将数据取出来。
注意
1. 有一个messageReceived事件,事件的触发,是在读取完当前缓冲池中所有的信息之后在触发的。这倒是可以解释,为什么即使我们收到事件的次数少,但是消息是完整的。
2. 从目前来看,Netty通过Java 的NIO机制传递数据,数据读写跟事件没有严格的绑定机制。数据是以流的形式独立存在,读写都有一个缓冲池。
Selector模式
NIO 有一个主要的类Selector,这个类似一个观察者,只要我们把需要探知的socketchannel告诉Selector,我们接着做别的事情,当有事件发生时,他会通知我们,传回一组SelectionKey,我们读取这些Key,就会获得我们刚刚注册过的socketchannel,然后,我们从这个Channel中读取数据,放心,包准能够读到,接着我们可以处理这些数据。
Selector服务端样例代码:
/** * Java NIO Select模式服务端样例代码 * */ public class NioSelectorServer { public static void main(String[] args) throws IOException { // 创建一个selector选择器 Selector selector = Selector.open(); // 打开一个通道 ServerSocketChannel socketChannel = ServerSocketChannel.open(); // 绑定到9000端口 socketChannel.socket().bind(new InetSocketAddress(8000)); // 使设定non-blocking的方式。 socketChannel.configureBlocking(false); // 向Selector注册Channel及我们有兴趣的事件 socketChannel.register(selector, SelectionKey.OP_ACCEPT); for (;;) { // 选择事件 selector.select(); // 当有客户端准备连接到服务端时,便会出发请求 for (Iterator<SelectionKey> keyIter = selector.selectedKeys() .iterator(); keyIter.hasNext();) { SelectionKey key = keyIter.next(); keyIter.remove(); System.out.println(key.readyOps()); if (key.isAcceptable()) { System.out.println("Accept"); // 接受连接到此Channel的连接 socketChannel.accept(); } } } } }
Selector客户端样例代码:
/** * Java NIO Selector模式,客户端代码 * */ public class NioSelectorClient { public static void main(String[] args) throws IOException { SocketChannel channel = SocketChannel.open(); channel.configureBlocking(false); channel.connect(new InetSocketAddress("127.0.0.1", 8000)); } }
结果:
服务端接受到客户端的连接请求后,会打印出"Accept"信息。
简单概括就是,整一个通道,通道加个选择过滤器,看来的事件是不是我想要的,不想要的干脆不管,想要的,我就存起来,留着慢慢处理。Netty的实现机制也是按照这种原理。
最后总结
首先,Selector机制让我们注册一个感兴趣的事件,然后只要有该事件发生,就会传递给接收端。我们写了三次,接收端一定会出发三次的。然后,Netty实现机制里,有个Buffer缓冲池,把收到的信息都缓存在里面,通过一个线程统一处理。也就是我们看到的那个buffer的处理过程。
Netty的设置中,有一个一次性最多读取字节大小的设定。并且,事件的触发是在处理过缓冲池中的消息之后。我们再来回顾一下Netty中读取信息的那段代码:
ByteBuffer bb = recvBufferPool.acquire(predictedRecvBufSize); try { while ((ret = ch.read(bb)) > 0) { readBytes += ret; if (!bb.hasRemaining()) { break; } } failure = false; } catch (ClosedChannelException e) { // Can happen, and does not need a user attention. } catch (Throwable t) { fireExceptionCaught(channel, t); } if (readBytes > 0) { bb.flip(); final ChannelBufferFactory bufferFactory = channel.getConfig().getBufferFactory(); final ChannelBuffer buffer = bufferFactory.getBuffer(readBytes); buffer.setBytes(0, bb); buffer.writerIndex(readBytes); recvBufferPool.release(bb); // Update the predictor. predictor.previousReceiveBufferSize(readBytes); // Fire the event. fireMessageReceived(channel, buffer); } else { recvBufferPool.release(bb); }
可以看到,如果没有读取到字节是不会触发事件的,所以我们可能会收到2次或者3次信息。(如果发的快,解析的慢,后两次信息,一次性读取了,就2次,如果发送间隔长,分次解析,就收到3次。)原因应该就是如此。跟我们开始猜的差不多。
参考:
http://www.it165.net/pro/html/201207/3219.html
相关推荐
基于 Java Netty实现的可用于内网穿透的代理工具.zip基于 Java Netty实现的可用于内网穿透的代理工具.zip基于 Java Netty实现的可用于内网穿透的代理工具.zip基于 Java Netty实现的可用于内网穿透的代理工具.zip基于...
在Java中,处理串口通信并不像处理网络套接字那样常见,但Netty提供了一种方式来扩展其功能以支持这种通信模式。 首先,我们需要了解Netty中的Channel接口,它是所有I/O操作的核心。在串口通信中,我们需要创建一个...
Java Netty是一个高性能、异步事件驱动的网络应用程序框架,常用于开发高效的网络服务,包括TCP、UDP等网络协议的应用。在"基于Java Netty的UDP客户端声呐数据对接"项目中,我们主要关注如何利用Netty处理UDP通信,...
在Java编程环境中,Netty是一个高性能、异步事件驱动的网络应用程序框架,常用于构建可伸缩、高并发的服务器。本示例关注的是如何利用Netty实现一个基于UDP(User Datagram Protocol)的数据接收服务,这在需要进行...
在Java中,Netty提供了一个名为ProtobufDecoder和ProtobufEncoder的类,它们可以帮助我们自动地对protobuf消息进行解码和编码。 当C++客户端需要向Java服务器发送数据时,先序列化protobuf消息,然后通过socket发送...
Java Netty是一个高性能、异步事件驱动的网络应用程序框架,用于快速开发可维护的高性能协议服务器和客户端。这本书“Java Netty权威指南”是深入理解并掌握Netty的关键资源,包含详细的目录,使得学习和查阅更为...
在这个“基于Netty的服务器客户端收发消息代码”中,我们可以看到一个简单的实现,它演示了如何使用Netty进行双向通信,即服务器与客户端之间的消息交换。 首先,我们从服务器端(ChatServer)入手。服务器端通常...
标题"Java Netty客户端与服务器"表明我们将探讨如何使用Netty构建一个简单的服务器和客户端系统,其中客户端能够发送消息到服务器,而服务器则会给予响应。这种通信模式在许多分布式系统中非常常见,例如聊天应用、...
Netty 是一个基于 Java 的高性能、异步事件驱动的网络应用程序框架,专为开发协议服务器和客户端而设计。它的核心是基于 NIO(非阻塞 I/O)模型,提供了丰富的 API 和高度可定制的组件,使得开发者能够快速、高效地...
Java Netty是一个高性能、异步事件驱动的网络应用程序框架,用于快速开发可维护的高性能协议服务器和客户端。这个"Java Netty基于对象数据传输Demo"应该是演示了如何使用Netty进行对象序列化和反序列化,以便在网络...
Netty的组件和设计使其在分布式系统的网络通信中表现出色,比如处理消息分段、粘包和半包问题、心跳检测、重连机制等。它的扩展性允许开发者针对特定的业务需求开发插件。例如,在处理用户登录时,可以添加一个...
Java应用程序中的Netty框架是一个高性能、异步事件驱动的网络应用程序框架,用于快速开发可维护的高性能协议服务器和客户端。Netty广泛应用于分布式系统、云计算、大数据处理等领域,它的核心特性包括非阻塞I/O、...
netty-mqtt是一个基于Java开发的MQTT 3.1.1协议服务端与客户端,包含113个文件,其中包括87个Java源文件、8个XML文件、7个Iml文件、3个YAML文件、3个JKS文件、2个Factories文件、1个LICENSE文件和1个Markdown文件。...
JAVA版基于netty的物联网高并发智能网关 JAVA版基于netty的物联网高并发智能网关 JAVA版基于netty的物联网高并发智能网关 JAVA版基于netty的物联网高并发智能网关 JAVA版基于netty的物联网高并发智能网关 JAVA...
在这个项目中,我们将深入理解如何利用 Netty 4 来编写服务器和客户端,实现自定义的消息编解码,并进行通信。 首先,我们要创建一个自定义的消息类。这个消息类通常会包含必要的字段,比如消息头、消息体等,以...
标题中的“Netty实现Java服务端和C#客户端联通”是指使用Netty作为Java服务器框架,与C#客户端(使用DotNetty库)进行通信的一种技术实现。这涉及到跨平台的网络通信,以及两个不同编程语言间的交互。 Netty是Java...
java netty需要的包。。。。。。。。。。。。java netty需要的包,netty-3.2.10.Final.jar一个就行
【作品名称】:基于Java+Netty开发的即时通信基础框架,支持websocket与Netty客户端的消息传递 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期...
JAVA netty完整示例代码。里面包括整个项目和所需的JAR包。示例以:TCP/IP自定义报文协议进行解析分析,基于帧头HEAD_DATA=0x76解析过程的示例代码,并对数据进行粘包分离的处理。粘包处理方式有两种:1.自定义报文...
这是一个java web项目集成了netty websocket的完整代码。java web项目作为服务器端和客户端进行数据通信。但是常常存在提示Max frame length of 65536 has been exceeded问题。初始化握手对象时指定了...