java nio SocketChannel 服务器端与多客户端 信息交互(聊天功能)

来源:互联网 发布:淘宝搜索规则 编辑:程序博客网 时间:2024/05/17 12:48

java nio SocketChannel 服务器端与多客户端 信息交互(聊天功能)

服务器端:
Java代码 :
  1. import java.io.IOException; 
  2. import java.net.InetSocketAddress; 
  3. import java.net.ServerSocket; 
  4. import java.net.Socket; 
  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.nio.charset.Charset; 
  11. import java.util.HashMap; 
  12. import java.util.Map; 
  13. import java.util.Set; 
  14.  
  15. public class NIOSServer { 
  16.     private int port =8888
  17.     //解码buffer 
  18.     private Charset cs = Charset.forName("gbk"); 
  19.     /*接受数据缓冲区*/ 
  20.     private static ByteBuffer sBuffer = ByteBuffer.allocate(1024); 
  21.     /*发送数据缓冲区*/ 
  22.     private static ByteBuffer rBuffer = ByteBuffer.allocate(1024); 
  23.     /*映射客户端channel */ 
  24.     private Map<String, SocketChannel> clientsMap =new HashMap<String, SocketChannel>(); 
  25.     private static Selector selector; 
  26.      
  27.     public NIOSServer(int port){ 
  28.         this.port = port; 
  29.         try
  30.             init(); 
  31.         } catch (Exception e) { 
  32.             e.printStackTrace(); 
  33.         } 
  34.     } 
  35.     private void init()throws IOException{ 
  36.         /*
  37.          *启动服务器端,配置为非阻塞,绑定端口,注册accept事件
  38.          *ACCEPT事件:当服务端收到客户端连接请求时,触发该事件
  39.          */ 
  40.         ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); 
  41.         serverSocketChannel.configureBlocking(false); 
  42.         ServerSocket serverSocket = serverSocketChannel.socket(); 
  43.         serverSocket.bind(new InetSocketAddress(port)); 
  44.         selector = Selector.open(); 
  45.         serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); 
  46.         System.out.println("server start on port:"+port); 
  47.     } 
  48.     /**
  49.      * 服务器端轮询监听,select方法会一直阻塞直到有相关事件发生或超时
  50.      */ 
  51.     private void listen(){ 
  52.         while (true) { 
  53.             try
  54.                 selector.select();//返回值为本次触发的事件数 
  55.                 Set<SelectionKey> selectionKeys = selector.selectedKeys(); 
  56.                 for(SelectionKey key : selectionKeys){ 
  57.                     handle(key); 
  58.                 } 
  59.                 selectionKeys.clear();//清除处理过的事件 
  60.             } catch (Exception e) { 
  61.                 e.printStackTrace(); 
  62.                 break
  63.             } 
  64.              
  65.         } 
  66.     } 
  67.     /**
  68.      * 处理不同的事件
  69.     */ 
  70.     private void handle(SelectionKey selectionKey)throws IOException { 
  71.         ServerSocketChannel server = null
  72.         SocketChannel client = null
  73.         String receiveText=null
  74.         int count=0
  75.         if (selectionKey.isAcceptable()) { 
  76.             /*
  77.              * 客户端请求连接事件
  78.              * serversocket为该客户端建立socket连接,将此socket注册READ事件,监听客户端输入
  79.              * READ事件:当客户端发来数据,并已被服务器控制线程正确读取时,触发该事件
  80.              */ 
  81.             server = (ServerSocketChannel) selectionKey.channel(); 
  82.             client = server.accept(); 
  83.             client.configureBlocking(false); 
  84.             client.register(selector, SelectionKey.OP_READ); 
  85.         } else if (selectionKey.isReadable()) { 
  86.             /*
  87.              * READ事件,收到客户端发送数据,读取数据后继续注册监听客户端
  88.              */ 
  89.             client = (SocketChannel) selectionKey.channel(); 
  90.             rBuffer.clear(); 
  91.             count = client.read(rBuffer); 
  92.             if (count > 0) { 
  93.                 rBuffer.flip(); 
  94.                 receiveText = String.valueOf(cs.decode(rBuffer).array()); 
  95.                 System.out.println(client.toString()+":"+receiveText); 
  96.                 dispatch(client, receiveText); 
  97.                 client = (SocketChannel) selectionKey.channel(); 
  98.                 client.register(selector, SelectionKey.OP_READ); 
  99.             } 
  100.         }  
  101.     } 
  102.      
  103.     /**
  104.      * 把当前客户端信息 推送到其他客户端
  105.      */ 
  106.     private void dispatch(SocketChannel client,String info)throws IOException{ 
  107.         Socket s = client.socket(); 
  108.         String name = "["+s.getInetAddress().toString().substring(1)+":"+Integer.toHexString(client.hashCode())+"]"; 
  109.         if(!clientsMap.isEmpty()){ 
  110.             for(Map.Entry<String, SocketChannel> entry : clientsMap.entrySet()){ 
  111.                 SocketChannel temp = entry.getValue(); 
  112.                 if(!client.equals(temp)){ 
  113.                     sBuffer.clear(); 
  114.                     sBuffer.put((name+":"+info).getBytes()); 
  115.                     sBuffer.flip(); 
  116.                     //输出到通道 
  117.                     temp.write(sBuffer); 
  118.                 } 
  119.             } 
  120.         } 
  121.         clientsMap.put(name, client); 
  122.     } 
  123.     public staticvoid main(String[] args) throws IOException { 
  124.         NIOSServer server = new NIOSServer(7777); 
  125.         server.listen(); 
  126.     } 
