nio 代码实现简易多人聊天

这几天在学习nio相关知识。实现了一个简单的多人聊天程序。

服务端代码;

  1 import java.io.IOException;
  2 import java.net.InetSocketAddress;
  3 import java.nio.ByteBuffer;
  4 import java.nio.channels.*;
  5 import java.nio.charset.Charset;
  6 import java.util.*;
  7 
  8 /**
  9  * @ClassName CharRoomServer
 10  * @Description TODO
 11  * @Author hufeng8
 12  * @Date 2018/8/3 14:39
 13  * @Version 1.0
 14  */
 15 public class CharRoomServer implements Runnable{
 16 
 17     private ServerSocketChannel serverSocketChannel = null;
 18 
 19     private Selector selector = null;
 20 
 21     public static final int PORT_NUM = 1198;
 22 
 23     private boolean active = true;
 24 
 25     private Charset charset = Charset.forName("UTF-8");
 26 
 27     private List<String> users  = new ArrayList<String>();
 28 
 29     private ByteBuffer byteBuffer = ByteBuffer.allocate(2*1024);
 30 
 31     public static final String protocol = "#user#";
 32 
 33     public CharRoomServer() {
 34         this.init();
 35     }
 36 
 37     public void init() {
 38         try {
 39             selector = Selector.open();
 40             serverSocketChannel = ServerSocketChannel.open();
 41             serverSocketChannel.socket().bind(new InetSocketAddress(PORT_NUM));
 42             serverSocketChannel.configureBlocking(false);
 43             serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
 44         } catch (IOException e) {
 45             e.printStackTrace();
 46         }
 47     }
 48 
 49     public void run() {
 50         System.out.println("开始监听。。。。");
 51         while (active) {
 52             try {
 53                 //非阻塞接受连接
 54 //                int s = selector.selectNow();
 55 
 56                 //阻塞连接
 57                 int s = selector.select();
 58 
 59                 System.out.println("服务端接受到连接总数"+selector.keys().size());
 60             } catch (IOException e) {
 61                 e.printStackTrace();
 62             }
 63             System.out.println("服务端接受到的选择连接数"+selector.selectedKeys().size());
 64             Iterator<SelectionKey> keys = selector.selectedKeys().iterator();
 65             while (keys.hasNext()) {
 66                 SelectionKey k = keys.next();
 67                 keys.remove();
 68                 //处理逻辑
 69                 doHandler(selector, k);
 70             }
 71         }
 72     }
 73 
 74     private void doHandler(Selector selector, SelectionKey k) {
 75         try {
 76             //连接事件
 77             if (k.isConnectable()) {
 78                 System.out.println("Connectable 连接事件");
 79             } else if (k.isAcceptable()) {
 80                 ServerSocketChannel ser = (ServerSocketChannel) k.channel();
 81                 if (ser == serverSocketChannel) {
 82                     System.out.println("同一个连接");
 83                 }
 84                 SocketChannel socketChannel = ser.accept();
 85                 socketChannel.configureBlocking(false);
 86                 socketChannel.register(selector, SelectionKey.OP_READ);
 87                 socketChannel.write(charset.encode("please enter login name:"));
 88 
 89                 //设置k为接受事件,准备接受其它请求?
 90 
 91             } else if (k.isReadable()) {
 92                 //获取客户端连接
 93                 SocketChannel socketChannel = (SocketChannel) k.channel();
 94                 StringBuffer content = new StringBuffer();
 95                 int sum = 0;
 96                 try {
 97                     byteBuffer.clear();
 98                     while ((sum = socketChannel.read(byteBuffer)) > 0) {
 99                         byteBuffer.flip();
100                         content.append(charset.decode(byteBuffer));
101                     }
102                     System.out.println(sum);
103                     //判断客户端连接关闭
104                     if (sum == -1) {
105                         socketChannel.close();
106                         System.out.println("1--关闭连接");
107                     }
108 
109                     System.out.println("服务端:监听:"+ content.toString());
110                 } catch (Exception e) {
111                     System.out.println("2--关闭连接");
112                     k.cancel();
113                     if (null != socketChannel) {
114                         socketChannel.close();
115                     }
116                 }
117                 if (content.length() > 0) {
118                     //按照协议切分内容
119                     String[] contents = content.toString().split(protocol);
120                     //登陆用户
121                     if (contents != null && contents.length == 1) {
122                         String user = contents[0];
123                         if (users.contains(user)) {
124                             socketChannel.write(charset.encode("登陆用户已存在!"));
125                         } else {
126                             users.add(user);
127                             //获取在线人数
128                             int i = onlineCount(selector);
129                             //广播登陆消息给当前房间所有人
130                             brokerMessage(selector, k, "欢迎"+user+"登陆,当前第"+i+"号");
131                         }
132                     } else if (contents != null && contents.length > 1) {
133                         String message = contents[0] + "say :" + contents[1];
134                         brokerMessage(selector, k, message);
135                     }
136                 }
137             } else if (k.isWritable()) {
138 
139             }
140         } catch (Exception e) {
141             e.printStackTrace();
142         }
143     }
144 
145     /**
146      * 广播消息
147      * @param content
148      */
149     private void brokerMessage(Selector selector, SelectionKey k, String content) {
150         for (SelectionKey key : selector.keys()) {
151             if (key.channel() instanceof SocketChannel && key != k) {
152                 try {
153                     SocketChannel sc = (SocketChannel) key.channel();
154                     sc.write(charset.encode(content));
155                 } catch (IOException e1) {
156                     e1.printStackTrace();
157                 }
158             }
159         }
160     }
161 
162     /**
163      * 统计在线人数
164      * @param selector
165      * @return
166      */
167     private int onlineCount(Selector selector) {
168 
169         return 0;
170     }
171 
172     public static void main(String[] args) {
173         System.out.println("开始启动服务");
174         new Thread(new CharRoomServer()).start();
175         System.out.println("服务启动");
176     }
177 }
View Code

