JavaNIO非阻塞服务器示例

以前一直用的是“ervery thread per connection”的服务器端模式,今天试了下NIO非阻塞模式的服务器。 不过java不能实现I/O完成端口模型,这点很遗憾。

峨山县网站制作公司哪家好,找成都创新互联!从网页设计、网站建设、微信开发、APP开发、响应式网站等网站项目制作,到程序开发,运营维护。成都创新互联从2013年开始到现在10年的时间,我们拥有了丰富的建站经验和运维经验,来保证我们的工作的顺利进行。专注于网站建设就选成都创新互联

 
 
 
  1. package com.vista.Server;
  2. import java.io.IOException;
  3. import java.net.InetSocketAddress;
  4. import java.net.ServerSocket;
  5. import java.nio.ByteBuffer;
  6. import java.nio.channels.SelectionKey;
  7. import java.nio.channels.Selector;
  8. import java.nio.channels.ServerSocketChannel;
  9. import java.nio.channels.SocketChannel;
  10. import java.util.Iterator;
  11. import java.util.LinkedList;
  12. import java.util.Set;
  13. public class SelectorServer 
  14. {
  15.     private static int DEFAULT_SERVERPORT = 6018;//默认端口
  16.     private static int DEFAULT_BUFFERSIZE = 1024;//默认缓冲区大小为1024字节
  17.     private ServerSocketChannel channel;
  18.     private LinkedList clients;
  19.     private Selector readSelector;
  20.     private ByteBuffer buffer;//字节缓冲区
  21.     private int port;
  22.     
  23.     public SelectorServer(int port) throws IOException
  24.     {
  25.         this.port = port;
  26.         this.clients = new LinkedList();
  27.         this.channel = null;
  28.         this.readSelector = Selector.open();//打开选择器
  29.         this.buffer = ByteBuffer.allocate(DEFAULT_BUFFERSIZE);
  30.     }
  31.      // 服务器程序在服务循环中调用sericeClients()方法为已接受的客户服务
  32.     public void serviceClients()throws IOException
  33.     {
  34.         Set keys;
  35.         Iterator it;
  36.         SelectionKey key;
  37.         SocketChannel client;
  38.         // 在readSelector上调用select()方法,参数1代表如果调用select的时候 那么阻塞最多1秒钟等待可用的客户端连接
  39.         if(readSelector.select(1) > 0)
  40.         {
  41.             keys = readSelector.selectedKeys(); // 取得代表端通道的键集合
  42.             it = keys.iterator();
  43.            // 遍历,为每一个客户服务 
  44.             while(it.hasNext()) 
  45.             {
  46.                key = (SelectionKey)it.next();
  47.                if(key.isReadable())
  48.                { // 如果通道可读,那么读此通道到buffer中
  49.                   int bytes;
  50.                   client = (SocketChannel)key.channel();// 取得键对应的通道
  51.                   buffer.clear(); // 清空缓冲区中的内容,设置好position,limit,准备接受数据
  52.                   bytes = client.read(buffer); // 从通道中读数据到缓冲中,返回读取得字节数
  53.                   if(bytes >= 0) 
  54.                   {
  55.                      buffer.flip(); // 准备将缓冲中的数据写回到通道中
  56.                      client.write(buffer);  // 数据写回到通道中
  57.                   } 
  58.                   else if(bytes < 0) 
  59.                   { // 如果返回小于零的值代表读到了流的末尾
  60.                      clients.remove(client);
  61.                   // 通道关闭时,选择键也被取消
  62.                      client.close();
  63.                   }
  64.                }
  65.             }
  66.          }
  67.     }
  68.     
  69.     public void registerClient(SocketChannel client) throws IOException
  70.     {// 配置和注册代表客户连接的通道对象
  71.         client.configureBlocking(false);  // 设置此通道使用非阻塞模式    
  72.         client.register(readSelector, SelectionKey.OP_READ); // 将这个通道注册到选择器上
  73.         clients.add(client); //保存这个通道对象
  74.     }
  75.     public void listen() throws IOException
  76.     { //服务器开始监听端口,提供服务
  77.         ServerSocket socket;
  78.         SocketChannel client;
  79.         channel = ServerSocketChannel.open(); // 打开通道
  80.         socket = channel.socket();   //得到与通到相关的socket对象
  81.         socket.bind(new InetSocketAddress(port), 10);   //将scoket榜定在制定的端口上
  82.         //配置通到使用非阻塞模式,在非阻塞模式下,可以编写多道程序同时避免使用复杂的多线程
  83.         channel.configureBlocking(false);    
  84.         try 
  85.         {
  86.             while(true) 
  87.             {//     与通常的程序不同,这里使用channel.accpet()接受客户端连接请求,而不是在socket对象上调用accept(),这里在调用accept()方法时如果通道配置为非阻塞模式,那么accept()方法立即返回null,并不阻塞
  88.                 client = channel.accept();    
  89.                 if(client != null)
  90.                 {
  91.                     registerClient(client); // 注册客户信息
  92.                 }
  93.                 serviceClients();  // 为以连接的客户服务
  94.             }
  95.         } 
  96.         finally 
  97.         {
  98.             socket.close(); // 关闭socket,关闭socket会同时关闭与此socket关联的通道
  99.         }
  100.     }
  101.     public static void main(String[] args) throws IOException 
  102.     {
  103.         System.out.println("服务器启动");
  104.         SelectorServer server = new SelectorServer(SelectorServer.DEFAULT_SERVERPORT);
  105.         server.listen(); //服务器开始监听端口,提供服务
  106.         
  107.     }
  108. }

