Chinaunix首页 | 论坛 | 博客
  • 博客访问: 749266
  • 博文数量: 130
  • 博客积分: 2951
  • 博客等级: 少校
  • 技术积分: 1875
  • 用 户 组: 普通用户
  • 注册时间: 2010-03-04 18:32
文章分类

全部博文(130)

文章存档

2013年(1)

2012年(129)

分类: Java

2012-04-20 17:26:10


  1. package intro.nio;


  2. import java.io.IOException;
  3. import java.net.InetAddress;
  4. import java.net.InetSocketAddress;
  5. import java.net.Socket;
  6. import java.nio.ByteBuffer;
  7. import java.nio.CharBuffer;
  8. import java.nio.channels.SelectableChannel;
  9. import java.nio.channels.SelectionKey;
  10. import java.nio.channels.Selector;
  11. import java.nio.channels.ServerSocketChannel;
  12. import java.nio.channels.SocketChannel;
  13. import java.nio.charset.CharacterCodingException;
  14. import java.nio.charset.Charset;
  15. import java.nio.charset.CharsetDecoder;
  16. import java.util.HashMap;
  17. import java.util.Iterator;
  18. import java.util.Set;

  19. public class NBlockingServer {
  20.     int port = 35000;
  21.     int BUFFERSIZE = 1024;
  22.     Selector selector = null;
  23.     ServerSocketChannel serverChannel = null;
  24.     HashMap clientChannelMap = null;// 用来存放每一个客户连接对应的套接字和通道

  25.     public NBlockingServer(int port) {
  26.         this.clientChannelMap = new HashMap();
  27.         this.port = port;
  28.     }

  29.     public void initialize() throws IOException {
  30.         // 初始化,分别实例化一个选择器,一个服务器端可选择通道
  31.         this.selector = Selector.open();
  32.         this.serverChannel = ServerSocketChannel.open();
  33.         this.serverChannel.configureBlocking(false);
  34.         InetAddress localhost = InetAddress.getLocalHost();
  35.         InetSocketAddress isa = new InetSocketAddress(localhost, this.port);
  36.         this.serverChannel.socket().bind(isa);// 将该套接字绑定到服务器某一可用端口
  37.     }

  38.     // 结束时释放资源
  39.     public void finalize() throws IOException {
  40.         this.serverChannel.close();
  41.         this.selector.close();
  42.     }

  43.     // 将读入字节缓冲的信息解码
  44.     public String decode(ByteBuffer byteBuffer) throws CharacterCodingException {
  45.         Charset charset = Charset.forName("ISO-8859-1");
  46.         CharsetDecoder decoder = charset.newDecoder();
  47.         CharBuffer charBuffer = decoder.decode(byteBuffer);
  48.         String result = charBuffer.toString();
  49.         return result;
  50.     }

  51.     // 监听端口,当通道准备好时进行相应操作
  52.     public void portListening() throws IOException, InterruptedException {
  53.         // 服务器端通道注册OP_ACCEPT事件
  54.         SelectionKey acceptKey = this.serverChannel.register(this.selector,
  55.                 SelectionKey.OP_ACCEPT);
  56.         // 当有已注册的事件发生时,select()返回值将大于0
  57.         while (acceptKey.selector().select() > 0) {
  58.             System.out.println("event happened");
  59.             // 取得所有已经准备好的所有选择键
  60.             Set readyKeys = this.selector.selectedKeys();
  61.             // 使用迭代器对选择键进行轮询
  62.             Iterator i = readyKeys.iterator();
  63.             while (i.hasNext()) {
  64.                 SelectionKey key = (SelectionKey) i.next();
  65.                 i.remove();// 删除当前将要处理的选择键
  66.                 if (key.isAcceptable()) {// 如果是有客户端连接请求
  67.                     System.out.println("more client connect in!");
  68.                     ServerSocketChannel nextReady = (ServerSocketChannel) key
  69.                             .channel();
  70.                     // 获取客户端套接字
  71.                     //Socket s = nextReady.accept();
  72.                     SocketChannel sc = nextReady.accept();
  73.                     // 设置对应的通道为异步方式并注册感兴趣事件
  74.                     //s.getChannel().configureBlocking(false);
  75.                     sc.configureBlocking(false);
  76.                     //SelectionKey readWriteKey = s.getChannel().register(
  77.                     SelectionKey readWriteKey = sc.register(
  78.                             this.selector,
  79.                             SelectionKey.OP_READ | SelectionKey.OP_WRITE);
  80.                     // 将注册的事件与该套接字联系起来
  81.                     readWriteKey.attach(sc);
  82.                     // 将当前建立连接的客户端套接字及对应的通道存放在哈希表//clientChannelMap中
  83.                     this.clientChannelMap.put(sc,
  84.                             new ClientChInstance(sc));
  85.                 } else if (key.isReadable()) {// 如果是通道读准备好事件
  86.                     System.out.println("Readable");
  87.                     // 取得选择键对应的通道和套接字
  88.                     SelectableChannel nextReady = (SelectableChannel) key
  89.                             .channel();
  90.                     //Socket socket = (Socket) key.attachment();
  91.                     SocketChannel sc = (SocketChannel) key.attachment();
  92.                     // 处理该事件,处理方法已封装在类ClientChInstance中
  93.                     this.readFromChannel(sc,
  94.                             (ClientChInstance) this.clientChannelMap
  95.                                     .get(sc));
  96.                 } else if (key.isWritable()) {// 如果是通道写准备好事件
  97.                     System.out.println("writeable");
  98.                     // 取得套接字后处理,方法同上
  99.                     //Socket socket = (Socket) key.attachment();
  100.                     SocketChannel sc = (SocketChannel) key.attachment();
  101.                     //SocketChannel channel = (SocketChannel) socket.getChannel();
  102.                     this.writeToChannel(sc, "This is from server!");
  103.                 }
  104.             }
  105.         }
  106.     }

  107.     // 对通道的写操作
  108.     public void writeToChannel(SocketChannel channel, String message)
  109.             throws IOException {
  110.         ByteBuffer buf = ByteBuffer.wrap(message.getBytes());
  111.         int nbytes = channel.write(buf);
  112.     }

  113.     // 对通道的读操作
  114.     public void readFromChannel(SocketChannel channel,
  115.             ClientChInstance clientInstance) throws IOException,
  116.             InterruptedException {
  117.         ByteBuffer byteBuffer = ByteBuffer.allocate(BUFFERSIZE);
  118.         int nbytes = channel.read(byteBuffer);
  119.         byteBuffer.flip();
  120.         String result = this.decode(byteBuffer);
  121.         // 当客户端发出”@exit”退出命令时,关闭其通道
  122.         if (result.indexOf("@exit") >= 0) {
  123.             channel.close();
  124.         } else {
  125.             clientInstance.append(result.toString());
  126.             // 读入一行完毕,执行相应操作
  127.             if (result.indexOf("\n") >= 0) {
  128.                 System.out.println("client input" + result);
  129.                 clientInstance.execute();
  130.             }
  131.         }
  132.     }

  133.     // 该类封装了怎样对客户端的通道进行操作,具体实现可以通过重载execute()方法
  134.     public class ClientChInstance {
  135.         SocketChannel channel;
  136.         StringBuffer buffer = new StringBuffer();

  137.         public ClientChInstance(SocketChannel channel) {
  138.             this.channel = channel;
  139.         }

  140.         public void execute() throws IOException {
  141.             String message = "This is response after reading from channel!";
  142.             writeToChannel(this.channel, message);
  143.             buffer = new StringBuffer();
  144.         }

  145.         // 当一行没有结束时,将当前字窜置于缓冲尾
  146.         public void append(String values) {
  147.             buffer.append(values);
  148.         }
  149.     }

  150.     // 主程序
  151.     public static void main(String[] args) {
  152.         NBlockingServer nbServer = new NBlockingServer(8000);
  153.         try {
  154.             nbServer.initialize();
  155.         } catch (Exception e) {
  156.             e.printStackTrace();
  157.             System.exit(-1);
  158.         }
  159.         try {
  160.             nbServer.portListening();
  161.             System.out.println("heer");
  162.         } catch (Exception e) {
  163.             e.printStackTrace();
  164.         }
  165.     }
  166. }
不过这个程序运行起来后,我不能telnet 127.0.0.1 35000...总是说端口无法打开。。。还要再查查
阅读(3440) | 评论(0) | 转发(0) |
0

上一篇:JAVA - Annotation

下一篇:san switch配置实践

给主人留下些什么吧!~~