Nio 实现多人聊天

1.服务器端

  1 package nio;
  2 
  3 import java.io.IOException;
  4 import java.net.InetSocketAddress;
  5 import java.nio.ByteBuffer;
  6 import java.nio.channels.*;
  7 import java.security.PublicKey;
  8 import java.util.Iterator;
  9 
 10 /**
 11  * Nio 聊天服务器
 12  */
 13 public class GroupChatServer {
 14     private Selector selector;
 15     private ServerSocketChannel serverSocketChannel;
 16     private  static  final  int port=9000;
 17     /**
 18      * 构造方法
 19      * 初始化工作
 20      */
 21     public  GroupChatServer(){
 22     try{
 23         //得到选择器
 24         selector =Selector.open();
 25         //初始化 serverSocketChannel
 26         serverSocketChannel=ServerSocketChannel.open();
 27         //绑定端口
 28         serverSocketChannel.socket().bind(new InetSocketAddress(port));
 29         //设置非阻塞模式
 30         serverSocketChannel.configureBlocking(false);
 31         //将serverSocketChannel 注册到selector上
 32         serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
 33 
 34 
 35     }catch (IOException e){
 36         e.printStackTrace();
 37     }
 38     }
 39     //监听
 40     public void listen(){
 41         try{
 42             while (true){//查询连接
 43                 int count = selector.select();
 44                 if(count>0){
 45                     //有事件处理
 46                     //得到连接集合遍历
 47                     Iterator<SelectionKey> keys = selector.selectedKeys().iterator();
 48                     SelectionKey selectionKey;
 49                     while (keys.hasNext()){
 50                          selectionKey = keys.next();
 51                          //如果监听到accept
 52                          if(selectionKey.isAcceptable()){
 53                              SocketChannel sc = serverSocketChannel.accept();
 54                              sc.configureBlocking(false);
 55                              //将该 sc注册到selector
 56                              sc.register(selector,SelectionKey.OP_READ);
 57                             //提示
 58                              System.out.println(sc.getRemoteAddress().toString().substring(1)+"上线");
 59                          }
 60                          if(selectionKey.isReadable()){
 61                              //如果通道时可读事件
 62                              readData(selectionKey);
 63                          }
 64                          //删除当前key,防止重复
 65                         keys.remove();
 66                     }
 67 
 68                 }else {
 69                     System.out.println("等待客户端连接中。。。。");
 70                 }
 71             }
 72 
 73         }catch (Exception e){
 74             e.printStackTrace();
 75         }finally {
 76 
 77         }
 78     }
 79     //读取客户端消息
 80     private void readData(SelectionKey ky){
 81         //定义 SocketChannel
 82         SocketChannel socketChannel=null;
 83         try{
 84             socketChannel=(SocketChannel)ky.channel();
 85             //创建buffer
 86             ByteBuffer buffer=ByteBuffer.allocate(1024);
 87             int len = socketChannel.read(buffer);
 88             if(len>0){
 89                 //读取到了数据
 90                 String s = new String(buffer.array());
 91                 System.out.println("客户端:"+s);
 92                 //向其他客户端转发消息
 93                 sendMsgToOtherClients(s,socketChannel);
 94             }
 95         }catch (IOException e){
 96             try {
 97                 System.out.println(socketChannel.getRemoteAddress() + "离线了。。。");
 98                 //取消注册
 99                 ky.cancel();
100                 //关闭通道
101                 socketChannel.close();
102             }catch (IOException e1){
103                 e1.printStackTrace();
104             }
105         }
106     }
107     //转发消息给其他客户端(通道)
108     private  void sendMsgToOtherClients(String msg,SocketChannel client) throws  IOException{
109         System.out.println("服务器转发消息");
110         //遍历所有注册到select上的SocketChannel ,并排除自己
111         for (SelectionKey k:selector.keys()){
112             //通过key取出对应的
113             //这里可以不用强转为 SocketChannel
114         Channel tarChannel = k.channel();
115          //   SocketChannel tarChannel =(SocketChannel) k.channel();
116             //排除自己
117             if(tarChannel instanceof SocketChannel&&tarChannel!=client){
118                 //转型
119                 SocketChannel  dest=(SocketChannel)tarChannel;
120                 //将信息msg存储到buffer
121                 ByteBuffer buffer = ByteBuffer.wrap(msg.getBytes());
122                 //将buffer写入通道中
123                 dest.write(buffer);
124             }
125         }
126     }
127     public static void main(String[] args) {
128         GroupChatServer groupChatServer=new GroupChatServer();
129         groupChatServer.listen();
130     }
131 }

