首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > JAVA > J2SE开发 >

非阻塞服务器建立有关问题

2012-06-30 
非阻塞服务器建立问题这是一份关于建立非阻塞服务器的完整代码,有好几个地方不明白!!!希望高人指教。。。。以

非阻塞服务器建立问题
这是一份关于建立非阻塞服务器的完整代码,有好几个地方不明白!!!希望高人指教。。。。以前用的都是阻塞式socket通信,第一次接触非阻塞通信,对于缓冲区,以及读写控制等都不是很懂!对于疑惑的地方我在以下代码中标出!求解答。。。(各种函数,类我都在jdk文档中看过解释,所以请勿直接贴解释,比较笨,希望得到通俗易懂的理解)
[code=Java]
package   thread2;
import   java.io.*;
import   java.nio.*;
import   java.nio.channels.*;
import   java.nio.charset.*;
import   java.net.*;
import   java.util.*;

public   class   EchoServer{
    private   Selector   selector   =   null;
    private   ServerSocketChannel   serverSocketChannel   =   null;
    private   int   port   =   8000;
    private   Charset   charset=Charset.forName( "GBK ");

    public   EchoServer()throws   IOException{
        selector   =   Selector.open();
        serverSocketChannel=   ServerSocketChannel.open();
        serverSocketChannel.socket().setReuseAddress(true);
        serverSocketChannel.socket().bind(new   InetSocketAddress(port));
        System.out.println( "服务器启动 ");
    }

    public   void   accept(){
            for(;;){
                try{
                        SocketChannel   socketChannel   =   serverSocketChannel.accept();
                        System.out.println( "接收到客户连接,来自: "   +
                                                              socketChannel.socket().getInetAddress()   +
                                                              ": "   +   socketChannel.socket().getPort());
                        socketChannel.configureBlocking(false);

                        ByteBuffer   buffer   =   ByteBuffer.allocate(1024);
                        synchronized(gate){                                 //问题1:此处同步的运用不是很懂!关gate什么事???后面也有用到
                                selector.wakeup();                           //问题2:wakeup()在此处的作用
                                socketChannel.register(selector,
                                                                              SelectionKey.OP_READ   |
                                                                              SelectionKey.OP_WRITE,   buffer);         //问题3:buffer说是附加的项目,有什么用?


                        }
                }catch(IOException   e){e.printStackTrace();}
            }
    }
    private   Object   gate=new   Object();
    public   void   service()   throws   IOException{
        for(;;){
            synchronized(gate){}
            int   n   =   selector.select();

            if(n==0)continue;
            Set   readyKeys   =   selector.selectedKeys();
            Iterator   it   =   readyKeys.iterator();
            while   (it.hasNext()){
                SelectionKey   key=null;
                try{
                        key   =   (SelectionKey)   it.next();
                        it.remove();
                        if   (key.isReadable())   {                 //问题4:selector的监控机制我有研究过!基本知识懂。但不明白如何控制数据的通信!比如我要通过此服务器像客户端发送数据该调用什么函数?或是进行什么操作?这个困扰了很久。。。务必解答呀~~~
                                receive(key);
                        }
                        if   (key.isWritable())   {
                                send(key);
                        }
                }catch(IOException   e){
                      e.printStackTrace();
                      try{
                              if(key!=null){
                                      key.cancel();
                                      key.channel().close();
                              }
                      }catch(Exception   ex){e.printStackTrace();}
                }
            }//#while
        }//#while
    }

    public   void   send(SelectionKey   key)throws   IOException{
   
        ByteBuffer   buffer=(ByteBuffer)key.attachment();                   //问题5:这个函数里面对bytebuffer的各种操作,flip(),compact()等。。。看来解释,还是没搞懂实际作用=   =。


        SocketChannel   socketChannel=(SocketChannel)key.channel();
        buffer.flip();     //把极限设为位置
        String   data=decode(buffer);
        if(data.indexOf( "\n ")==-1)return;
       
        String   outputData=data.substring(0,data.indexOf( "\n ")+1);
        System.out.print(outputData);
        ByteBuffer   outputBuffer=encode( "echo: "+outputData);
       
        while(outputBuffer.hasRemaining())
            socketChannel.write(outputBuffer);

        ByteBuffer   temp=encode(outputData);
        buffer.position(temp.limit());
        buffer.compact();

        if(outputData.equals( "bye\r\n ")){
            key.cancel();
            socketChannel.close();
            System.out.println( "关闭与客户的连接 ");
        }
    }

    public   void   receive(SelectionKey   key)throws   IOException{
        ByteBuffer   buffer=(ByteBuffer)key.attachment();

        SocketChannel   socketChannel=(SocketChannel)key.channel();
        ByteBuffer   readBuff=   ByteBuffer.allocate(32);
        socketChannel.read(readBuff);
        readBuff.flip();

        buffer.limit(buffer.capacity());
        buffer.put(readBuff);
    }

