`
xiaoZ5919
  • 浏览: 404675 次
  • 性别: Icon_minigender_1
  • 来自: 安平人@北京
博客专栏
Group-logo
Netty学习笔记
浏览量:73191
社区版块
存档分类
最新评论

Nio框架需要注意的两个问题(2)

阅读更多

    书接上回,上次说到了selector的register和select会有锁冲突,这次再来考虑write的问题。

1. channel.write(Bytebuffer)是不是总是可写,当socket的writeBuffer满的时候会返回0,说明不能再写进任何字节。假设要写入一个很大的ByteBuffer,有可能需要分多次写。

2. channel上执行write操作需要获得锁保证同步,如果用户在应用代码中多处同时执行则会有锁竞争。

     我们知道NIO是无阻塞同步的IO,无阻塞说的是读或者写的就绪状态。一般来说写的流程是这样的,使channel对write感兴趣,然后轮询selector的select方法,遍历selectionKey,如果可写则对给channel执行写操作

 

 while (true) {

                try {
                    handlerRegister();
                    keyCount = selector.select(selectTimeout);
                    if(keyCount > 0)
                        debug(Thread.currentThread().getName() + " selected:" + keyCount);
                    Iterator<SelectionKey> iterator =
                            keyCount > 0 ? selector.selectedKeys().iterator() : null;
                        // Walk through the collection of ready keys and dispatch
                        // any active event.
                        while (iterator != null && iterator.hasNext()) {
                            SelectionKey sk = iterator.next();
                            NioSession session = (NioSession)sk.attachment();
                            // Attachment may be null if another thread has called
                            // cancelledKey()
                            if (session == null) {
                                iterator.remove();
                            } else {
                                iterator.remove();
                                if(sk.isValid() && sk.isWritable()){
                                    debug("Session write:" + session);
                                    session.write();//可写时 执行写操作
                                }else if(sk.isValid() && sk.isReadable()){
                                    debug("Session read:" + session);
                                    session.read();
                                }else{
                                	debug("Session close from select");
                                    session.close();
                                }
                            }
                        }//while
                } catch (IOException e) {
                   debug("I'm here");
                    e.printStackTrace();
                }
            }

        }

 从上面的代码我们很快就发现一个问题,这个写操作是在Poller的SelectorLoop,假设我们需要在程序代码中执行write操作的时候,根本不知道什么时候可写。那我们不管什么selector的可读可写。直接执行channel.write()是否可以。可以不总是可行,就像前面提到的。writeBuffer已满是不能写入任何byte的。

     对于这个问题,Tomcat和Netty采用不同的解决方案,先说一个tomcat的方案:

     Tomcat采用阻塞写的方案,首先循环执行channle.write(buffer)直到不可写,当buffer没有写完即hasRemaining为true,则注册到一个blockingSelector执行不断轮询阻塞写。一般来说tomcat返回的html没有那么大就不需要注册给阻塞的selector,tomcat这样处理而只在Poller中执行读操作,还有另外一个好处。减少了每个SelectorLoop的时间把所有的时间都交给了读事件的处理大大提交了吞吐量。

 

 try {
            while ( (!timedout) && buf.hasRemaining()) {
                if (keycount > 0) { //only write if we were registered for a write
                    int cnt = socket.write(buf); //write the data
                    if (lastWrite != null) lastWrite.set(cnt);
                    if (cnt == -1)
                        throw new EOFException();
                    written += cnt;
                    if (cnt > 0) {
                        time = System.currentTimeMillis(); //reset our timeout timer 首先直接执行channel的write直到不能写入任何byte,这时候就需要交给另外一个selector处理
                        continue; //we successfully wrote, try again without a selector
                    }
                }
                try {
                    if ( att.getWriteLatch()==null || att.getWriteLatch().getCount()==0) att.startWriteLatch(1);
                    poller.add(att,SelectionKey.OP_WRITE,reference);//注册给阻塞的selector
//同时加了一个CountDownLatch,如果Selector的select一直没有检测到该channel可写而执行countDown()则会后续根据count是否超时                    att.awaitWriteLatch(writeTimeout,TimeUnit.MILLISECONDS);
                }catch (InterruptedException ignore) {
                    Thread.interrupted();
                }
                if ( att.getWriteLatch()!=null && att.getWriteLatch().getCount()> 0) {
                    //we got interrupted, but we haven't received notification from the poller.
                    keycount = 0;
                }else {
                    //latch countdown has happened
                    keycount = 1;
                    att.resetWriteLatch();
                }

                if (writeTimeout > 0 && (keycount == 0))
                    timedout = (System.currentTimeMillis() - time) >= writeTimeout;
            } //while
            if (timedout)
                throw new SocketTimeoutException();
        } finally {
            poller.remove(att,SelectionKey.OP_WRITE);
            if (timedout && reference.key!=null) {
                poller.cancelKey(reference.key);
            }
            reference.key = null;
        }

  blog编辑器有点不太好用,后续再介绍一个Netty的解决方案。

0
0
分享到:
评论

相关推荐

    Java NIO通信框架在电信领域的实践

    电信软件是一个宽泛的概念,根据功能和应用场景的不同大致可以分为两大类:系统软件和业务应用软件。系统软件通常涉及底层技术和基础设施,如路由器中的信令机软件和移动设备的操作系统等。而业务应用软件则更侧重于...

    java NIO异步框架

    5. **管道(Pipe)**:管道用于在两个线程间进行单向数据传输。在一个线程中写入的数据可以在另一个线程中读出。 6. **内存映射文件(Memory-Mapped File)**:NIO允许将文件映射到内存中,使得文件操作如同访问...

    基于NIO框架的TeeTime信息平台的设计与实现

    基于NIO框架的TeeTime信息平台的设计与实现一文,详细阐述了Java网络应用开发中面临的并发处理问题,并对NIO(New I/O)技术在Java中的应用进行了深入研究。文章首先指出,在Web2.0时代,应用与客户的互动性要求网络...

    NIO简易服务器框架、文件传输

    在这个例子中,有两个过滤器已经实现: - **日志过滤器(Logger Filter)**:此过滤器负责记录客户端的请求信息,便于调试和追踪。它在数据流转过程中,记录相关的操作和状态。 - **文件拦截过滤器(File ...

    java NIO技巧及原理

    在Java NIO中,"新"主要体现在非阻塞和多路复用这两个特性上,这使得NIO更适合于高并发、低延迟的系统。 **Java IO原理:** Java IO基于流模型,分为输入流和输出流。流是一维数据序列,可以是从源到目标的单向流动...

    基于NIO的Java聊天室2

    接下来,我们要解决的是上一版本中的一个严重问题:当两个客户端同时启动时,CPU占用率高达100%。这通常是由于线程资源的不当使用导致的。在NIO中,通常我们会使用Selector(选择器)来监听多个通道(Channel)的...

    NIO和Netty框架的学习

    NIO(Non-blocking Input/Output)和Netty框架是Java平台上的两个核心概念,它们极大地提升了网络应用的性能和效率。本篇文章将深入探讨NIO的基本原理和Netty框架的使用,帮助你从初学者逐渐晋升为高级开发者。 ...

    Java NIO英文高清原版

    7. **管道(Pipe)**:管道是两个线程间进行单向数据传输的通道。一个线程写入数据,另一个线程读取数据。 Netty利用NIO的特性,提供了高度优化的API,使得开发者可以轻松地构建高效、可靠的网络服务。Netty的事件...

    NioSocket,包括server端和client端

    NioSocket是一个基于Java NIO(非阻塞I/O)技术实现的网络通信框架,它包含服务器端(Server)和客户端(Client)两部分。在Java编程中,NIO(New Input/Output)提供了一种不同于传统IO模型的I/O操作方式,其核心...

    Java NIO 中英文版 + Pro Java 7 NIO.2

    6. **管道(Pipes)**:管道是两个线程之间进行单向数据传输的通道,用于线程间通信。 7. **网络编程**:Java NIO引入了SocketChannel和ServerSocketChannel,用于实现高效的TCP/IP和UDP/IP通信。这些通道与传统的...

    用NIO解析modbus协议

    标题中的“用NIO解析modbus协议”表明我们要探讨的是如何使用Java的非阻塞I/O(Non-blocking Input/Output,简称NIO)框架来处理Modbus通信协议。Modbus是一种广泛使用的工业通信协议,主要在自动化设备之间进行数据...

    Java NIO Socket基本

    4. **管道(Pipe)**:在某些特定情况下,两个线程之间可以使用`java.nio.Pipe`进行单向数据传递。 5. **文件系统API**:NIO还提供了`java.nio.file`包,包含一系列与文件系统交互的类,如Files、Paths等。 Java ...

    NIO trick and trap NIO网络

    #### NIO框架的设计与优化 - **Reactor模式**:这是一种常见的设计模式,用于实现NIO网络框架。它包含以下核心组件: - **SynchronousEventDemultiplexer**:负责事件循环和事件分离。 - **Dispatcher**:事件...

    nio_javanio_NIO_

    管道是两个线程之间的单向数据通道。通过Pipe的SinkChannel写入数据,SourceChannel读取数据,可以实现线程间的通信。 7. **字符集转换** NIO提供了Charset、CharsetDecoder和CharsetEncoder类来处理字符编码和...

    NIO实例

    5. **管道(Pipes)**:用于两个线程间的数据传输。 描述中提到的"博文链接:https://smallbee.iteye.com/blog/2008119"可能提供了一个关于NIO实际应用的示例或详细讲解。虽然具体内容无法在此直接查看,但通常博主...

    talent-nio3.0.0备份

    【标题】"talent-nio3.0.0备份"所指的可能是一个关于NIO(Non-blocking Input/Output)的开源项目或者框架的版本3.0.0的备份文件。NIO是Java中的一种I/O模型,它与传统的 Blocking I/O 相比,提供了更加高效的数据...

    MINA通讯框架的两个简单实例和文档

    Apache的Mina(Multipurpose Infrastructure Networked ... NIO框架  客户端/服务端框架(典型的C/S架构)  网络套接字(networking socket)类库  事件驱动的异步API(注意:在JDK7中也新增了异步API)

    Socket 之 BIO、NIO、Netty 简单实现

    它允许两个网络应用程序之间建立连接并交换数据。在Java中,`java.net.Socket`和`java.net.ServerSocket`类是进行Socket编程的主要接口。 **2. BIO ( Blocking I/O)** BIO是Java早期提供的网络通信模型,特点是...

    Java IO_NIO

    2. 多路复用:NIO的选择器允许单线程管理多个通道,而传统的IO需要为每个连接创建一个新的线程,导致资源消耗较大。 3. 缓存区:NIO引入了缓冲区,提高了数据传输的效率和灵活性。 总结来说,Java NIO提供了一种更...

Global site tag (gtag.js) - Google Analytics