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 }
运行效果



浙公网安备 33010602011771号