修改版本:

 
 
 
  1. package com.vista.Server;
  2. import java.io.BufferedWriter;
  3. import java.io.FileInputStream;
  4. import java.io.IOException;
  5. import java.io.OutputStreamWriter;
  6. import java.io.PrintWriter;
  7. import java.net.InetSocketAddress;
  8. import java.net.ServerSocket;
  9. import java.nio.ByteBuffer;
  10. import java.nio.CharBuffer;
  11. import java.nio.channels.FileChannel;
  12. import java.nio.channels.SelectionKey;
  13. import java.nio.channels.Selector;
  14. import java.nio.channels.ServerSocketChannel;
  15. import java.nio.channels.SocketChannel;
  16. import java.nio.charset.Charset;
  17. import java.nio.charset.CharsetDecoder;
  18. import java.util.Iterator;
  19. import java.util.LinkedList;
  20. import java.util.Set;
  21. public class SelectorServer 
  22. {
  23.     private static int DEFAULT_SERVERPORT = 6018;//默认端口
  24.     private static int DEFAULT_BUFFERSIZE = 1024;//默认缓冲区大小为1024字节
  25.     private static String DEFAULT_CHARSET = "GB2312";//默认码集
  26.     private static String DEFAULT_FILENAME = "bigfile.dat";
  27.     private ServerSocketChannel channel;
  28.     private LinkedList clients;
  29.     private Selector selector;//选择器
  30.     private ByteBuffer buffer;//字节缓冲区
  31.     private int port;
  32.     private Charset charset;//字符集
  33.     private CharsetDecoder decoder;//解码器
  34.     
  35.     
  36.     public SelectorServer(int port) throws IOException
  37.     {
  38.         this.port = port;
  39.         this.clients = new LinkedList();
  40.         this.channel = null;
  41.         this.selector = Selector.open();//打开选择器
  42.         this.buffer = ByteBuffer.allocate(DEFAULT_BUFFERSIZE);
  43.         this.charset = Charset.forName(DEFAULT_CHARSET);
  44.         this.decoder = this.charset.newDecoder();
  45.         
  46.     }
  47.     
  48.      private class HandleClient 
  49.      {
  50.          private String strGreeting = "welcome to VistaQQ";
  51.          public HandleClient() throws IOException 
  52.          {
  53.          }
  54.          public String readBlock() 
  55.          {//读块数据
  56.              return this.strGreeting;
  57.          }
  58.          public void close() 
  59.          {
  60.              
  61.          }
  62.     }
  63.     protected void handleKey(SelectionKey key) throws IOException
  64.     {//处理事件
  65.           if (key.isAcceptable()) 
  66.           { // 接收请求
  67.               ServerSocketChannel server = (ServerSocketChannel) key.channel();//取出对应的服务器通道
  68.               SocketChannel channel = server.accept();
  69.               channel.configureBlocking(false);
  70.               channel.register(selector, SelectionKey.OP_READ);//客户socket通道注册读操作
  71.           }
  72.           else if (key.isReadable()) 
  73.           { // 读信息
  74.               SocketChannel channel = (SocketChannel) key.channel();
  75.               int count = channel.read(this.buffer);
  76.               if (count > 0) 
  77.               {
  78.                 this.buffer.flip();
  79.                 CharBuffer charBuffer = decoder.decode(this.buffer);
  80.                 System.out.println("Client >>" + charBuffer.toString());
  81.                 SelectionKey wKey = channel.register(selector,
  82.                     SelectionKey.OP_WRITE);//为客户sockt通道注册写操作
  83.                 wKey.attach(new HandleClient());
  84.               } 
  85.               else
  86.               {//客户已经断开
  87.                 channel.close();
  88.               }
  89.               this.buffer.clear();//清空缓冲区
  90.          }
  91.          else if (key.isWritable()) 
  92.          { // 写事件
  93.               SocketChannel channel = (SocketChannel) key.channel();
  94.               HandleClient handle = (HandleClient) key.attachment();//取出处理者
  95.               ByteBuffer block = ByteBuffer.wrap(handle.readBlock().getBytes());
  96.               channel.write(block);
  97.              // channel.socket().getInputStream().(block);
  98. //              PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(
  99. //                        channel.socket().getOutputStream())), true);
  100. //              out.write(block.toString());
  101.         }
  102.     }
  103.     public void listen() throws IOException
  104.     { //服务器开始监听端口,提供服务
  105.         ServerSocket socket;
  106.         channel = ServerSocketChannel.open(); // 打开通道
  107.         socket = channel.socket();   //得到与通到相关的socket对象
  108.         socket.bind(new InetSocketAddress(port));   //将scoket榜定在制定的端口上
  109.         //配置通到使用非阻塞模式,在非阻塞模式下,可以编写多道程序同时避免使用复杂的多线程
  110.         channel.configureBlocking(false);    
  111.         channel.register(selector, SelectionKey.OP_ACCEPT);
  112.         try 
  113.         {
  114.             while(true) 
  115.             {//     与通常的程序不同,这里使用channel.accpet()接受客户端连接请求,而不是在socket对象上调用accept(),这里在调用accept()方法时如果通道配置为非阻塞模式,那么accept()方法立即返回null,并不阻塞
  116.                 this.selector.select();
  117.                 Iterator iter = this.selector.selectedKeys().iterator();
  118.                 while(iter.hasNext())
  119.                 {
  120.                     SelectionKey key = (SelectionKey)iter.next();
  121.                     iter.remove();
  122.                     this.handleKey(key);
  123.                     
  124.                 }
  125.             }
  126.         } 
  127.         catch(IOException ex)
  128.         {
  129.             ex.printStackTrace();
  130.         }
  131.     }
  132.     public static void main(String[] args) throws IOException 
  133.     {
  134.         System.out.println("服务器启动");
  135.         SelectorServer server = new SelectorServer(SelectorServer.DEFAULT_SERVERPORT);
  136.         server.listen(); //服务器开始监听端口,提供服务
  137.     }
  138. }

本文题目:JavaNIO非阻塞服务器示例
URL标题:http://www.hantingmc.com/qtweb/news13/3663.html

网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等

广告

声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联