java基于NIO如何实现群聊模式
这篇文章将为大家详细讲解有关java基于NIO如何实现群聊模式,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。
具体内容如下
Client
package com.qst.chat;import java.io.IOException;import java.net.InetSocketAddress;import java.nio.ByteBuffer;import java.nio.channels.SelectionKey;import java.nio.channels.Selector;import java.nio.channels.SocketChannel;import java.util.Iterator;import java.util.Scanner;public class GroupChatClient { private final int PORT = 9999; private final String HOST = "localhost"; private SocketChannel channel; private static Selector selector; private String name; public GroupChatClient() throws IOException { selector = Selector.open(); // 连接服务器 channel = SocketChannel.open(new InetSocketAddress(HOST, PORT)); // 设置非阻塞 channel.configureBlocking(false); // 将channel 注册到selector channel.register(selector, SelectionKey.OP_READ); name = channel.getLocalAddress().toString().substring(1); System.out.println(name + "is ok ...."); } // 向服务器发送消息 public void sendTO(String msg) { ByteBuffer buffer = ByteBuffer.wrap((name+":"+msg).getBytes()); try { channel.write(buffer); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } // 读取从服务器端回复的消息 public static void getInfo() { try { if(selector.select() >0) { Iterator<SelectionKey> iterator = selector.selectedKeys().iterator(); while(iterator.hasNext()) { SelectionKey key = iterator.next(); if(key.isReadable()) { // 得到通道 SocketChannel sc = (SocketChannel) key.channel(); ByteBuffer buffer = ByteBuffer.allocate(1024); int len; // 把读到的缓冲区的数据转成字符串 while((len = sc.read(buffer)) > 0) { System.out.println(new String(buffer.array())); } } } // 删除当前的selectionKey, 防止重复操作 iterator.remove(); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static void main(String[] args) { try { GroupChatClient client = new GroupChatClient(); new Thread() { public void run() { while(true) { try { Thread.sleep(3000); GroupChatClient.getInfo(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }; }.start(); Scanner sc = new Scanner(System.in);// while(true) {// String name = sc.nextLine();// client.sendTO(name);// } while(sc.hasNextLine()) { String s = sc.nextLine(); client.sendTO(s); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } }}
Server端
package com.qst.chat;import java.io.IOException;import java.net.InetAddress;import java.net.InetSocketAddress;import java.net.ServerSocket;import java.net.Socket;import java.nio.ByteBuffer;import java.nio.channels.SelectableChannel;import java.nio.channels.SelectionKey;import java.nio.channels.Selector;import java.nio.channels.ServerSocketChannel;import java.nio.channels.SocketChannel;import java.time.chrono.IsoChronology;import java.util.Iterator;import com.sun.accessibility.internal.resources.accessibility;import sun.print.resources.serviceui;public class GroupChatServer { private static ServerSocketChannel socketChannel; private static Socket socket; private static Selector selector; private static SocketChannel accept; public GroupChatServer() throws IOException { socketChannel = ServerSocketChannel.open(); selector = Selector.open(); // 绑定端口 socketChannel.socket().bind(new InetSocketAddress(9999)); // 设置非阻塞模式 socketChannel.configureBlocking(false); // 将该通道 注册到selector socketChannel.register(selector, SelectionKey.OP_ACCEPT); } // 监听 public static void listen() { System.out.println("监听线程: " + Thread.currentThread().getName()); try { while (selector.select() > 0) { Iterator<SelectionKey> iterator = selector.selectedKeys().iterator(); if (iterator.hasNext()) { // 遍历得到selectionKey 集合 SelectionKey next = iterator.next(); if (next.isAcceptable()) { next.channel(); // socketChannel = (ServerSocketChannel) next.channel(); SocketChannel accept = socketChannel.accept(); accept.configureBlocking(false); accept.register(selector, SelectionKey.OP_READ); System.out.println(accept.getRemoteAddress()+" 上线 了。。。"); } if (next.isReadable()) { readDate(next); } // 移除当前的next,防止重复处理 iterator.remove(); // System.out.println("未发现"); } } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } // 读取客户端消息 public static void readDate(SelectionKey key) { try { accept = (SocketChannel) key.channel(); ByteBuffer buffer = ByteBuffer.allocate(1024); int len = accept.read(buffer); if (len > 0) { buffer.flip(); String msg = new String(buffer.array()); System.out.println("user = " + msg); // 向其它的客户端转发消息(去掉自己) sendToAll(msg, accept); buffer.clear(); } } catch (IOException e) { // TODO Auto-generated catch block try { String msg = accept.getRemoteAddress().toString(); // 取消注册 key.cancel(); // 关闭通道 accept.close(); System.out.println(msg + "离线了"); } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } // e.printStackTrace(); } finally { // TODO: handle finally clause } } public static void sendToAll(String msg, SocketChannel ssc) { for (SelectionKey ss : selector.keys()) { // 通过 key 取出对应的 SocketChannel SelectableChannel channel = ss.channel(); // 排除自己 if (channel instanceof SocketChannel && channel != ssc) { // 转型 SocketChannel sh = (SocketChannel) channel; // 转存到buffer ByteBuffer wrap = ByteBuffer.wrap(msg.getBytes()); try { // 写入通道 sh.write(wrap); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } public static void main(String[] args) throws IOException { GroupChatServer server = new GroupChatServer(); GroupChatServer.listen(); }}
key.isAcceptable()进行接入 操作的时候, 获取通道有两种方式
通过selector获取 (Selector key) socketChannel = (ServerSocketChannel) key.channel();
建立连接 socketChannel .accept();
定义一个全局变量
在进行初始化的时候,存储(socketChannel = ServerSocketChannel.open();)
建立连接 socketChannel .accept();
key.isReadable() 当进行到读入操作的时候( ) SelectionKey key accept = (SocketChannel) key.channel();
演示
服务器启动,客户端启动
客户端发送消息
启动第二个客户端
两个客户端相互通信
离线信息显示
关于“java基于NIO如何实现群聊模式”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341