`

nio

阅读更多

来源http://blog.chinaunix.net/uid-9460004-id-3224208.html

参考:

  http://blog.csdn.net/xymyeah/article/details/3714667
  http://blog.csdn.net/wfeng007/article/details/5308614
  http://www.oschina.net/question/54100_33531 *

 

  普通的 Sock 拥塞

     在 ServerSocket的accept()方法;和InputStream的read()方式

         因此我们需要两类型的线程分别进行处理。而且每一个阻塞方法所绑定的线程的生命周期和网络连接的生命周期是一致的 -- 并发造成大量维护线程,导致浪费

        

    NIO 的解决办法 : 

        1.  数据缓冲处理(ByteBuffer) :解决 read/write 大量使用线程和每个线程中使用的缓存区内存问题

                ByteBuffer 可使用 <共享缓冲区 - view buffer >

                还可以使用 Direct ByteBuffer - native 本地非java内存 ,提高性能
             
         为方便大家理解,下面用自己的语言描述下  : 
                 position(操作游标) < limit(某操作挡板) < capacity(整个缓存大小)  :
              
          a。在写入场景中  (以写入数据第一行灰色); 
          b。执行filp(),就变成读取场景 ,游标指向写入开始,挡板放置在写入最后结束位置
                 


           a。读取到最后,执行clear() ,缓存区状态回到初始
                 
               




          2. 异步通道 (Channel) : [我的理解] Channel 是使用底层系统方法传送 Client Sock消息到 Server Buffer 中 ,非传统方式 使用 线程去传送消息. 

              Channel 维护ByteBuffer - Client Socket 的关系 

           3. 有条件的选择(Readiness Selection):

                 a. 有Channel 底层系统支持消息传输, 非拥塞主要的逻辑实现部分。

                 b. [我的理解]非拥塞的机制 :是由监听Channel的事件完成。消息交给底层系统接口维护(非java线程维护的)当消息传输结束或一段落,就触发Server上的一个响应事件,这样一个客户端消息传递请求就可以快速返回。

                 SelectionKey标识Selector和SelectableChannel,一旦一个Channel注册到Selector中,就会返回一个SelectionKey对象

                 SelectionKey保存了两类状态:对应的 Channel注册了哪些操作;对应的Channel的那些操作已经准备好了,可以进行相应的数据操作了)结合来实现这个功能的。







在参考中还提到这种非拥塞方式的一些弊端(当然 一些有特点的技术是有使用场景的):

  1. 持久连接的超时问题(Timeout) 

         感觉这是个棘手问题,虽然交给底层维护消息的缓冲,但当一个消息的缓冲超时事件应该很有必要监听把 ?? 这个监听事件没有??

   2. 如何使用Selector,由于每一个Selector的处理能力是有限的

   3.    在非阻塞情况下,read和write都不在是阻塞的, 相对应的 IO不好的问题如果消息传输有丢失怎么办 ?

   4. 如何共享内存Buffer,这给 程序猿 增加一定难度

   5.  网络非拥塞造成的消息顺序问题 

    6. 内存泄露 




   NIO 两种并发线程 的介绍,目前还没具体使用 ,不给个人理解。




这上网上抄了个demo - 先mark下,到时加自己的注解
Client 端输出 
 $> welcome to VistaQQ 



点击(此处)折叠或打开

1.if __name__ == '__main__':

2.    import socket

3.    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

4.    sock.connect(('localhost', 6018))

5.    import time

6.    #time.sleep(2)

7.    sock.send('1 test !~ ')

8.    print sock.recv(1024)

9.    sock.close()


服务端输出(客户端运行了 3次 ) : 
$> 服务器启动
$> Client >> 1 test !~
$> key.isWritable
$>   block = java.nio.HeapByteBuffer[pos=0 lim=18 cap=18]

$> Client >> 1 test !~
$> key.isWritable
$>   block = java.nio.HeapByteBuffer[pos=0 lim=18 cap=18]
$> 
$> Client >> 1 test !~
$> key.isWritable
$>   block = java.nio.HeapByteBuffer[pos=0 lim=18 cap=18]




 点击(此处)折叠或打开

1.//package com.vista.Server;

2.

3.import java.io.BufferedWriter;

4.import java.io.FileInputStream;

5.import java.io.IOException;

6.import java.io.OutputStreamWriter;

7.import java.io.PrintWriter;

8.import java.net.InetSocketAddress;

9.import java.net.ServerSocket;

10.import java.nio.ByteBuffer;

11.import java.nio.CharBuffer;

12.import java.nio.channels.FileChannel;

13.import java.nio.channels.SelectionKey;

14.import java.nio.channels.Selector;

15.import java.nio.channels.ServerSocketChannel;

16.import java.nio.channels.SocketChannel;

17.import java.nio.charset.Charset;

18.import java.nio.charset.CharsetDecoder;

19.import java.util.Iterator;

20.import java.util.LinkedList;

21.import java.util.Set;

22.

23.

24.

25.public class SelectorServer {

26.

27.    private static int DEFAULT_SERVERPORT = 6018;//默认端口

28.    private static int DEFAULT_BUFFERSIZE = 1024;//默认缓冲区大小为1024字节

29.

30.    private static String DEFAULT_CHARSET = "GB2312";//默认码集

31.    private static String DEFAULT_FILENAME = "bigfile.dat";

32.

33.    private ServerSocketChannel sschannel;

34.

35.    private Selector selector;//选择器

36.    private ByteBuffer buffer;//字节缓冲区

37.

38.    private int port;

39.    private Charset charset;//字符集

40.    private CharsetDecoder decoder;//解码器

41.

42.    

43.

44.    

45.

46.    public SelectorServer(int port) throws IOException {

47.        this.port = port;

48.        this.sschannel = null;

49.

50.        this.selector = Selector.open();//打开选择器

51.

52.        this.buffer = ByteBuffer.allocate(DEFAULT_BUFFERSIZE);

53.

54.        this.charset = Charset.forName(DEFAULT_CHARSET);

55.        this.decoder = this.charset.newDecoder();

56.    }

57.

58.    

59.

60.     private class HandleClient {

61.

62.         private String strGreeting = "welcome to VistaQQ";

63.

64.         public HandleClient() throws IOException {

65.         }

66.

67.         public String readBlock() {

68.     //读块数据

69.             return this.strGreeting;

70.         }

71.

72.         public void close() {

73.         }

74.

75.    }

76.

77.

78.

79.    protected void handleKey(SelectionKey key) throws IOException {

80.          //处理事件

81.          if (key.isAcceptable()) {

82.              // 接收请求

83.              ServerSocketChannel server = (ServerSocketChannel) key.channel();

84.             //取出对应的服务器通道

85.              SocketChannel schannel = server.accept();

86.              schannel.configureBlocking(false);

87.              //客户socket通道注册读操作

88.              schannel.register(selector, SelectionKey.OP_READ);

89.          } else if (key.isReadable()) {

90.              // 读信息

91.              SocketChannel schannel = (SocketChannel) key.channel();

92.              int count = schannel.read(this.buffer);

93.              if (count > 0) {

94.                this.buffer.flip();

95.                CharBuffer charBuffer = decoder.decode(this.buffer);

96.                System.out.println("Client >> " + charBuffer.toString());

97.                // 注册写入 和添加 处理者 

98.                schannel.register(selector,

99.                                  SelectionKey.OP_WRITE|SelectionKey.OP_READ,

100.                                  new HandleClient());

101.              } else {

102.                //客户已经断开

103.                schannel.close();

104.              }

105.

106.              this.buffer.clear();//清空缓冲区

107.

108.         } else if (key.isWritable()) {

109.             System.out.println("key.isWritable");

110.              // 写事件

111.              SocketChannel schannel = (SocketChannel) key.channel();

112.              HandleClient handle = (HandleClient) key.attachment();//取出处理者
113.              // 包装一个 缓冲区  
114.              ByteBuffer block = ByteBuffer.wrap(handle.readBlock().getBytes());

115.             System.out.println(" block = "+block);

116.              schannel.write(block);

117.             

118.              // 是表示Socket可写,网络不出现阻塞情况下,一直是可以写的,

119.              // 所认一直为true. 一般不注册OP_WRITE事件,或特别小心注册写入事件.

120.              // 为测试 直接 取出 写入 事件 

121.              key.interestOps(SelectionKey.OP_READ);

122.              //channel.close();

123.

124.        }

125.

126.

127.

128.    }

129.

130.    public void listen() throws IOException {

131.    //服务器开始监听端口,提供服务

132.        ServerSocket socket;

133.        sschannel = ServerSocketChannel.open(); // 打开通道

134.        socket = sschannel.socket(); //得到与通到相关的socket对象

135.        socket.bind(new InetSocketAddress(port)); //将scoket榜定在制定的端口上

136.        //配置通到使用非阻塞模式,在非阻塞模式下,可以编写多道程序同时避免使用复杂的多线程

137.        sschannel.configureBlocking(false);

138.        sschannel.register(selector, SelectionKey.OP_ACCEPT);

139.        try {

140.            while(true) {

141.     // 与通常的程序不同,这里使用channel.accpet()接受客户端连接请求,而不是在socket对象上调用accept(),这里在调用accept()方法时如果通道配置为非阻塞模式,那么accept()方法立即返回null,并不阻塞

142.                this.selector.select();

143.                //if (selector.select(1000) == 0) { 

144.                // System.out.print("."); 

145.                // continue; 

146.                //} 

147.

148.                Iterator iter = this.selector.selectedKeys().iterator();

149.                while(iter.hasNext()) {

150.                    SelectionKey key = (SelectionKey)iter.next();

151.                    iter.remove();

152.                    this.handleKey(key);

153.                }

154.

155.            }

156.

157.        }

158.

159.        catch(IOException ex) {

160.            ex.printStackTrace();

161.        }

162.

163.    }

164.

165.    public static void main(String[] args) throws IOException {

166.        System.out.println("服务器启动");

167.        SelectorServer server = new SelectorServer(SelectorServer.DEFAULT_SERVERPORT);

168.        server.listen(); //服务器开始监听端口,提供服务

169.    }

170.

171.

172.

173.}


分享到:
评论

相关推荐

    Java NIO英文高清原版

    Java NIO,全称为Non-Blocking Input/Output(非阻塞输入/输出),是Java平台中用于替代标准I/O(BIO)模型的一种新机制。NIO在Java 1.4版本引入,提供了更高效的数据处理和通道通信方式,特别适用于高并发、大数据...

    java nio 包读取超大数据文件

    ### Java NIO 处理超大数据文件的知识点详解 #### 一、Java NIO简介 Java NIO(New IO)是Java平台上的新输入/输出流API,它提供了与传统IO(即Java IO)不同的数据处理方式。NIO在Java 1.4版本引入,并在后续版本...

    java NIO.zip

    Java NIO,全称为Non-Blocking Input/Output(非阻塞输入/输出),是Java标准库提供的一种替代传统的I/O模型的新技术。自Java 1.4版本引入NIO后,它为Java开发者提供了更高效的数据传输方式,尤其是在处理大量并发...

    基于nio实现的多文件上传源码

    在Java编程领域,NIO(New IO)是一个重要的特性,它是Java 1.4版本引入的,用于替代标准的IO API。NIO提供了一种非阻塞I/O操作的方式,特别适用于处理大量的并发连接,例如在文件传输、网络通信等场景。本主题...

    基于nio的简易聊天室

    在Java编程领域,NIO(New Input/Output)是一个重要的概念,它提供了非阻塞I/O操作的能力,相比传统的BIO(Blocking I/O),在处理大量并发连接时表现出更高的效率和性能。本项目"基于nio的简易聊天室"旨在通过NIO...

    xnio-nio-3.8.0.Final-API文档-中文版.zip

    赠送jar包:xnio-nio-3.8.0.Final.jar; 赠送原API文档:xnio-nio-3.8.0.Final-javadoc.jar; 赠送源代码:xnio-nio-3.8.0.Final-sources.jar; 赠送Maven依赖信息文件:xnio-nio-3.8.0.Final.pom; 包含翻译后的API...

    httpcore-nio-4.3.jar包

    它基于Java NIO API,利用其非阻塞I/O特性,可以同时处理大量连接,尤其适合于高并发的网络环境。HttpCore NIO 4.3版是对该框架的进一步优化和完善,增强了对HTTP/1.1协议的支持,同时保持了良好的兼容性和稳定性。 ...

    《NIO与Socket编程技术指南》_高洪岩

    《NIO与Socket编程技术指南》是一本深入探讨Java NIO(New Input/Output)和Socket编程的专业书籍,由高洪岩撰写。本书主要针对Java开发者,旨在帮助他们理解和掌握这两种在开发网络应用中至关重要的技术。 Java ...

    java NIO详细教程

    ### Java NIO 详细教程知识点解析 #### 一、Java NIO 概述 Java NIO(New IO)是Java平台提供的一种新的IO操作模式,它首次出现在Java 1.4版本中,并在后续版本中不断完善。Java NIO 的设计目的是为了克服传统Java ...

    NIO 入门.chm,NIO 入门.chm

    **NIO(New Input/Output)是Java编程语言中用于替代标准I/O(BIO,Blocking I/O)的一组API,它提供了非阻塞式的I/O操作方式,极大地提升了Java在处理I/O密集型应用时的性能。NIO在Java 1.4版本中被引入,之后在...

    基于Spring Boot + NIO实现的电商平台见证宝服务

    本项目"基于Spring Boot + NIO实现的电商平台见证宝服务"旨在利用Spring Boot的便捷性与NIO(非阻塞I/O)的效率,来打造一个高效、稳定且可扩展的服务。下面将详细阐述其中涉及的关键技术点。 首先,Spring Boot是...

    基于java的BIO、NIO、AIO通讯模型代码实现

    Java作为一门广泛使用的开发语言,提供了多种I/O(Input/Output)通信模型,包括传统的阻塞I/O(BIO)、非阻塞I/O(NIO)以及异步I/O(AIO)。这些通信模型在不同的场景下有着各自的优势,理解和掌握它们对于优化...

    JAVA NIO 按行读取大文件,支持 GB级别

    设计思想: 每次通过nio读取字节到 fbb中 然后对fbb自己中的内容进行行判断即 10 回车 13 行号 0 文件结束 这样字节的判断,然后 返回行 如果 到达 fbb的结尾 还没有结束,就再通过nio读取一段字节,继续处理...

    javaNiO.doc

    ### Java NIO (New IO) 详解 #### 1. 引言 在Java的世界里,I/O(Input/Output)操作是程序与外部环境进行交互的重要方式之一。随着技术的发展,传统I/O模型逐渐显露出一些局限性,特别是在处理高并发场景下,其...

    JAVA-NIO-DEMO

    Java NIO(New IO)是Java 1.4版本引入的一个新模块,它提供了一种不同于传统IO(基于字节流和字符流)的I/O操作方式。传统的IO模型是阻塞式的,而NIO的核心特点是非阻塞,这使得在处理大量并发I/O请求时更为高效。...

    httpcore-nio-4.4.6-API文档-中文版.zip

    赠送jar包:httpcore-nio-4.4.6.jar 赠送原API文档:httpcore-nio-4.4.6-javadoc.jar 赠送源代码:httpcore-nio-4.4.6-sources.jar 包含翻译后的API文档:httpcore-nio-4.4.6-javadoc-API文档-中文(简体)版.zip ...

    Java NIO实现多个客户端之间的消息互发,客户端与服务器完整代码

    Java NIO(Non-blocking Input/Output)是一种在Java中处理I/O操作的新方式,相比于传统的BIO(Blocking I/O),NIO提供了更高效的数据传输能力,尤其适合于高并发、低延迟的网络应用,如聊天服务器。在这个场景下,...

Global site tag (gtag.js) - Google Analytics