JAVA网页编程之Java收集服务器编程(NIO版)
java比较简单,没有C++的烦琐,但学习时最好有C++为基础.与JSP和SQL起应用,功能强大.编程|服务器|收集从Java1.4入手下手供应的NIOAPI经常使用于开辟高功能收集服务器,本文演示了怎样用这个API开辟一个TCPEchoServer。
Java收集服务器编程一文演示了怎样利用Java的SocketAPI编写一个复杂的TCPEchoServer。其堵塞式IO的处置体例固然复杂,但每一个客户端都必要一个独自的Thread来处置,当服务器必要同时处置大批客户端时,这类做法不再可行。利用NIOAPI可让一个或无限的几个Thread同时处置毗连到服务器上的一切客户端。(关于NIOAPI的一些先容,能够在JavaNIOAPI详解一文中找到。)
NIOAPI同意一个线程经由过程Selector对象同时监控多个SelectableChannel来处置多路IO,NIO使用程序一样平常按下图所示事情:
Figure1
如Figure1所示,Client一向在轮回地举行select操纵,每次select()前往今后,经由过程selectedKeys()能够失掉必要处置的SelectableChannel并对其逐一处置。
如许做固然复杂但也有个成绩,当有分歧范例的SelectableChannel必要做分歧的IO处置时,在图中Client的代码就必要判别channel的范例然后再作响应的操纵,这常常意味着连续串的ifelse。更糟的是,每增添一种新的channel,不仅必要增添响应的处置代码,还必要对这一串ifelse举行保护。(在本文的这个例子中,我们有ServerSocketChannel和SocketChannel这两种channel必要分离被处置。)
假如思索将channel及其必要的IO处置举行封装,笼统出一个一致的接口,就能够办理这一成绩。在Listing1中的NioSession就是这个接口。
NioSession的channel()办法前往其封装的SelectableChannel对象,interestOps()前往用于这个channel注册的interestOps。registered()是当SelectableChannel被注册后挪用的回调函数,经由过程这个回调函数,NioSession能够失掉channel注册后的SelectionKey。process()函数则是NioSession接口的中心,这个办法笼统了封装的SelectableChannel所需的IO处置逻辑。
Listing1:
publicinterfaceNioSession{
publicSelectableChannelchannel();
publicintinterestOps();
publicvoidregistered(SelectionKeykey);
publicvoidprocess();
}
和NioSession一同事情的是NioWorker这个类(Listing2),它是NioSession的挪用者,封装了一个Selector对象和Figure1中轮回select操纵的逻辑。了解这个类能够匡助我们懂得该怎样利用NioSession这个接口。
NioWorker完成了Runnable接口,轮回select操纵的逻辑就在run()办法中。在NioWorker–NioSession这个框架中,NioSession在channel注册的时分会被作为attachment送进register函数,如许,在每次select()操纵的轮回中,关于selectedKeys()中的每个SelectionKey,我们都能够经由过程attachment拿到其绝对应的NioSession然后挪用其process()办法。
每次select()轮回另有一个义务,就是将经由过程add()办法到场到这个NioWorker的NioSession注册到Selector上。在Listing2的代码中能够看出,NioSession中的channel()被掏出并注册在Selector上,注册所需的interestOps从NioSession中掏出,NioSession自己则作为attachment送进register()函数。注册乐成后,NioSession的registered()回调函数会被挪用。
NioWorker的add()办法的感化是将一个NioSession到场到该NioWorker中,并wakeup以后的select操纵,如许鄙人一次的select()挪用之前,这个NioSession会被注册。stop()办法则是让一个正在run()的NioWorker中断。closeAllChannels()会封闭以后注册的一切channel,这个办法可在NioWorker不再利用时用来开释IO资本。
Listing2:
publicclassNioWorkerimplementsRunnable{
publicNioWorker(Selectorsel){
_sel=sel;
_added=newHashSet();
}
publicvoidrun(){
try{
try{
while(_run){
_sel.select();
Setselected=_sel.selectedKeys();
for(Iteratoritr=selected.iterator();itr.hasNext();){
SelectionKeykey=(SelectionKey)itr.next();
NioSessions=(NioSession)key.attachment();
s.process();
itr.remove();
}
synchronized(_added){
for(Iteratoritr=_added.iterator();itr.hasNext();){
NioSessions=(NioSession)itr.next();
SelectionKeykey=s.channel().register(_sel,s.interestOps(),s);
s.registered(key);
itr.remove();
}
}
}
}finally{
_sel.close();
}
}catch(IOExceptionex){
thrownewError(ex);
}
}
publicvoidadd(NioSessions){
synchronized(_added){
_added.add(s);
}
_sel.wakeup();
}
publicsynchronizedvoidstop(){
_run=false;
_sel.wakeup();
}
publicvoidcloseAllChannels(){
for(Iteratoritr=_sel.keys().iterator();itr.hasNext();){
SelectionKeykey=(SelectionKey)itr.next();
try{
key.channel().close();
}catch(IOExceptionex){}
}
}
protectedSelector_sel=null;
protectedCollection_added=null;
protectedvolatileboolean_run=true;
}
在EchoServer这个例子中,我们必要一个ServerSocketChannel来承受新的TCP毗连,关于每一个TCP毗连,我们还必要一个SocketChannel来处置这个TCP毗连上的IO操纵。把这两种channel和下面的NioWorker–NioSession布局整合在一同,能够失掉NioServerSession和NioEchoSession这两个类,它们分离封装了ServerSocketChannel和SocketChannel及其对应的IO操纵。上面这个UML类图形貌了这4个类的干系:
Figure2
能够看到NioWorker和NioSession对新到场的两个类没有任何依附性,NioServerSession和NioEchoSession经由过程完成NioSession这个接口为体系到场了新的功效。如许的一个别系架构切合了Open-Close准绳,新的功效能够经由过程完成NioSession被到场而无需对原本的模块举行修正,这表现了面向对象计划的壮大能力。
NioServerSession的完成(Listing3)绝对对照复杂,其封装了一个ServerSocketChannel和从这个channel上承受新的TCP毗连的逻辑。NioServerSession还必要一个NioWorker的援用,如许每承受一个新的TCP毗连,NioServerSession就为其创立一个NioEchoSession的对象,并将这个对象到场到NioWorker中。
Listing3:
publicclassNioServerSessionimplementsNioSession{
publicNioServerSession(ServerSocketChannelchannel,NioWorkerworker){
_channel=channel;
_worker=worker;
}
publicvoidregistered(SelectionKeykey){}
publicvoidprocess(){
try{
SocketChannelc=_channel.accept();
if(c!=null){
c.configureBlocking(false);
NioEchoSessions=newNioEchoSession(c);
_worker.add(s);
}
}catch(IOExceptionex){
thrownewError(ex);
}
}
publicSelectableChannelchannel(){
return_channel;
}
publicintinterestOps(){
returnSelectionKey.OP_ACCEPT;
}
protectedServerSocketChannel_channel;
protectedNioWorker_worker;
}
NioEchoSession的举动要庞大一些,NioEchoSession会先从TCP毗连中读取数据,再将这些数据用统一个毗连写归去,偏重复这个步骤直到客户端把毗连封闭为止。我们能够把“Reading”和“Writing”看做NioEchoSession的两个形态,如许能够用一个无限形态机来形貌它的举动,以下图所示:
Figure3
接上去的事情就是怎样完成这个无限形态机了。在这个例子中,我们利用State形式来完成它。上面这张UML类图形貌了NioEchoSession的计划细节。
Figure4
NioEchoSession所处的形态由EchoState这个笼统类来体现,其两个子类分离对应了“Reading”和“Writing”这两个形态。NioEchoSession会将process()和interestOps()这两个办法delegate给EchoState来处置,如许,当NioEchoSession处于分歧的形态时,就会有分歧的举动。
Listing4是EchoState的完成。EchoState界说了process()和interestOps()这两个笼统的办法来让子类完成。NioEchoSession中的process()办法会被delegate到其以后EchoState的process()办法,NioEchoSession自己也会作为一个形貌context的参数被送进EchoState的process()办法中。EchoState界说的interestOps()办法则会在NioEchoSession注册和变化State的时分被用到。
EchoState还界说了两个静态的办法来前往事后创立好的ReadState和WriteState,如许做的优点是能够制止在NioEchoSession转换state的时分创立一些不用要的对象从而影响功能。但是,如许做请求state类必需是无形态的,形态必要保留在context类,也就是NioEchoSession中。
Listing4:
publicabstractclassEchoState{
publicabstractvoidprocess(NioEchoSessions)throwsIOException;
publicabstractintinterestOps();
publicstaticEchoStatereadState(){
return_read;
}
publicstaticEchoStatewriteState(){
return_write;
}
protectedstaticEchoState_read=newReadState();
protectedstaticEchoState_write=newWriteState();
}
Listing5是NioEchoSession的完成。NioEchoSession包括有一个SocketChannel,这个channel注册后失掉的SelectionKey,一个用于寄存数据的ByteBuffer和一个纪录以后state的EchoState对象。在初始化时,EchoState被初始化为一个ReadState。NioEchoSession把process()办法和interestOps()办法都delegate到以后的EchoState中。其setState()办法用于切换以后state,在切换state后,NioEchoSession会经由过程SelectionKey更新注册的interestOps。close()办法用于封闭这个NioEchoSession对象。
Listing5:
publicclassNioEchoSessionimplementsNioSession{
publicNioEchoSession(SocketChannelc){
_channel=c;
_buf=ByteBuffer.allocate(128);
_state=EchoState.readState();
}
publicvoidregistered(SelectionKeykey){
_key=key;
}
publicvoidprocess(){
try{
_state.process(this);
}catch(IOExceptionex){
close();
thrownewError(ex);
}
}
publicSelectableChannelchannel(){
return_channel;
}
publicintinterestOps(){
return_state.interestOps();
}
publicvoidsetState(EchoStatestate){
_state=state;
_key.interestOps(interestOps());
}
publicvoidclose(){
try{
_channel.close();
}catch(IOExceptionex){
thrownewError(ex);
}
}
protectedSocketChannel_channel=null;
protectedSelectionKey_key;
protectedByteBuffer_buf=null;
protectedEchoState_state=null;
}
Listing6和Listing7分离是ReadState和WriteState的完成。ReadState在process()中会先从NioEchoSession的channel中读取数据,假如未能读到数据,NioEchoSession会持续留在ReadState;假如读掏出错,NioEchoSession会被封闭;假如读取乐成,NioEchoSession会被切换到WriteState。WriteState则卖力将NioEchoSession中已读取的数据写回到channel中,全体写完后,NioEchoSession会被切换回ReadState。
Listing6:
publicclassReadStateextendsEchoState{
publicvoidprocess(NioEchoSessions)
throwsIOException
{
SocketChannelchannel=s._channel;
ByteBufferbuf=s._buf;
intcount=channel.read(buf);
if(count==0){
return;
}
if(count==-1){
s.close();
return;
}
buf.flip();
s.setState(EchoState.writeState());
}
publicintinterestOps(){
returnSelectionKey.OP_READ;
}
}
Listing7:
publicclassWriteStateextendsEchoState{
publicvoidprocess(NioEchoSessions)
throwsIOException
{
SocketChannelchannel=s._channel;
ByteBufferbuf=s._buf;
channel.write(buf);
if(buf.remaining()==0){
buf.clear();
s.setState(EchoState.readState());
}
}
publicintinterestOps(){
returnSelectionKey.OP_WRITE;
}
}
NioEchoServer(Listing8)被用来启动和封闭一个TCPEchoServer,这个类完成了Runnable接口,挪用其run()办法就启动了EchoServer。其shutdown()办法被用来封闭这个EchoServer,注重shutdown()和run()的finallyblock中的同步代码确保了只要当EchoServer被封闭后,shutdown()办法才会前往。
Listing8:
publicclassNioEchoServerimplementsRunnable{
publicvoidrun(){
try{
ServerSocketChannelserv=ServerSocketChannel.open();
try{
serv.socket().bind(newInetSocketAddress(7));
serv.configureBlocking(false);
_worker=newNioWorker(Selector.open());
NioServerSessions=newNioServerSession(serv,_worker);
_worker.add(s);
_worker.run();
}finally{
_worker.closeAllChannels();
synchronized(this){
notify();
}
}
}catch(IOExceptionex){
thrownewError(ex);
}
}
publicsynchronizedvoidshutdown(){
_worker.stop();
try{
wait();
}catch(InterruptedExceptionex){
thrownewError(ex);
}
}
protectedNioWorker_worker=null;
}
最初,经由过程一个复杂的main()函数(Listing9),我们就能够运转这个EchoServer了。
Listing9:
publicstaticvoidmain(String[]args){
newNioEchoServer().run();
}
我们能够经由过程telnet程序来查验这个程序的运转情况:
1.翻开一个命令行,输出telnetlocalhost7来运转一个telnet程序并毗连到EchoServer上。
2.在telnet程序中输出字符,能够看到输出的字符被显现在屏幕上。(这是由于EchoServer将收到的字符写回到客户端)
3.多翻开几个telnet程序举行测试,能够看到EchoServer能经由过程NIOAPI用一个Thread服务多个客户端。
DaiJiaLin
mailto:woodydai@gmail.com
http://blog.csdn.net/DaiJiaLin
J2ME在手机游戏开发的作用也是无用质疑的。至于桌面程序,可能有人说java不行,界面不好看,但是请看看NetBeans和Eclipse吧,他们都是利用java开发的,而他们的界面是多么的华丽,所以界面决不是java的缺点。还有一个不得不提的优点就是大多java人员都挂在嘴边的java的跨平台性,目前这确实也是java优点之一。 接着就是EJB了,EJB就是Enterprise JavaBean, 看名字好象它是Javabean,可是它和Javabean还是有区别的。它是一个体系结构,你可以搭建更安全、更稳定的企业应用。它的大量代码已由中间件(也就是我们常听到的 Weblogic,Websphere这些J2EE服务器)完成了,所以我们要做的程序代码量很少,大部分工作都在设计和配置中间件上。 Jive的资料在很多网站上都有,大家可以找来研究一下。相信你读完代码后,会有脱胎换骨的感觉。遗憾的是Jive从2.5以后就不再无条件的开放源代码,同时有licence限制。不过幸好还有中国一流的Java程序员关注它,外国人不开源了,中国人就不能开源吗?这里向大家推荐一个汉化的Jive版本—J道。Jive(J道版)是由中国Java界大名 鼎鼎的banq在Jive 2.1版本基础上改编而成, 全中文,增加了一些实用功能,如贴图,用户头像和用户资料查询等,而且有一个开发团队在不断升级。你可以访问banq的网站 其实说这种话的人就如当年小日本号称“三个月拿下中国”一样大言不惭。不是Tomjava泼你冷水,你现在只是学到了Java的骨架,却还没有学到Java的精髓。接下来你得研究设计模式了。 我大二,Java也只学了一年,觉得还是看thinking in java好,有能力的话看英文原版(中文版翻的不怎么好),还能提高英文文档阅读能力。 多重继承(以接口取代)等特性,增加了垃圾回收器功能用于回收不再被引用的对象所占据的内存空间,使得程序员不用再为内存管理而担忧。在 Java 1.5 版本中,Java 又引入了泛型编程(Generic Programming)、类型安全的枚举、不定长参数和自动装/拆箱等语言特性。 应用在电视机、电话、闹钟、烤面包机等家用电器的控制和通信。由于这些智能化家电的市场需求没有预期的高,Sun公司放弃了该项计划。随着1990年代互联网的发展 是一种突破用户端机器环境和CPU Java是一种计算机编程语言,拥有跨平台、面向对java 是一种使网页(Web Page)产生生动活泼画面的语言 接着就是EJB了,EJB就是Enterprise JavaBean, 看名字好象它是Javabean,可是它和Javabean还是有区别的。它是一个体系结构,你可以搭建更安全、更稳定的企业应用。它的大量代码已由中间件(也就是我们常听到的 Weblogic,Websphere这些J2EE服务器)完成了,所以我们要做的程序代码量很少,大部分工作都在设计和配置中间件上。 是一种简化的C++语言 是一种安全的语言,具有阻绝计算机病毒传输的功能 不过,每次的执行编译后的字节码需要消耗一定的时间,这同时也在一定程度上降低了 Java 程序的运行效率。 设计模式是高级程序员真正掌握面向对象核心思想的必修课。设计模式并不是一种具体"技术",它讲述的是思想,它不仅仅展示了接口或抽象类在实际案例中的灵活应用和智慧 是一种使网页(Web Page)产生生动活泼画面的语言 是一种使用者不需花费很多时间学习的语言 《JAVA语言程序设计》或《JAVA从入门到精通》这两本书开始学,等你编程有感觉的时候也可以回看一下。《JAVA读书笔记》这本书,因为讲的代码很多,也很容易看懂,涉及到面也到位。是你学习技术巩固的好书,学完后就看看《JAVA编程思想》这本书,找找一个自己写的代码跟书上的代码有什么不一样。 Jive的资料在很多网站上都有,大家可以找来研究一下。相信你读完代码后,会有脱胎换骨的感觉。遗憾的是Jive从2.5以后就不再无条件的开放源代码,同时有licence限制。不过幸好还有中国一流的Java程序员关注它,外国人不开源了,中国人就不能开源吗?这里向大家推荐一个汉化的Jive版本—J道。Jive(J道版)是由中国Java界大名 鼎鼎的banq在Jive 2.1版本基础上改编而成, 全中文,增加了一些实用功能,如贴图,用户头像和用户资料查询等,而且有一个开发团队在不断升级。你可以访问banq的网站 Java自面世后就非常流行,发展迅速,对C++语言形成了有力冲击。Java 技术具有卓越的通用性、高效性、平台移植性和安全性,广泛应用于个人PC、数据中心、游戏控制台 一直感觉JAVA很大,很杂,找不到学习方向,前两天在网上找到了这篇文章,感觉不错,给没有方向的我指了一个方向,先不管对不对,做下来再说。
页:
[1]