1      非阻塞(Nonblocking)体系结构
  
         在这一部分,我将从理论的角度来解释非阻塞体系的结构及其工作原理。这部“喜剧”(当然,如果你喜欢的话也可以称做戏剧)的“人物”如下:
  ●服务器端:接收请求的应用程序。
  ●客户端:向服务器端发出请求的应用程序。
  ●套接字通道:客户端与服务器端之间的通信通道。它能识别服务器端的IP地址和端口号。数据以Buffer中元素的形式通过套接字通道传送。
  ●选择器:所有非阻塞技术的主要对象。它监视着已注册的套接字通道,并序列化服务器需要应答的请求。
  ●关键字:选择器用来对对象的请求进行排序。每个关键字代表一个单独的客户端子请求并包含识别客户端和请求类型的信息。

  2 SocketChannel 类
 
    SocketAddress rama = new SocketAddress("localhost" , 8888) ;
    利用静态工厂方法得到SocketChannel的实例。
    SocketChannel client = SocketChannel.open(rama) ;

  如果这是传统的套接字,那么就会寻求得到socket的输入或者输出流,利用通道,我们可以直接写入通道本身,
  不是写入字节数组,而是要写入ByteBuffer对象,将此对象写入 client的read 方法。

    
  

       客户端应用程序同时执行对服务器端的请求,接着选择器将其集中起来,创建关键字,然后将其发
送至服务器端。这看起来像是阻塞(Blocking)体系,因为在一定时间内只处理一个请求,但事实并非如此。
实际上,每个关键字不代表从客户端发至服务器端的整个信息流,仅仅只是一部分。我们不要忘了选择器能
分割那些被关键字标识的子请求里的数据。因此,如果有更多连续地数据发送至服务器端,那么选择器就会
创建更多的根据时间共享策略(Time-sharing policy)来进行处理的关键字。强调一下,在图一中关键字的颜色
与客户端的颜色相对应。
   

     服务器端非阻塞(Server Nonblocking)
客户端和服务器端是两个Java应用程序。套接字通道是SocketChannel类的实例,这个类允许通过网络传送数据。
它们能被Java程序员看作是一个新的套接字。SocketChannel类被定义在java.nio.channel包中。
  选择器是一个Selector类的对象。该类的每个实例均能监视更多的套接字通道,进而建立更多的连接。
当一些有意义的事发生在通道上(如客户端试图连接服务器端或进行读/写操作),选择器便会通知应用程序处理请求。
选择器会创建一个关键字,这个关键字是SelectionKey类的一个实例。每个关键字都保存着应用程序的标识及请求的类型。
其中,请求的类型可以是如下之一:

基本上,服务器端的实现是由选择器等待事件和创建关键字的无限循环组成的。根据关键字的类型,及时的执行操作。
关键字存在以下4种可能的类型。
  Acceptable: 相应的客户端要求连接。
  Connectable:服务器端接受连接。
  Readable:服务器端可读。
  Writeable:服务器端可写。



一个通用的实现非阻塞服务器的算法如下:
  create SocketChannel;
  create Selector
  associate the SocketChannel to the Selector
  for(;;) {
  waiting events from the Selector;
  event arrived; create keys;
  for each key created by Selector {
  check the type of request;
  isAcceptable:
  get the client SocketChannel;
  associate that SocketChannel to the Selector;
  record it for read/write operations
  continue;
  isReadable:
  get the client SocketChannel;
  read from the socket;
  continue;
  isWriteable:
  get the client SocketChannel;
  write on the socket;
  continue;
  }
  }


 3  下面为一个实例
     (1)客户端
      

 1package cn.bupt.channel;
 2
 3import java.io.IOException;
 4import java.net.InetSocketAddress;
 5import java.net.SocketAddress;
 6import java.nio.ByteBuffer;
 7import java.nio.channels.Channels;
 8import java.nio.channels.SocketChannel;
 9import java.nio.channels.WritableByteChannel;
10
11import cn.bupt.constant.Default;
12
13public class ChargenClient {
14
15    public static int DEFAULT_PORT = 8778 ;
16    /**
17     * @param args
18     */

19    public static void main(String[] args) {
20        // TODO Auto-generated method stub
21       if(args.length == 0)
22       {
23           System.out.println("please input the port");
24           return ;
25       }

26       
27       int port ;
28       
29       
30       port = DEFAULT_PORT ;
31       
32       SocketAddress address = new InetSocketAddress(args[0] , port) ;
33       try {
34        SocketChannel client = SocketChannel.open(address) ;
35        ByteBuffer buffer = ByteBuffer.allocate(74) ;
36        WritableByteChannel out = Channels.newChannel(System.out) ;
37        
38        while(client.read(buffer) != -1)
39        {
40            buffer.flip() ;
41            out.write(buffer) ;
42            buffer.clear() ;
43            
44        }

45        
46        
47        
48        
49        
50        
51    }
 catch (IOException e) {
52        // TODO Auto-generated catch block
53        e.printStackTrace();
54    }

55       
56       
57        
58    }

59
60}