客户端,可运行启动多个:
Java代码: 
  1. import java.io.BufferedReader; 
  2. import java.io.IOException; 
  3. import java.io.InputStreamReader; 
  4. import java.net.InetSocketAddress; 
  5. import java.nio.ByteBuffer; 
  6. import java.nio.channels.SelectionKey; 
  7. import java.nio.channels.Selector; 
  8. import java.nio.channels.SocketChannel; 
  9. import java.util.Date; 
  10. import java.util.Set; 
  11.  
  12. public class NIOClient { 
  13.     /*发送数据缓冲区*/ 
  14.     private static ByteBuffer sBuffer = ByteBuffer.allocate(1024); 
  15.     /*接受数据缓冲区*/ 
  16.     private static ByteBuffer rBuffer = ByteBuffer.allocate(1024); 
  17.     /*服务器端地址*/ 
  18.     private InetSocketAddress SERVER; 
  19.     private static Selector selector; 
  20.     private static SocketChannel client; 
  21.     private static String receiveText; 
  22.     private static String sendText; 
  23.     private staticint count=0
  24.      
  25.     public NIOClient(int port){ 
  26.         SERVER = new InetSocketAddress("localhost", port); 
  27.         init(); 
  28.     } 
  29.     public void init(){ 
  30.         try
  31.            /*
  32.              * 客户端向服务器端发起建立连接请求
  33.              */ 
  34.             SocketChannel socketChannel = SocketChannel.open(); 
  35.             socketChannel.configureBlocking(false); 
  36.             selector = Selector.open(); 
  37.             socketChannel.register(selector, SelectionKey.OP_CONNECT); 
  38.             socketChannel.connect(SERVER); 
  39.             /*
  40.              * 轮询监听客户端上注册事件的发生
  41.              */ 
  42.             while (true) { 
  43.                 selector.select(); 
  44.                 Set<SelectionKey> keySet = selector.selectedKeys(); 
  45.                 for(final SelectionKey key : keySet){ 
  46.                     handle(key); 
  47.                 }; 
  48.                 keySet.clear(); 
  49.             } 
  50.         } catch (Exception e) { 
  51.             e.printStackTrace(); 
  52.         } 
  53.     } 
  54.     public staticvoid main(String[] args) throws IOException { 
  55.         NIOClient client = new NIOClient(7777); 
  56.     } 
  57.      
  58.     private void handle(SelectionKey selectionKey)throws IOException{ 
  59.         if (selectionKey.isConnectable()) { 
  60.             /*
  61.              * 连接建立事件,已成功连接至服务器
  62.              */ 
  63.             client = (SocketChannel) selectionKey.channel(); 
  64.             if (client.isConnectionPending()) { 
  65.                 client.finishConnect(); 
  66.                 System.out.println("connect success !"); 
  67.                 sBuffer.clear(); 
  68.                 sBuffer.put((new Date().toLocaleString()+" connected!").getBytes()); 
  69.                 sBuffer.flip(); 
  70.                 client.write(sBuffer);//发送信息至服务器 
  71.                 /* 原文来自站长网
  72.                  * 启动线程一直监听客户端输入,有信心输入则发往服务器端
  73.                  * 因为输入流是阻塞的,所以单独线程监听
  74.                  */ 
  75.                 new Thread(){ 
  76.                     @Override 
  77.                     public void run() { 
  78.                         while(true){ 
  79.                             try
  80.                                 sBuffer.clear(); 
  81.                                 InputStreamReader input = new InputStreamReader(System.in); 
  82.                                 BufferedReader br = new BufferedReader(input); 
  83.                                 sendText = br.readLine(); 
  84.                                 /*
  85.                                  * 未注册WRITE事件,因为大部分时间channel都是可以写的
  86.                                  */ 
  87.                                 sBuffer.put(sendText.getBytes()); 
  88.                                 sBuffer.flip(); 
  89.                                 client.write(sBuffer); 
  90.                             } catch (IOException e) { 
  91.                                 e.printStackTrace(); 
  92.                                 break
  93.                             } 
  94.                       } 
  95.                     }; 
  96.                 }.start(); 
  97.             } 
  98.             //注册读事件 
  99.             client.register(selector, SelectionKey.OP_READ); 
  100.         } else if (selectionKey.isReadable()) { 
  101.             /*
  102.              * 读事件触发
  103.              * 有从服务器端发送过来的信息,读取输出到屏幕上后,继续注册读事件
  104.              * 监听服务器端发送信息
  105.              */ 
  106.             client = (SocketChannel) selectionKey.channel(); 
  107.             rBuffer.clear(); 
  108.             count=client.read(rBuffer); 
  109.             if(count>0){ 
  110.                 receiveText = new String( rBuffer.array(),0,count); 
  111.                 System.out.println(receiveText); 
  112.                 client = (SocketChannel) selectionKey.channel(); 
  113.                 client.register(selector, SelectionKey.OP_READ); 
  114.             } 
  115.         }  
  116.     } 
  117. }  原文来自java教程网 http://www.software8.co/wzjs/java/   欢迎java爱好者前来投稿
原创粉丝点击