- 浏览: 305805 次
- 性别:
- 来自: 北京
文章分类
- 全部博客 (165)
- hadoop (47)
- linux (11)
- nutch (7)
- hbase (7)
- solr (4)
- zookeeper (4)
- J2EE (1)
- jquery (3)
- java (17)
- mysql (14)
- perl (2)
- compass (4)
- suse (2)
- memcache (1)
- as (1)
- roller (1)
- web (7)
- MongoDB (8)
- struts2 (3)
- lucene (2)
- 算法 (4)
- 中文分词 (3)
- hive (17)
- noIT (1)
- 中间件 (2)
- maven (2)
- sd (0)
- php (2)
- asdf (0)
- kerberos 安装 (1)
- git (1)
- osgi (1)
- impala (1)
- book (1)
- python 安装 科学计算包 (1)
最新评论
-
dandongsoft:
你写的不好用啊
solr 同义词搜索 -
黎明lm:
meifangzi 写道楼主真厉害 都分析源码了 用了很久. ...
hadoop 源码分析(二) jobClient 通过RPC 代理提交作业到JobTracker -
meifangzi:
楼主真厉害 都分析源码了
hadoop 源码分析(二) jobClient 通过RPC 代理提交作业到JobTracker -
zhdkn:
顶一个,最近也在学习设计模式,发现一个问题,如果老是看别人的博 ...
Java观察者模式(Observer)详解及应用 -
lvwenwen:
木南飘香 写道
高并发网站的架构
转自:http://yangguangfu.iteye.com/blog/774194
Java代码 晚上学习了下Java 的 NIO Socket编程,写了下面这个小程序,包括服务器端与客户端。实现的功能为客户端向服务器端发送随即数目的消息,服务器端一条一条的回应。消息内容保存在talks.properties文件中,内容为: Hi=Hi Bye=Bye 床前明月光=疑是地上霜 举头望明月=低头思故乡 少小离家老大回=乡音无改鬓毛衰 天王盖地虎=宝塔镇河妖 我是甲=我是乙 我是客户端=我是服务器 我是周星驰=我是周润发 客户端会随即发送“=”左边的消息,服务器端会回应客户端“=”右边的消息。如果客户端想断开连接,会向服务器发送一个"Bye",然后服务器会回应一个"Bye“。收到服务器端的"Bye"后,客户端会断开连接。 当然,java的properties文件不接受中文内容,你需要native2ascii一下。talks.properties 的实际文件内容为: Hi=Hi Bye=Bye \u5E8A\u524D\u660E\u6708\u5149=\u7591\u662F\u5730\u4E0A\u971C \u4E3E\u5934\u671B\u660E\u6708=\u4F4E\u5934\u601D\u6545\u4E61 \u5C11\u5C0F\u79BB\u5BB6\u8001\u5927\u56DE=\u4E61\u97F3\u65E0\u6539\u9B13\u6BDB\u8870 \u5929\u738B\u76D6\u5730\u864E=\u5B9D\u5854\u9547\u6CB3\u5996 \u6211\u662F\u7532=\u6211\u662F\u4E59 \u6211\u662F\u5BA2\u6237\u7AEF=\u6211\u662F\u670D\u52A1\u5668 \u6211\u662F\u5468\u661F\u9A70=\u6211\u662F\u5468\u6DA6\u53D1 看下服务器端的代码。此例中的服务器端只有一个主线程,用于selector操作,并处理多个客户端的消息。在常规的socket编程中,每个客户端都需要单独开一个线程,效率比较低。代码为: package helloweenpad; import java.io.FileInputStream; import java.net.InetSocketAddress; import java.net.Socket; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import java.nio.charset.CharsetEncoder; import java.util.Iterator; import java.util.Properties; public class MyFirstNIOServer { public static final int PORT = 12315; protected Selector selector; protected Charset charset = Charset.forName("UTF-8"); protected CharsetEncoder charsetEncoder = charset.newEncoder(); protected CharsetDecoder charsetDecoder = charset.newDecoder(); protected Properties talks = new Properties(); int clientCount; public MyFirstNIOServer() throws Exception { talks.load(new FileInputStream("E:\\talk.properties")); selector = Selector.open(); ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); serverSocketChannel.socket().bind(new InetSocketAddress(PORT)); // port serverSocketChannel.configureBlocking(false); serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);// register p("Server localhost:" + PORT + " started. waiting for clients. "); while (true) { // selector 线程。select() 会阻塞,直到有客户端连接,或者有消息读入 selector.select(); Iterator<SelectionKey> iterator = selector.selectedKeys().iterator(); while (iterator.hasNext()) { SelectionKey selectionKey = iterator.next(); iterator.remove(); // 删除此消息 // 并在当前线程内处理。(为了高效,一般会在另一个线程中处理此消息,例如使用线程池等) handleSelectionKey(selectionKey); } } } public void handleSelectionKey(SelectionKey selectionKey) throws Exception { if (selectionKey.isAcceptable()) { // 有客户端进来 clientCount++; ServerSocketChannel serverSocketChannel = (ServerSocketChannel) selectionKey.channel(); SocketChannel socketChannel = serverSocketChannel.accept(); socketChannel.configureBlocking(false); Socket socket = socketChannel.socket(); // 立即注册一个 OP_READ 的SelectionKey, 接收客户端的消息 SelectionKey key = socketChannel.register(selector, SelectionKey.OP_READ); key.attach("第 " + clientCount + " 个客户端 [" + socket.getRemoteSocketAddress() + "]: "); p(key.attachment() + "\t[connected] ========================================="); } else if (selectionKey.isReadable()) { // 有消息进来 ByteBuffer byteBuffer = ByteBuffer.allocate(100); SocketChannel socketChannel = (SocketChannel) selectionKey.channel(); try { int len = socketChannel.read(byteBuffer); // 如果len>0,表示有输入。如果len==0, 表示输入结束。需要关闭 socketChannel if (len > 0) { byteBuffer.flip(); String msg = charsetDecoder.decode(byteBuffer).toString(); // 根据客户端的消息,查找到对应的输出 String newMsg = talks.getProperty(msg); if (newMsg == null) newMsg = "Sorry? I don't understand your message. "; // UTF-8 格式输出到客户端,并输出一个'n' socketChannel.write(charsetEncoder.encode(CharBuffer.wrap(newMsg + "\n"))); p(selectionKey.attachment() + "\t[recieved]: " + msg + " ----->\t[send]: " + newMsg); } else { // 输入结束,关闭 socketChannel p(selectionKey.attachment() + "read finished. close socketChannel. "); socketChannel.close(); } } catch (Exception e) { // 如果read抛出异常,表示连接异常中断,需要关闭 socketChannel e.printStackTrace(); p(selectionKey.attachment() + "socket closed? "); socketChannel.close(); } } else if (selectionKey.isWritable()) { p(selectionKey.attachment() + "TODO: isWritable() ???????????????????????????? "); } else if (selectionKey.isConnectable()) { p(selectionKey.attachment() + "TODO: isConnectable() ????????????????????????? "); } else { p(selectionKey.attachment() + "TODO: else. "); } } public static void p(Object object) { System.out.println(object); } public static void main(String[] args) throws Exception { new MyFirstNIOServer(); } } 再看下客户端代码。这个客户端使用了常规的socket编程,没有使用NIO。是否使用NIO对另一方是透明的,对方看不见,也不关心。无论使用NIO还是使用常规socket,效果都是一样的,只是NIO的效率要高一些。代码为: package helloweenpad; import java.io.BufferedReader; import java.io.FileInputStream; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.Socket; import java.util.Properties; import java.util.Random; public class MyFirstNIOClientTest extends Thread { public static final String HOST = "localhost"; public static final int PORT = 12315; boolean exist = false; Properties talks = new Properties(); Random random = new Random(); String[] keys; int messageCount = 0; public void run() { try { // 对话内容 talks.load(new FileInputStream("E:\\talk.properties")); // 客户端发送 "=" 左边的内容 keys = new String[talks.size()]; talks.keySet().toArray(keys); Socket socket = new Socket(HOST, PORT); OutputStream ous = socket.getOutputStream(); InputStream ins = socket.getInputStream(); // 接收线程,接收服务器的回应 RecieverThread reciever = new RecieverThread(ins); reciever.start(); while (!exist) { messageCount++; // 选择一个随机消息 String msg = chooseMessage(); synchronized (ins) { // 发送给服务器端 ous.write(msg.getBytes("UTF-8")); System.out.println("[send]\t" + messageCount + ": " + msg); // 然后等待接收线程 ins.wait(); } if (msg.equals("Bye")) { break; } } ins.close(); ous.close(); socket.close(); } catch (Exception e) { e.printStackTrace(); } } public String chooseMessage() { int index = random.nextInt(keys.length); String msg = keys[index]; // 如果 10 次就选中 Bye,则重新选择,为了使对话内容多一些 if (messageCount < 10 && msg.equalsIgnoreCase("Bye")) { return chooseMessage(); } return msg; } // 接收线程 class RecieverThread extends Thread { private InputStream ins; public RecieverThread(InputStream ins) { this.ins = ins; } @Override public void run() { try { String line = null; BufferedReader r = new BufferedReader(new InputStreamReader( ins, "UTF-8")); // readLine()会阻塞,直到服务器输出一个 '\n' while ((line = r.readLine()) != null) { System.out.println("[Recieved]: " + line); synchronized (ins) { // 接收到服务器的消息,通知下主线程 ins.notify(); } if (line.trim().equals("Bye")) { exist = true; break; } } } catch (Exception e) { e.printStackTrace(); } } } public static void main(String[] args) throws Exception { // 开三个客户端线程 for (int i = 0; i < 3; i++) { try { new MyFirstNIOClientTest().start(); } catch (Exception e) { e.printStackTrace(); } } } } ============================================================================= 服务器端的输出: Server localhost:12315 started. waiting for clients. 第 1 个客户端 [/127.0.0.1:1890]: [connected] ========================================= 第 2 个客户端 [/127.0.0.1:1865]: [connected] ========================================= 第 3 个客户端 [/127.0.0.1:1866]: [connected] ========================================= 第 2 个客户端 [/127.0.0.1:1865]: [recieved]: 床前明月光 -----> [send]: 疑是地上霜 第 3 个客户端 [/127.0.0.1:1866]: [recieved]: 我是周星驰 -----> [send]: 我是周润发 第 1 个客户端 [/127.0.0.1:1890]: [recieved]: 少小离家老大回 -----> [send]: 乡音无改鬓毛衰 第 1 个客户端 [/127.0.0.1:1890]: [recieved]: 床前明月光 -----> [send]: 疑是地上霜 第 1 个客户端 [/127.0.0.1:1890]: [recieved]: 我是客户端 -----> [send]: 我是服务器 第 3 个客户端 [/127.0.0.1:1866]: [recieved]: 举头望明月 -----> [send]: 低头思故乡 第 3 个客户端 [/127.0.0.1:1866]: [recieved]: 床前明月光 -----> [send]: 疑是地上霜 第 2 个客户端 [/127.0.0.1:1865]: [recieved]: 举头望明月 -----> [send]: 低头思故乡 第 1 个客户端 [/127.0.0.1:1890]: [recieved]: 我是甲 -----> [send]: 我是乙 第 1 个客户端 [/127.0.0.1:1890]: [recieved]: 我是周星驰 -----> [send]: 我是周润发 第 3 个客户端 [/127.0.0.1:1866]: [recieved]: 举头望明月 -----> [send]: 低头思故乡 第 2 个客户端 [/127.0.0.1:1865]: [recieved]: 床前明月光 -----> [send]: 疑是地上霜 第 1 个客户端 [/127.0.0.1:1890]: [recieved]: 床前明月光 -----> [send]: 疑是地上霜 第 3 个客户端 [/127.0.0.1:1866]: [recieved]: 床前明月光 -----> [send]: 疑是地上霜 第 2 个客户端 [/127.0.0.1:1865]: [recieved]: Hi -----> [send]: Hi 第 2 个客户端 [/127.0.0.1:1865]: [recieved]: 举头望明月 -----> [send]: 低头思故乡 第 2 个客户端 [/127.0.0.1:1865]: [recieved]: 举头望明月 -----> [send]: 低头思故乡 第 2 个客户端 [/127.0.0.1:1865]: [recieved]: 少小离家老大回 -----> [send]: 乡音无改鬓毛衰 第 3 个客户端 [/127.0.0.1:1866]: [recieved]: 我是甲 -----> [send]: 我是乙 第 2 个客户端 [/127.0.0.1:1865]: [recieved]: 床前明月光 -----> [send]: 疑是地上霜 第 1 个客户端 [/127.0.0.1:1890]: [recieved]: 我是客户端 -----> [send]: 我是服务器 第 2 个客户端 [/127.0.0.1:1865]: [recieved]: Hi -----> [send]: Hi 第 3 个客户端 [/127.0.0.1:1866]: [recieved]: Hi -----> [send]: Hi 第 2 个客户端 [/127.0.0.1:1865]: [recieved]: 我是周星驰 -----> [send]: 我是周润发 第 1 个客户端 [/127.0.0.1:1890]: [recieved]: 我是周星驰 -----> [send]: 我是周润发 第 3 个客户端 [/127.0.0.1:1866]: [recieved]: 举头望明月 -----> [send]: 低头思故乡 第 2 个客户端 [/127.0.0.1:1865]: [recieved]: Bye -----> [send]: Bye 第 1 个客户端 [/127.0.0.1:1890]: [recieved]: Hi -----> [send]: Hi 第 2 个客户端 [/127.0.0.1:1865]: read finished. close socketChannel. 第 1 个客户端 [/127.0.0.1:1890]: [recieved]: Bye -----> [send]: Bye 第 3 个客户端 [/127.0.0.1:1866]: [recieved]: 我是客户端 -----> [send]: 我是服务器 第 1 个客户端 [/127.0.0.1:1890]: read finished. close socketChannel. 第 3 个客户端 [/127.0.0.1:1866]: [recieved]: 我是客户端 -----> [send]: 我是服务器 第 3 个客户端 [/127.0.0.1:1866]: [recieved]: Bye -----> [send]: Bye 第 3 个客户端 [/127.0.0.1:1866]: read finished. close socketChannel. 客户端的输出: [send] 1: 我是周星驰 [send] 1: 少小离家老大回 [Recieved]: 乡音无改鬓毛衰 [send] 2: 床前明月光 [Recieved]: 疑是地上霜 [send] 3: 我是客户端 [Recieved]: 我是服务器 [Recieved]: 疑是地上霜 [Recieved]: 我是周润发 [Recieved]: 低头思故乡 [send] 2: 举头望明月 [Recieved]: 疑是地上霜 [send] 3: 床前明月光 [send] 1: 床前明月光 [send] 2: 举头望明月 [Recieved]: 低头思故乡 [Recieved]: 我是乙 [send] 4: 我是甲 [Recieved]: 我是周润发 [send] 5: 我是周星驰 [send] 3: 床前明月光 [send] 6: 床前明月光 [send] 4: 举头望明月 [Recieved]: 低头思故乡 [send] 5: 床前明月光 [Recieved]: 疑是地上霜 [Recieved]: 疑是地上霜 [Recieved]: 疑是地上霜 [Recieved]: Hi [send] 4: Hi [Recieved]: 低头思故乡 [send] 5: 举头望明月 [Recieved]: 低头思故乡 [Recieved]: 低头思故乡 [send] 6: 举头望明月 [send] 7: 少小离家老大回 [s
发表评论
-
博客地址变更
2013-08-16 10:29 1218all the guys of visiting the bl ... -
java 中object 方法
2012-11-02 07:39 1588Java中Object的方法 构造方法摘要 Object() ... -
java 容易引起内存泄漏的几大原因
2012-02-14 16:01 1776容易引起内存泄漏的几 ... -
jvm 调优2
2012-02-09 17:37 55B-树 是一种多路搜索树(并不是二叉的): 1 ... -
java 反射机制
2012-02-09 11:24 1084JAVA反射机制的学习 JAVA语言中的反射机制: ... -
JVM学习笔记-方法区示例与常量池解析
2012-01-30 09:36 1470JVM学习笔记-方法区示例与常量池解析(Method Area ... -
JVM调优 (2)
2012-01-13 14:00 869JVM调优 1. Heap设定与垃圾回收 J ... -
jvm 启动参数
2012-01-13 13:58 972转载自:http://www.blogjava ... -
Java虚拟机(JVM)参数简介
2012-01-13 13:14 1289Java虚拟机(JVM)参数简介 在Java、J2EE大型 ... -
Java 哈夫曼编码反编码的实现
2011-12-23 09:52 1316Java 哈夫曼编码反编码 ... -
离线并发与锁机制
2011-12-15 15:47 908离线并发与锁机制 离线并发的来源 在W ... -
Java观察者模式(Observer)详解及应用
2011-12-14 11:19 4839Java观察者模式(Observer)详解及应用 由于网站 ... -
解决zookeeper linux下无法启动的问题
2011-12-05 14:20 4765在linux下安装zookeeper时,出现了如下的错误: ... -
使用Java NIO编写高性能的服务器
2011-12-04 17:28 1127使用Java NIO编写高性能的服务器 从JDK 1.5开 ... -
jvm 参数设置
2011-10-18 16:01 1132jvm 参数设置 /usr/local/jdk/bin/ja ... -
eclipse 成功发布工程 但访问不到项目
2011-09-29 17:48 1362前提: 将其他的 工程 copy 一份修改了名字 在eclip ... -
java 生成 静态html
2011-09-15 15:43 1579java 生成html 网上的大部分资料都是 用 ##tit ...
相关推荐
java NIO和java并发编程的书籍java NIO和java并发编程的书籍java NIO和java并发编程的书籍java NIO和java并发编程的书籍java NIO和java并发编程的书籍java NIO和java并发编程的书籍java NIO和java并发编程的书籍java...
标题“nio.rar_NIO_NIO-socket_java nio_java 实例_java.nio”表明这个压缩包包含了一个关于Java NIO的实例,特别是关于NIO套接字(Socket)的编程示例。NIO套接字是Java NIO库中用于网络通信的关键组件,它们允许...
### Java网络编程NIO视频教程知识点汇总 #### 1. Java NIO-课程简介 - **主要内容**:简述...通过以上内容的学习,开发者可以全面掌握Java NIO编程的相关技术和最佳实践,为开发高性能网络应用程序打下坚实的基础。
Java NIO,全称为Non-Blocking Input/Output(非阻塞输入/输出),是Java平台中用于替代标准I/O(BIO)模型的一种新机制。...学习和理解Java NIO以及Netty的使用,对于提升Java网络编程的能力至关重要。
8. Java NIO编程要点: - 使用Channel进行数据的传输。 - 使用Buffer暂存数据,Channel与Buffer之间的数据交换是单向的。 - 使用Selector来处理多个通道的事件,实现单线程管理多个连接。 - 对于文件操作,使用...
**JAVA-NIO程序设计完整实例** Java NIO(New IO)是Java 1.4引入的一个新特性,它为Java提供了非阻塞I/O操作的能力,使得Java在处理I/O时更加高效。NIO与传统的BIO(Blocking I/O)模型相比,其核心在于它允许程序...
在实际开发中,我们通常会使用一些NIO框架来简化编程,例如: 1. **Netty**:是一个高性能、异步事件驱动的网络应用框架,常用于创建服务器和客户端的TCP、UDP通信。 2. **Grizzly**:是Sun Microsystems(现Oracle...
Java NIO(非阻塞I/O)编程是Java平台中的一种高效处理I/O操作的方式,尤其是在高并发和大...这本书可能还会涵盖实际案例和最佳实践,帮助开发者提升Java NIO编程技能,从而在实际工作中实现更高的系统性能和可扩展性。
NIO在Java 1.4版本引入,其设计目标是提供一种更高效、更灵活的I/O操作方式,特别适合处理大量并发连接的场景,如服务器端编程。在NIO中,我们不再像BIO那样等待一个操作完成,而是通过选择器(Selector)监控多个...
在Java 1.4版本中引入,NIO提供了一种全新的I/O编程方式,使得Java开发者能够更高效地处理I/O操作,特别是在处理大量并发连接时,性能提升尤为显著。本篇文章将深入探讨Java NIO的基本概念、核心组件以及实际应用。 ...
**传统阻塞I/O模型**:在传统的Java IO编程中,当我们调用`read()`或`write()`方法时,如果当前没有数据可读或写,那么这些方法将会阻塞,直到有数据可用或者写操作完成。这种阻塞机制会导致大量的线程被占用,从而...
在实际应用中,Java NIO通常用于高性能的服务器编程,例如在开发聊天服务器、Web服务器或游戏服务器时,可以利用其高效的并发处理能力。然而,NIO的API相对复杂,学习曲线较陡峭,需要花费一定时间去理解和实践。...
在“AsynIOModule”这个压缩包中,可能包含了关于Java NIO和AIO编程的相关示例代码和文档,这些资源可以帮助开发者深入理解和实践这两种异步I/O机制,提升他们在Java网络编程中的技能。通过研究这些代码和文档,...
总的来说,Java NIO提供了一种更高效、灵活的方式来处理文件读取和其他I/O操作,尤其适合需要处理大量并发I/O请求的场合,例如服务器端编程。通过熟练掌握NIO,开发者可以构建出更加高效的Java应用程序。