61


      
   (2) 服务器端 
        

  1package cn.bupt.channel;
  2
  3import java.io.IOException;
  4import java.net.InetSocketAddress;
  5import java.net.ServerSocket;
  6import java.nio.ByteBuffer;
  7import java.nio.channels.SelectionKey;
  8import java.nio.channels.Selector;
  9import java.nio.channels.ServerSocketChannel;
 10import java.nio.channels.SocketChannel;
 11import java.util.Iterator;
 12import java.util.Set;
 13
 14public class ChargenServer {
 15
 16    public static final int DEFAULT_PORT = 8778 ;
 17    /**
 18     * @param args
 19     */

 20    public static void main(String[] args) {
 21        // TODO Auto-generated method stub
 22        int port ;
 23        port = DEFAULT_PORT ;
 24        
 25        byte[] rotation = new byte[95 * 2 ] ;
 26        for(byte i = ' ' ; i < '~' ;i++)
 27        {
 28            rotation[i - ' '= i ;
 29            rotation[i + 95 - ' '= i ;
 30        }

 31        
 32        ServerSocketChannel serverChannel = null  ;
 33        Selector selector = null;
 34        
 35        
 36        /**
 37         * 先建立服务器端的通道
 38         * 
 39         */

 40        
 41        try {
 42            serverChannel = ServerSocketChannel.open() ;
 43            ServerSocket ss = serverChannel.socket() ;
 44            InetSocketAddress address = new InetSocketAddress(port) ; 
 45            ss.bind(address) ;
 46            serverChannel.configureBlocking(false) ;
 47            selector = Selector.open() ;
 48            serverChannel.register(selector, SelectionKey.OP_ACCEPT) ;
 49            
 50            
 51        
 52        }
 catch (IOException e) {
 53            // TODO Auto-generated catch block
 54            e.printStackTrace();
 55        }

 56        
 57        
 58        while(true)
 59        {
 60            
 61            try {
 62                selector.select() ;
 63            }
 catch (IOException e) {
 64                e.printStackTrace();
 65            }

 66            
 67            Set readyKeys = selector.selectedKeys() ;
 68            Iterator iter = readyKeys.iterator() ;
 69            while(iter.hasNext())
 70            {
 71                SelectionKey key = (SelectionKey) iter.next() ;
 72                iter.remove() ;
 73                
 74                if(key.isAcceptable())
 75                {
 76                    ServerSocketChannel server = (ServerSocketChannel) key.channel() ;
 77                    try {
 78                        SocketChannel client = server.accept() ;
 79                        System.out.println("Accept connection from " + client) ;
 80                        client.configureBlocking(false) ;
 81                        SelectionKey key2 = client.register(selector, SelectionKey.OP_WRITE) ;
 82                        ByteBuffer buffer = ByteBuffer.allocate(74) ;
 83                        buffer.put(rotation , 0 , 72) ;
 84                        buffer.put((byte)'\r') ;
 85                        buffer.put((byte)'\n') ;
 86                        buffer.flip() ;
 87                        key2.attach(buffer) ;
 88                        
 89                        
 90                        
 91                        
 92                    }
 catch (IOException e) {
 93                        // TODO Auto-generated catch block
 94                        e.printStackTrace();
 95                    }

 96                    
 97                    
 98                    
 99                    
100                }

101                
102                else
103                    if(key.isWritable())
104                    {
105                        
106                        /**
107                         * 建立客户端通道
108                         * 
109                         */

110                        SocketChannel client = (SocketChannel)key.channel() ;
111                        ByteBuffer buffer = (ByteBuffer) key.attachment() ;
112                        if(!buffer.hasRemaining())
113                        {
114                            buffer.rewind() ;
115                            int first = buffer.get() ;
116                            buffer.rewind() ;
117                            int position = first - ' ' + 1 ;
118                            buffer.put(rotation , position , 72) ;
119                            buffer.put((byte'\r') ;
120                            buffer.put((byte'\n');
121                            buffer.flip() ;
122                        }

123                        try {
124                            client.write(buffer) ;
125                        }
 catch (IOException e) {
126                            // TODO Auto-generated catch block
127                            e.printStackTrace();
128                        }

129                    }

130                    
131                    
132                    
133                
134                
135                
136                
137                
138                key.cancel() ;
139                try {
140                    key.channel().close() ;
141                }
 catch (IOException e) {
142                    // TODO Auto-generated catch block
143                    e.printStackTrace();
144                }

145            }

146            
147        
148        }

149        
150        
151        
152        
153        
154        
155        
156        
157        
158    }

159
160}

161


















 


posted on 2010-08-01 21:19 buptduming 阅读(4485) 评论(0)  编辑  收藏

只有注册用户登录后才能发表评论。


网站导航: