java.nio 网络编程 入门讲解_第1页
java.nio 网络编程 入门讲解_第2页
java.nio 网络编程 入门讲解_第3页
java.nio 网络编程 入门讲解_第4页
java.nio 网络编程 入门讲解_第5页
已阅读5页,还剩9页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

Java.NIO 网络编程 入门讲解 服务器:java 在服务器编程方面已经成就霸主地位,非其他语言能够比拟的 2。移动设备,java 与.net 有较量,因为大的手机场上不信任微软 3。桌面应用,java 不是.net 的对手(个人观点) 所以,如果你对 java 熟悉的程度越高,你的收入会越高,但使用的地方在中国会越少,所 以尽管有国外的很多软件开发者熟悉 java,但在中国依然有很多人说 java 没有用!我用. net 开发客户端的软件,java 开发服务器端! Java 的发展前景 Sun 公司以及 IBM、Oracle 、 Netscape 等公司都在大力推进 Java 的应用。旨在提高 Java 运 行速度的 Java 芯片也在紧锣密鼓地赶制当中,有人预计不久的将来, Java 的代码的运行速 度和 C+一样快。Java 在 WWW 应用中的地位得到肯定以后,Sun 又反过来扩展 Java 在家 电领域的应用,Java 的应用有向更广阔的领域扩展的趋势。 Sun 公司的高层人士称“Java 的潜力远远超过作为编程语言带来的好处。事实上,Java 是一种新计算模式的使能技术” 。 看来,Java 的前程不可限量。 Java 主要是用在服务器端的 Middle Tier 的编程上。随着 JDK-1.4 的普及,这样的时代也许已 经成为历史,可以宣告结束了。让我们一起来看看 Java 的新面貌。 自 JDK-1.4 开始的新 I/O(NIO)为 Java 程序员提供了新的高效率的 I/O 能力。效率的提高主 要来源于一个新的内存共享技术。传统上,Java 内存来自 JVM 的堆,Native code(JNI)不能很 好的与 Java code 共享这些 Java 内存,因为 Native code 对这些 Java 内存的访问和使用受到很 多的限制。JDK-1.2 对此略有改进,提供给 Native code 一点比较好的控制 Java 内存的能力, 但是并没有从根本上解决问题。JDK-1.4 提供了一个特殊的包装技术,使得任何一块系统内 存在经过包装之后可以很好地被 Native 与 Java code 共享。这些系统内存可以是 JVM 的堆 以外的,甚至是 JVM 之外的内存,例如 video memory,device controller memory,等等。这意味 着,Java 的 I/O 效率已经达到了与 C 相似的境界。换句话说 ,我们终于可以用纯 Java 来编写 复杂的,实时(real-time)的,3D,交互式的高级应用程序了。 Full-Screen Exclusive Mode 也是 JDK-1.4 新增的功能。熟悉微软的 DirectX 的程序员也许早 已通晓 Full-Screen Exclusive Mode,但对 Java 程序员来讲也许是个新的概念。Full-Screen Exclusive Mode 允许程序员暂停并跳过窗口系统的画图操作流程而直接对屏幕进行画图操 作。也就是说,程序不应再等待 PAINT EVENT 来执行 paint 方法,而是要主动地,直接在屏幕 上,执行画图操作了。这个技术应用在高效率作图以及游戏程序中。在有些平台上, 一些先 进的技术例如 Page Flipping, Stereo Buffering 等等,必须在 Full-Screen Exclusive Mode 下才可 以使用。 现代应用程序越来越多地在用户界面上使用优美的图像。Java2D 早已为我们提供了丰富多 彩的高级图形和图像处理功能。JDK-1.4 不但提高了它的效率,又为它改进和新增了很多重 要的功能,例如 New Pipeline Architecture, Pluggable Image I/O Framework, Hardware Acceleration for Offscreen Images, New Java Print Service, Complete Porter-Duff Support,等等。 这使得 Java2D 的能力更上一层楼。 Reflection 是一个极其重要的 Java 技术。它使得我们可以在 Runtime 时去发掘任何一个 Object 的定义,并且使用其定义。例如,在我们对某一个 O 一无所知的情况下,我们可以发现 O 是 C 的一个实例,还发现它有某个方法 M,我们可以执行这个 M。Reflection 是 JavaBean,Object Serialization 等等重要 Java 技术的基础,也是各种 Java 工具赖以生存的重要 技术。JDK-1.4 对 Reflection 的实现作了相当的改进,使得它的速度大大提高了数倍。这对 Java 整体性能的提高有着重要的意义。 其他一些重要的,也许已为大家所熟悉的新功能,例如 Logging API, AssertionFacility, Regular Expression, IPv6 Support, Preference API,XML Processing,JDBC 3.0, Unicode 3.0 等等,都为我 们展示了一幅美好的 Java 前景。 总而言之, Java 以它精湛优美的设计思想,出人意料的发展速度而受到举世瞩目,并创造了巨 额的财富和庞大的就业机会。JDK-1.4 宣告了 Java 主要用在服务器端的形象已经成为历史。 新的 Java 已经遨翔在更广阔的天地之间。 【聚杰网核心技术】用 java.nio.*进行网络编程 前言 因为打算用 java 编写异步通信的 server 和 client 程序,笔者便学习使用 java.nio 开发包,其间遇到一些问题,上网却发现网上对它的应用描述的不是很多。所以,笔者不 惜班门弄斧,做些简单的讨论,以便大家更进一步的讨论。 对相关类的简单介绍 java.nio.*, 据说它提供了一些更加底层的一些功能,如:类似 windows 环境下的 AsyncSocket 类的异步操作的功能,能显著降低 server 端程序的线程管理开销。 因为大多数应用是建立在 TCP 之上,所以在此只说说 SocketChannel, ServerSocketChannel,Selector 和 ByteBuffer 这几个类.前三个最终都源自 channel 类。而 channel 类,可以理解为在具体 I/O 或文件对象之上抽象的一个操作对象,我们通过操作 channel 的读写达到对其对应的文件或 I/O 对象(包括 socket)读写的目的。读写的内容在内 存中放在 ByteBuffer 类提供的缓冲区。总而言之,channel 作为一个桥梁,连接了 I/O 对象 和内存中的 ByteBuffer,实现了 I/O 的更高效的存取。 一个基于 TCP 的服务器端程序,必然有个侦听端和若干个通信端,它们在 nio 中由对 应的 ServerSocketChannel 和 SocketChannel 类来实现。为了达到异步 I/O 操作的目的,需 要 Selector 类,它能检测到 I/O 对象的状态。 SocketChannel 类是抽象类,通过调用它的静态函数 open(),可生成一个 SocketChannel 对象,该对象对应一个 .Socket,可通过 SocketChannel.socket()获得, 而其对应的 Socket 也可通过调用函数 getChannel()得到已建立的相应 SocketChannel。 SocketChannel 与它的 socket 是一一对应的。SocketChannel 的操作与 Socket 也很相似. ServerSocketChannel 也是通过调用它的静态函数 open()生成的,只是它不能 直接调用 bind()函数来绑定一个地址,需要它对应的 ServerSocket 来完成绑定工作,一般可 按如下步骤做: ServerSocketChannel ssc = new ServerSocketChannel.open(); ssc.socket().bind(InetSocketAddress(host,port); 罗嗦了半天,还是看看最简单的 C/S 实现吧,服务器提供了基本的回射(echo)功 能,其中提供了较详细的注释。 源码分析 1.服务器端: / /AsyncServer.java / by / import java.nio.channels.SocketChannel; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.ByteBuffer; import java.nio.channels.SelectableChannel; import java.nio.channels.spi.SelectorProvider; import .ServerSocket; import .Socket; import .InetSocketAddress; import .SocketAddress; import java.util.Iterator; import java.util.LinkedList; import java.io.IOException; class AsyncServer implements Runnable private ByteBuffer r_buff = ByteBuffer.allocate(1024); private ByteBuffer w_buff = ByteBuffer.allocate(1024); private static int port = 8848; public AsyncServer() new Thread(this).start(); public void run() try /生成一个侦听端 ServerSocketChannel ssc = ServerSocketChannel.open(); /将侦听端设为异步方式 ssc.configureBlocking(false); /生成一个信号监视器 Selector s = Selector.open(); /侦听端绑定到一个端口 ssc.socket().bind(new InetSocketAddress(port); /设置侦听端所选的异步信号 OP_ACCEPT ssc.register(s,SelectionKey.OP_ACCEPT); System.out.println(“echo server has been set up “); while(true) int n = s.select(); if (n = 0) /没有指定的 I/O 事件发生 continue; Iterator it = s.selectedKeys().iterator(); while (it.hasNext() SelectionKey key = (SelectionKey) it.next(); if (key.isAcceptable() /侦听端信号触发 ServerSocketChannel server = (ServerSocketChannel) key.channel(); /接受一个新的连接 SocketChannel sc = server.accept(); sc.configureBlocking(false); /设置该 socket 的异步信号 OP_READ:当 socket 可读时, /触发函数 DealwithData(); sc.register(s,SelectionKey.OP_READ); if (key.isReadable() /某 socket 可读信号 DealwithData(key); it.remove(); catch(Exception e) e.printStackTrace(); public void DealwithData(SelectionKey key) throws IOException int count; /由 key 获取指定 socketchannel 的引用 SocketChannel sc = (SocketChannel)key.channel(); r_buff.clear(); /读取数据到 r_buff while(count = sc.read(r_buff) 0) ; /确保 r_buff 可读 r_buff.flip(); w_buff.clear(); /将 r_buff 内容拷入 w_buff w_buff.put(r_buff); w_buff.flip(); /将数据返回给客户端 EchoToClient(sc); w_buff.clear(); r_buff.clear(); public void EchoToClient(SocketChannel sc) throws IOException while(w_buff.hasRemaining() sc.write(w_buff); public static void main(String args) if(args.length 0) port = Integer.parseInt(args0); new AsyncServer(); 在当前目录下运行: javac AsynServer.java 后,若无编译出错,接下来可运行: java AsynServer 或 java AsynServer (端口号) 上述服务程序在运行时,可指定其侦听端口,否则程序会取 8848 为默认端口。 2.客户端的简单示例: / /AsyncClient.java / by / import java.nio.channels.SocketChannel; import .InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.Selector; import java.nio.channels.SelectionKey; import java.io.IOException; import java.io.BufferedReader; import java.io.InputStreamReader; class AsyncClient private SocketChannel sc; private final int MAX_LENGTH = 1024; private ByteBuffer r_buff = ByteBuffer.allocate(MAX_LENGTH); private ByteBuffer w_buff = ByteBuffer.allocate(MAX_LENGTH); private static String host ; private static int port = 8848; public AsyncClient() try InetSocketAddress addr = new InetSocketAddress(host,port); /生成一个 socketchannel sc = SocketChannel.open(); /连接到 server sc.connect(addr); while(!sc.finishConnect() ; System.out.println(“connection has been established!.“); while(true) /回射消息 String echo; try System.err.println(“Enter msg youd like to send: “); BufferedReader br = new BufferedReader(new InputStreamReader(System.in); /输入回射消息 echo = br.readLine(); /把回射消息放入 w_buff 中 w_buff.clear(); w_buff.put(echo.getBytes(); w_buff.flip(); catch(IOException ioe) System.err.println(“sth. is wrong with br.readline() “); /发送消息 while(w_buff.hasRemaining() sc.write(w_buff); w_buff.clear(); /进入接收状态 Rec(); /间隔 1 秒 Thread.currentThread().sleep(1000); catch(IOException ioe) ioe.printStackTrace(); catch(InterruptedException ie) ie.printStackTrace(); 用 java.nio.*进行网络编程 / /读取 server 端发回的数据,并显示 public void Rec() throws IOException int count; r_buff.clear(); count=sc.read(r_buff); r_buff.flip(); byte temp = new byter_buff.limit(); r_buff.get(temp); System.out.println(“reply is “ + count +“ long, and content is: “ + new String(temp); public static void main(String args) if(args.length 1) host = args0; port = Integer.parseInt(args1); new AsyncClient(); 在当前目录下运行: javac AsynClient.java 后,若无编译出错,确认 AsyncServer 已经运行的情况下,接下来可运行: java AsynClient hostname 或 java AsynClient hostname (端口号) 并按提示进行操作即可。 总结 总的来说,用 nio 进行网络编程还是很有新意的,服务器端软件能在一个线程中维护 与众多客户端的通信连接。笔者在本文中试图用一个典型的回射例子说明如何用 nio 建立 最基本的 C/S 应用。希望大家能试着用用它。 另外,笔者在实践中也发现 nio 在应用中存在的一些难题,比如如何应用 SocketChannel 的继承类,以及如何在 socketchannel 之上应用 SSL(Secure Socket Layer) 等等,因而希望这篇文章只是抛砖引玉,引起大家对 nio 作进一步的讨论。 在当前目录下运行: javac AsynServer.java 后,若无编译出错,接下来可运行: java AsynServer 或 java AsynServer (端口号) 上述服务程序在运行时,可指定其侦听端口,否则程序会取 8848 为默认端口。 2.客户端的简单示例: / /AsyncClient.java / by / import java.nio.channels.SocketChannel; import .InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.Selector; import java.nio.channels.SelectionKey; import java.io.IOException; import java.io.BufferedReader; import java.io.InputStreamReader; class AsyncClient private SocketChannel sc; private final int MAX_LENGTH = 1024; private ByteBuffer r_buff = ByteBuffer.allocate(MAX_LENGTH); private ByteBuffer w_buff = ByteBuffer.allocate(MAX_LENGTH); private static String host ; private static int port = 8848; public AsyncClient() try InetSocketAddress addr = new InetSocketAddress(host,port); /生成一个 socketchannel sc = SocketChannel.open(); /连接到 server sc.connect(addr); while(!sc.finishConnect() ; System.out.println(“connection has been established!.“); while(true) /回射消息 String echo; try System.err.println(“Enter msg youd like to send: “); BufferedReader br = new BufferedReader(new InputStreamReader(System.in); /输入回射消息 echo = br.readLine(); /把回射消息放入 w_buff 中 w_buff.clear(); w_buff.put(echo.getBytes(); w_buff.flip(); catch(IOException ioe) System.err.println(“sth. is wrong with br.readline() “); /发送消息 while(w_buff.hasRemaining() sc.write(w_buff); w_buff.clear(); /进入接收状态 Rec(); /间隔 1 秒 Thread.currentThread().sleep(1000); catch(IOException ioe) ioe.printStackTrace(); catch(InterruptedException ie) ie.printStackTrace(); / / 读取 server 端发回的数据,并显示 public void Rec() throws IOException int count; r_buff.clear(); while(count=sc.read(r_buff)0) ; r_buff.flip(); byte temp = new byter_buff.limit(); System.out.println(“reply is : “ + new String(temp); public static void main(String args) if(args.length 1) host = args0; port = Integer.parseInt(args1); new AsyncClient(); 在当前目录下运行: javac AsynClient.java 后,若无编译出错,确认 AsyncServer 已经运行的情况下,接下来可运行: java AsynClient hostname 或 java AsynClient hostname (端口号) 并按提示进行操作即可。 总结 总的来说,用 nio 进行网络编程还是很有新意的,服务器端软件能在一个线程中维护 与众多客户端的通信连接。笔者在本文中试图用一个典型的回射例子说明如何用 nio 建立 最基本的 C/S 应用。希望大家能试着用用它。 另外,笔者在实践中也发现 nio 在应用中存在的一些难题,比如如何应用 SocketChannel 的继承类,以及如何在 socketchannel 之上应用 SSL(Secure Socket Layer) 等等,因而希望这篇文章只是抛砖引玉,引起大家对 nio 作进一步的讨论。 在 JDK 1.4 以前,Java 的 IO 操作集中在 java.io 这个包中,是基于流的同步(blocking) API。对于大多数应用来说,这样的 API 使用很方便,然而,一些对性能要求较高的应用, 尤其是服务端应用,往往需要一个更为有效的方式来处理 IO。从 JDK 1.4 起,NIO API 作 为一个基于缓冲区,并能提供异步(non-blocking)IO 操作的 API 被引入。本文对其进行深入 的介绍。 NIO API 主要集中在 java.nio 和它的 subpackages 中: java.nio 定义了 Buffer 及其数据类型相关的子类。其中被 java.nio.channels 中的类用来进行 IO 操作 的 ByteBuffer 的作用非常重要。 java.nio.channels 定义了一系列处理 IO 的 Channel 接口以及这些接口在文件系统和网络通讯上的实现。通过 Selector 这个类,还提供了进行异步 IO 操作的办法。这个包可以说是 NIO API 的核心。 java.nio.channels.spi 定义了可用来实现 channel 和 selector API 的抽象类。 java.nio.charset 定义了处理字符编码和解码的类。 java.nio.charset.spi 定义了可用来实现 charset API 的抽象类。 java.nio.channels.spi 和 java.nio.charset.spi 这两个包主要被用来对现有 NIO API 进行扩展, 在实际的使用中,我们一般只和另外的 3 个包打交道。下面将对这 3 个包一一介绍。 Package java.nio 这个包主要定义了 Buffer 及其子类。 Buffer 定义了一个线性存放 primitive type 数据的容器 接口

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论