2.客户端

 1 package nio;
 2 
 3 import com.sun.org.apache.xerces.internal.util.SynchronizedSymbolTable;
 4 
 5 import java.io.IOException;
 6 import java.net.InetSocketAddress;
 7 import java.nio.ByteBuffer;
 8 import java.nio.channels.SelectableChannel;
 9 import java.nio.channels.SelectionKey;
10 import java.nio.channels.Selector;
11 import java.nio.channels.SocketChannel;
12 import java.util.Iterator;
13 import java.util.Scanner;
14 
15 /**
16  * Nio 客户端
17  */
18 public class GroupChatClient {
19     private final  String IP="127.0.0.1";
20     private final  int port=9000;
21     private Selector selector;
22     private SocketChannel socketChannel;
23     private  String userName;
24     public  GroupChatClient() throws IOException {
25         selector=Selector.open();
26         //连接服务器
27         socketChannel=socketChannel.open(new InetSocketAddress(IP,port));
28         //设置非阻塞
29         socketChannel.configureBlocking(false);
30         //注册
31         socketChannel.register(selector, SelectionKey.OP_READ);
32         userName = socketChannel.getLocalAddress().toString().substring(1);
33         System.out.println("客户端 "+userName+" 准备好了");
34     }
35     //向服务器发送消息
36     public  void  sendMsg(String msg) throws IOException {
37         msg=userName+"说:"+msg;
38         socketChannel.write(ByteBuffer.wrap(msg.getBytes()));
39     }
40     //读取从服务器端发送过来的消息
41     public  void  readMsg() throws IOException {
42         int readChannel = selector.select();
43         if(readChannel>0){
44             //有可用的通道
45             Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
46             while (iterator.hasNext()){
47                 SelectionKey k = iterator.next();
48                 if(k.isReadable()){
49                     //得到相关的通道了
50                     SocketChannel channel = (SocketChannel)k.channel();
51                     ByteBuffer buffer = ByteBuffer.allocate(1024);
52                     channel.read(buffer);
53                     //把独到的缓冲区的数据转为字符串
54                     System.out.println(new String(buffer.array()).trim());
55 
56                 }
57 
58             }
59 
60             iterator.remove();// 删除当前的key防止重复操作
61         }else {
62             System.out.println("没有可用的通道。。。。");
63         }
64 
65     }
66     public static void main(String[] args) throws IOException {
67         //启动客户端
68         GroupChatClient chatClient=new GroupChatClient();
69         //启动一个线程
70         new Thread(new Runnable() {
71             @Override
72             public void run() {
73                 while (true){
74                     try {
75                         chatClient.readMsg();
76                         Thread.currentThread().sleep(1000);
77                     } catch (IOException e){
78                         e.printStackTrace();
79                     }catch (InterruptedException e1 ) {
80                         e1.printStackTrace();
81                     }
82                 }
83             }
84         }).start();
85         //发送数据给服务器
86         Scanner scanner = new Scanner(System.in);
87         while (scanner.hasNextLine()){
88             chatClient.sendMsg(scanner.nextLine());
89         }
90 
91     }
92 }

运行效果

 

posted @ 2019-12-03 19:41  Angry-rookie  阅读(237)  评论(0)    收藏  举报