JAVA NIO的实例.docx
《JAVA NIO的实例.docx》由会员分享,可在线阅读,更多相关《JAVA NIO的实例.docx(16页珍藏版)》请在冰豆网上搜索。
JAVANIO的实例
JAVANIO的实例
分类:
java应用2010-07-1921:
29525人阅读评论(0)收藏举报
JAVANIO的实例
1:
JAVANIO简介
JavaNIO非堵塞技术实际是采取Reactor模式,或者说是Observer模式为我们监察I/O端口,假如有内容进来,会自动通知我们,这样,我们就不必开启多个线程死等,从外界看,实现了流畅的I/O读写,不堵塞了。
NIO有一个主要的类Selector,这个类似一个观察者,只要我们把需要探知的socketchannel告诉Selector,我们接着做别的事情,当有事件发生时,他会通知我们,传回一组SelectionKey,我们读取这些Key,就会获得我们刚刚注册过的socketchannel,然后,我们从这个Channel中读取数据,放心,包准能够读到,接着我们可以处理这些数据。
Selector内部原理实际是在做一个对所注册的channel的轮询访问,不断的轮询(目前就这一个算法),一旦轮询到一个channel有所注册的事情发生,比如数据来了,他就会站起来报告,交出一把钥匙,让我们通过这把钥匙来读取这个channel的内容。
2:
服务器端:
SumServer.java类
[java]viewplaincopyprint?
1.package nio;
2.import java.io.IOException;
3.import .InetSocketAddress;
4.import .Socket;
5.import java.nio.ByteBuffer;
6.import java.nio.IntBuffer;
7.import java.nio.channels.SelectionKey;
8.import java.nio.channels.Selector;
9.import java.nio.channels.ServerSocketChannel;
10.import java.nio.channels.SocketChannel;
11.import java.nio.channels.spi.SelectorProvider;
12.import java.util.Iterator;
13.import java.util.Set;
14./**
15. * SumServer.java
16. *
17. *
18. * Created:
Thu Nov 06 11:
41:
52 2003
19. *
20. * @author starchu1981
21. * @version 1.0
22. */
23.public class SumServer {
24. private ByteBuffer _buffer = ByteBuffer.allocate(8);
25. private IntBuffer _intBuffer = _buffer.asIntBuffer();
26. private SocketChannel _clientChannel = null;
27. private ServerSocketChannel _serverChannel = null;
28. public void start() {
29. try {
30. openChannel();
31. waitForConnection();
32. } catch (IOException e) {
33. System.err.println(e.toString());
34. }
35. }
36. private void openChannel() throws IOException {
37. _serverChannel = ServerSocketChannel.open();
38. _serverChannel.socket().bind(new InetSocketAddress(10001));
39. _serverChannel.configureBlocking(false);// 设置为非阻塞形式
40. System.out.println("服务器通道已经打开");
41. }
42. /*
43. * private void waitForConnection() throws IOException { while (true) {
44. * _clientChannel = _serverChannel.accept(); if (_clientChannel !
= null) {
45. * System.out.println("新的连接加入"); processRequest(); _clientChannel.close(); } } }
46. */
47. private void waitForConnection() throws IOException {
48. Selector acceptSelector = SelectorProvider.provider().openSelector();
49. /*
50. * 在服务器套接字上注册selector并设置为接受accept方法的通知。
51. * 这就告诉Selector,套接字想要在accept操作发生时被放在ready表 上,因此,允许多元非阻塞I/O发生。
52. */
53. SelectionKey acceptKey = _serverChannel.register(acceptSelector,
54. SelectionKey.OP_ACCEPT);
55. int keysAdded = 0;
56. /* select方法在任何上面注册了的操作发生时返回 */
57. while ((keysAdded = acceptSelector.select()) > 0) {
58. // 某客户已经准备好可以进行I/O操作了,获取其ready键集合
59. Set readyKeys = acceptSelector.selectedKeys();
60. Iterator i = readyKeys.iterator();
61. // 遍历ready键集合,并处理加法请求
62. while (i.hasNext()) {
63. SelectionKey sk = (SelectionKey) i.next();
64. i.remove();
65. if (sk.isAcceptable()) {
66. ServerSocketChannel nextReady = (ServerSocketChannel) sk
67. .channel();
68. // 接受加法请求并处理它
69. _clientChannel = nextReady.accept();
70. // Socket _clientSocket = _clientChannel.socket();
71. processRequest();
72. // _clientSocket.close();
73. }
74. }
75. }
76. }
77. private void processRequest() throws IOException {
78. _buffer.clear();
79. _clientChannel.read(_buffer);
80. int result = _intBuffer.get(0) + _intBuffer.get
(1);
81. _buffer.flip();
82. _buffer.clear();
83. _intBuffer.put(0, result);
84. _clientChannel.write(_buffer);
85. }
86. public static void main(String[] args) {
87. new SumServer().start();
88. }
89.} // SumServer
3:
客户端:
SumClient.java类
[java]viewplaincopyprint?
1.package nio;
2.import java.nio.ByteBuffer;
3.import java.nio.IntBuffer;
4.import java.nio.channels.SocketChannel;
5.import .InetSocketAddress;
6.import java.io.IOException;
7./**
8. * SumClient.java
9. *
10. *
11. * Created:
Thu Nov 06 11:
26:
06 2003
12. *
13. * @author starchu1981
14. * @version 1.0
15. */
16.public class SumClient {
17. private ByteBuffer _buffer = ByteBuffer.allocate(8);
18. private IntBuffer _intBuffer;
19. private SocketChannel _channel;
20. public SumClient() {
21. _intBuffer = _buffer.asIntBuffer();
22. } // SumClient constructor
23. public int getSum(int first, int second) {
24. int result = 0;
25. try {
26. _channel = connect();
27. sendSumRequest(first, second);
28. result = receiveResponse();
29. } catch (IOException e) {
30. System.err.println(e.toString());
31. } finally {
32. if (_channel !
= null) {
33. try {
34. _channel.close();
35. } catch (IOException e) {
36. }
37. }
38. }
39. return result;
40. }
41. private SocketChannel connect() throws IOException {
42. InetSocketAddress socketAddress = new InetSocketAddress("localhost",
43. 10001);
44. return SocketChannel.open(socketAddress);
45. }
46. private void sendSumRequest(int first, int second) throws IOException {
47. _buffer.clear();
48. _intBuffer.put(0, first);
49. _intBuffer.put(1, second);
50. _channel.write(_buffer);
51. System.out.println("发送加法请求 " + first + "+" + second);
52. }
53. private int receiveResponse() throws IOException {
54. _buffer.clear();
55. _channel.read(_buffer);
56. return _intBuffer.get(0);
57. }
58. public static void main(String[] args) {
59. SumClient sumClient = new SumClient();
60. System.out.println("加法结果为 :
" + sumClient.getSum(100, 324));
61. }
62.} // SumClient
JAVANIO MappedByteBuffer共享内存
JavaNIO应用—使用内存映射文件实现进程间通信
March19,2010—Unmi
一看到JavaNIO的内存映射文件(MappedByteBuffer),让我立即就联想到Windows系统的内存映射文件。
Windows系统的内存映射文件能用来在多个进程间共享数据,即进程间的共享内存,是通过把同一块内存区域映射到不同进程的地址空间中,从而达到共享内存。
JavaNIO的内存映射文件和Windows系统下的一样,都能把物理文件的内容映射到内存中,那么MappedByteBuffer是否能用来在不同Java进程(JVM)间共享数据呢?
答案是肯定的,这样在通常的Socket方式来实现Java进程间通信之上又多了一种方法。
在Windows中内存映射文件可以是脱离物理文件而存在的一块命名的内存区域,使用相同的内存映射名就能在不同的进程中共享同一片内存。
然后,Java的MappedByteBuffer总是与某个物理文件相关的,因为不管你是从FileInputStream、FileOutputStream还是RandomAccessFile得来的FileChannel,再map()得到的内存映射文件MappedByteBuffer,如果在构造FileInputStream、FileOutputStream、RandomAccessFile对象时不指定物理文件便会有FileNotFoundException异常。
所以JavaNIO来实现共享内存的办法就是让不同进程的内存映射文件关联到同一个物理文件,因为MappedByteBuffer能让内存与文件即时的同步内容。
严格说来,称之为内存共享是不准确的,其实就是两个Java进程通过中间文件来交换数据,用中间文件使得两个进程的两块内存区域的内容得到及时的同步。
用图来理解JavaNIO的“共享内存”的实现原理:
知道了实现原理之后,下面用代码来演示两个进程间用内存映射文件来进行数据通信。
代码WriteShareMemory.java往映射文件中依次写入A、B、C…Z,ReadShareMemory.java逐个读出来,打印到屏幕上。
代码对交换文件swap.mm的第一个字节作了读写标志,分别是0-可读,1-正在写,2-可读。
RandomAccessFile得到的Channel能够灵活的进行读或写,并且不会破坏原有文件内容,而FileInputStream或FileOutputStream取得的Channel则很难达到这一功效,所以使用了RandomAccessFile来获得FileChannel。
WriteShareMemory.java
viewsource
print?
01
packagecom.unmi;
02
03
importjava.io.RandomAccessFile;
04
importjava.nio.MappedByteBuffer;
05
importjava.nio.channels.FileChannel;
06
importjava.nio.channels.FileChannel.MapMode;
07
08
/**
09
*往"共享内存"写入数据
10
*@authorUnmi
11
*/
12
publicclassWriteShareMemory{
13
14
/**
15
*@paramargs
16
*@throwsException
17
*/
18
publicstaticvoidmain(String[]args)throwsException{
19
RandomAccessFileraf=newRandomAccessFile("c:
/swap.mm","rw");
20
FileChannelfc=raf.getChannel();
21
MappedByteBuffermbb=fc.map(MapMode.READ_WRITE,0,1024);
22
23
//清除文件内容
24
for(inti=0;i<1024;i++){
25
mbb.put(i,(byte)0);
26
}
27
28
//从文件的第二个字节开始,依次写入A-Z字母,第一个字节指明了当前操作的位置
29
for(inti=65;i<91;i++){
30
intindex=i-63;
31
intflag=mbb.get(0);//可读标置第一个字节为0
32
if(flag!
=0){//不是可写标示0,则重复循环,等待
33
i--;
34
continue;
35
}
36
mbb.put(0,(byte)1);//正在写数据,标志第一个字节为1
37
mbb.put(1,(byte)(index));//写数据的位置
38
39
System.out.println("程序WriteShareMemory:
"+System.currentTimeMillis()+
40
":
位置:
"+index+"写入数据:
"+(char)i);
41
42
mbb.put(index,(byte)i);//index位置写入数据
43
mbb.put(0,(byte)2);//置可读数据标志第一个字节为2
44
Thread.sleep(513);
45
}
46
}
47
}
ReadShareMemory.java
viewsource
print?
01
pack