客户端代码;

  1 import java.io.IOException;
  2 import java.net.InetSocketAddress;
  3 import java.nio.ByteBuffer;
  4 import java.nio.channels.SelectionKey;
  5 import java.nio.channels.Selector;
  6 import java.nio.channels.SocketChannel;
  7 import java.nio.charset.Charset;
  8 import java.util.Iterator;
  9 import java.util.Scanner;
 10 
 11 /**
 12  * @ClassName ChatRoomClient
 13  * @Description TODO
 14  * @Author hufeng8
 15  * @Date 2018/8/3 16:37
 16  * @Version 1.0
 17  */
 18 public class ChatRoomClient implements Runnable{
 19 
 20 
 21     private SocketChannel channel;
 22     private Selector selector;
 23     private boolean active = true;
 24     private Charset charset = Charset.forName("UTF-8");
 25 
 26     private String name = "";
 27 
 28     public ChatRoomClient() {
 29 
 30         try {
 31             selector = Selector.open();
 32             channel = SocketChannel.open(new InetSocketAddress("localhost",CharRoomServer.PORT_NUM));
 33             channel.configureBlocking(false);
 34             channel.register(selector, SelectionKey.OP_CONNECT|SelectionKey.OP_READ);
 35 
 36         } catch (IOException e) {
 37             e.printStackTrace();
 38         }
 39     }
 40 
 41     public void run() {
 42         System.out.println("客户端监听开始:");
 43         while (active) {
 44             try {
 45                 selector.select();
 46             } catch (IOException e) {
 47                 e.printStackTrace();
 48             }
 49 //            System.out.println(selector.selectedKeys().size());
 50             Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
 51             while (iterator.hasNext()) {
 52                 SelectionKey next = iterator.next();
 53                 iterator.remove();
 54                 if (channel == next.channel()) {
 55 //                    System.out.println("同一个对象");
 56                 }
 57 //                System.out.println("channel:"+channel+", sockchannel"+next.channel()+"连接事件:"+next.isConnectable()+", "+next.isReadable()+", "+next.isWritable());
 58                 if (next.isConnectable()) {
 59                     try {
 60                         System.out.println("客户端连接事件");
 61                         SocketChannel sc = (SocketChannel) next.channel();
 62                         sc.configureBlocking(false);
 63                         sc.register(selector, SelectionKey.OP_READ);
 64                     } catch (IOException e) {
 65                         e.printStackTrace();
 66                     }
 67                 } else if (next.isWritable()) {
 68                     System.out.println("客户端写事件");
 69                 } else if (next.isReadable()) {
 70                     SocketChannel sc = (SocketChannel) next.channel();
 71                     if (channel == sc) {
 72                         System.out.println("同一个对象");
 73                     }
 74                     System.out.println("客户端读取事件");
 75                     ByteBuffer bf = ByteBuffer.allocate(2*1024);
 76                     int i = 0;
 77                     StringBuffer content = new StringBuffer();
 78                     try {
 79                         while ((i = sc.read(bf)) > 0) {
 80                             bf.flip();
 81                             content.append(charset.decode(bf));
 82                         }
 83                         System.out.println(content.toString());
 84 //                        next.interestOps(SelectionKey.OP_READ);
 85                     } catch (IOException e) {
 86                         e.printStackTrace();
 87                         next.cancel();
 88                         if (sc != null) {
 89                             try {
 90                                 sc.close();
 91                             } catch (IOException e1) {
 92                                 e1.printStackTrace();
 93                             }
 94                         }
 95                     }
 96                 }
 97             }
 98         }
 99     }
100 
101     public SocketChannel getChannel() {
102         return channel;
103     }
104 
105     public String getName() {
106         return name;
107     }
108 
109     public void setName(String name) {
110         this.name = name;
111     }
112 
113     public Charset getCharset() {
114         return charset;
115     }
116 
117     public void setCharset(Charset charset) {
118         this.charset = charset;
119     }
120 
121     public static void main(String[] args) {
122         ChatRoomClient chatRoomClient = new ChatRoomClient();
123         new Thread(chatRoomClient).start();
124         String name = chatRoomClient.getName();
125         SocketChannel sc = chatRoomClient.getChannel();
126         Charset charset = chatRoomClient.getCharset();
127         System.out.println("请输入:");
128         Scanner scan = new Scanner(System.in);
129         while (scan.hasNextLine()) {
130             String data = scan.next();
131             if ("".equals(data)) {
132                 continue;
133             } else if ("".equals(name)) {
134                 name = data;
135                 data = name + CharRoomServer.protocol;
136             } else {
137                 data = name + CharRoomServer.protocol + data;
138             }
139             try {
140                 sc.write(charset.encode(data));
141             } catch (IOException e) {
142 
143             }
144         }
145 
146     }
147 }
View Code

posted @ 2018-09-05 14:56  Program_青菜  阅读(685)  评论(0编辑  收藏  举报