    public   String   decode(ByteBuffer   buffer){     //解码
        CharBuffer   charBuffer=   charset.decode(buffer);
        return   charBuffer.toString();
    }
    public   ByteBuffer   encode(String   str){     //编码
        return   charset.encode(str);
    }

    public   static   void   main(String   args[])throws   Exception{
        final   EchoServer   server   =   new   EchoServer();
        Thread   accept=new   Thread(){
                public   void   run(){
                        server.accept();
                }
        };
        accept.start();
        server.service();
    }
}
[/code]

路过的大神,求解=   =。这两天研究这个非阻塞通信,纠结死了。请耐心解答,感激不尽!

[解决办法]
非阻塞通信要细讲起来太多(做过C的scoket通信的可能会更容易理解)
就LZ的问题回答吧
//问题1:此处同步的运用不是很懂!关gate什么事???后面也有用到 
gate在这里只是一个锁的作用,这种用法在多线程里很常见,就是一个线程A要执行一段代码,就先要获得gate对象的锁,如果gate的锁已经有线程B在使用,那么线程A就会等待只到线程B把锁交出来,所以gate在这里就是协调accept和service的同步(因为accept方法是用一个线程调用,service方法是主线程调用)

//问题2:wakeup()在此处的作用 
就是如果有某个线程因为调用selct而正在堵塞中,那么wakeup就是让堵塞的线程立即返回,即select处理立刻结束,这样就可以遍历选择器的key去判断哪些通道有数据,可以采取什么操作等等



//问题3:buffer说是附加的项目,有什么用?
就是给通道一个缓存的附加项目,这样可以方便从通道中获得一个附加项目来操作,否则就要自己根据不同的通道去创建和查找通道的缓存,如果通道太多,管理就比较混乱(因为哪个缓存对应哪个通道要自己管理),所以还是让管道自己带着一个附加项目的缓存管理起来方便

//问题4:selector的监控机制我有研究过!基本知识懂。但不明白如何控制数据的通信!比如我要通过此服务器像客户端发送数据该调用什么函数?或是进行什么操作?这个困扰了很久。。。务必解答呀~~~ 
LZ你的receive方法和send方法就是接收和发送处理,key就是问题3处注册的通道的键(通过此键可以找回通信通道),socketChannel的read就是收信(就是从通道中读取数据到缓存),write就是送信(就把数据写到通道)

//问题5:这个函数里面对bytebuffer的各种操作,flip(),compact()等。。。看来解释,还是没搞懂实际作用= =。 
缓存是线性操作位置(position)到限制(limit)这段区间,那么假如我们保存数据,比如从0位置开始一直保存到64位置,限制是100,因为继续读或者继续写的话,是从65位置开始的,而此时如果我们想读取0-64位置的信息,该怎么办?那么就要调用flip方法,这样就会把限制(limit)设置到当前64的位置(position),并把位置(position)设置到0,这样我们就可以读取从0位置开始到64位置限制的信息了
而compact就是压缩缓存,什么意思呢?简单的说就是把当前位置到限制位置的信息移动到0位置开始,然后把当前位置设置为limit-positin+1(也就是移动的长度+1),然后把限制(limit)设置为最大。还是用上面的例子来说明,当前位置是65,限制是100,那么调用compact就会把65-100位置的信息移动到从0位置开始,即把65位置的信息保存到0位置,66位置的信息保存到1位置,依次类推,这样就变成从65-100位置的信息移动到了0-35位置,然后再把当前位置设置为36,把限制设置为最大(比如最大是1024,那么limit就设置到1024)

[解决办法]
2、问题四中,我问错方向了。。。我想知道key.readable()和key.writeable(),其中某些通道也就是key的这两个方法的结果为什么突然就变成true,而实现后续的读写操作?是什么操纵的?我可以调用吗?因为我要实现向特定客户端发送信息的功能!如果这个不可控,那我如何实现= =。应该不是直接调用write函数吧。。。

一般不注册写事件,想什么时候写就什么时候写,想写什么就写什么。
[解决办法]

探讨

2、问题四中,我问错方向了。。。我想知道key.readable()和key.writeable(),其中某些通道也就是key的这两个方法的结果为什么突然就变成true,而实现后续的读写操作?是什么操纵的?我可以调用吗?因为我要实现向特定客户端发送信息的功能!如果这个不可控,那我如何实现= =。应该不是直接调用write函数吧。。。

一般不注册写事件,想什么时候写就什么时候写,想写什么就写……

热点排行
Bad Request.