博客
关于我
JAVA-NIO实现聊天室详细代码说明
阅读量:301 次
发布时间:2019-03-01

本文共 7237 字,大约阅读时间需要 24 分钟。

服务端

github源码:https://github.com/JolyouLu/JAVAIO.git

src\main\java\com\JolyouLu\nio\groupchat 文件夹下

public class GroupChatServer {       //定义属性    private Selector selector;    private ServerSocketChannel listenChannel;    private static final int PORT = 6666;    //构造器 完成初始化工作    public GroupChatServer() {           try {               //得到选择器            selector = Selector.open();            //初始化ServerSocketChannel            listenChannel = ServerSocketChannel.open();            //绑定端口            listenChannel.socket().bind(new InetSocketAddress(PORT));            //设置非阻塞模式            listenChannel.configureBlocking(false);            //将来listenChannel注册到Selector            listenChannel.register(selector, SelectionKey.OP_ACCEPT);        }catch (IOException e){               e.printStackTrace();        }    }    //监听    public void listen(){           try {               //循环监听            while (true){                   int count = selector.select(2000); //阻塞2秒监听,通道有没有事件发生                if (count > 0){    //返回>0 有事件要处理                    //遍历selectedKeys集合                    Iterator
iterator = selector.selectedKeys().iterator(); while (iterator.hasNext()){ //获取SelectionKey SelectionKey key = iterator.next(); if (key.isAcceptable()){ //如果通道发生,客户端连接事件 //为连接的客户端,生成socketChannel SocketChannel socketChannel = listenChannel.accept(); //切换非阻塞模式 socketChannel.configureBlocking(false); //把socketChannel注册到selector中,并监听读事件 socketChannel.register(selector,SelectionKey.OP_READ); //提示客户端连接上了 System.out.println(socketChannel.getRemoteAddress() + " 客户端 上线"); } if (key.isReadable()){ //如果通道发生,可读事件 //处理读 readData(key); } //清理读取的selectedKeys容器 防止重复处理 iterator.remove(); } } } }catch (Exception e){ e.printStackTrace(); }finally { } } //读取客户端消息 private void readData(SelectionKey key){ //定义一个SocketChannel SocketChannel channel = null; try { //取到关联的channel channel = (SocketChannel) key.channel(); //创建buffer ByteBuffer buffer = ByteBuffer.allocate(1024); int count = channel.read(buffer); //根据count的值做处理 if (count > 0){ //读取到数据 //把缓冲区的数据转字符串 String msg = new String(buffer.array(), "GBK"); //输出消息 System.out.println("from 客户端:"+ msg); //向其它客户端转发消息 sendInfoToOtherClients(msg,channel); } }catch (IOException e){ try { System.out.println(channel.getRemoteAddress() + " 离线了.."); //取消注册 key.cancel(); //关闭通道 channel.close(); } catch (IOException ioException) { ioException.printStackTrace(); } } } //转发消息给其它客户端(channel) private void sendInfoToOtherClients(String msg,SocketChannel self) throws IOException { System.out.println("服务器转发消息中..."); //遍历 所有的注册到Selector的SocketChannel排查self for (SelectionKey key : selector.keys()) { //取出通道 Channel targetChannel = key.channel(); //targetChanneld的类型是SocketChannel,并且targetChannel不是自己 if (targetChannel instanceof SocketChannel && targetChannel != self){ //转型 SocketChannel dest = (SocketChannel)targetChannel; //将来msg 存到buffer ByteBuffer buffer = ByteBuffer.wrap(msg.getBytes("GBK")); //将来buffer的数据写入通道 dest.write(buffer); } } } public static void main(String[] args) { //初始化服务器对象 GroupChatServer chatServer = new GroupChatServer(); chatServer.listen(); }}

客户端

public class GroupChatClient {       //定义相关属性    private final String HOST = "127.0.0.1"; //服务器IP    private final int PORT = 6666; //服务器端口    private Selector selector;    private SocketChannel socketChannel;    private String username;    //构造器,初始化    public GroupChatClient() {           try {               //得到选择器            selector = Selector.open();            //连接服务            socketChannel = SocketChannel.open(new InetSocketAddress(HOST,PORT));            //设置非阻塞            socketChannel.configureBlocking(false);            //将来socketChannel注册到Selector,关注读事件            socketChannel.register(selector, SelectionKey.OP_READ);            //得到username            username = socketChannel.getLocalAddress().toString().substring(1);            System.out.println(username + " is ok ...");        }catch (Exception e){               e.printStackTrace();        }    }    //向服务器发送消息    public void sendInfo(String info){           info = username + " 说:" + info;        try {               socketChannel.write(ByteBuffer.wrap(info.getBytes("GBK")));        }catch (IOException e){               e.printStackTrace();        }    }    //读取从服务器端回复的消息    public void readInfo(){           try {               int readChannels = selector.select(2000);            if (readChannels > 0){   //有可用的通道                Iterator
iterator = selector.selectedKeys().iterator(); while (iterator.hasNext()){ SelectionKey key = iterator.next(); if (key.isReadable()){ //得到相关的通道 SocketChannel socketChannel = (SocketChannel) key.channel(); //得到一个Buffer ByteBuffer buffer = ByteBuffer.allocate(1024); //buffer 读取通道数据 socketChannel.read(buffer); //把读到缓冲区的数据转成字符串 String msg = new String(buffer.array()); System.out.println(msg.trim()); } iterator.remove(); } } }catch (IOException e){ e.printStackTrace(); } } public static void main(String[] args) { //启动客户端 GroupChatClient chatClient = new GroupChatClient(); //启动一个线程,每隔开3秒读取服务器发送的数据 new Thread(new Runnable() { @Override public void run() { while (true){ chatClient.readInfo(); try { Thread.currentThread().sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); //发送数据 Scanner scanner = new Scanner(System.in); while (scanner.hasNextLine()){ String s = scanner.nextLine(); chatClient.sendInfo(s); } }}

测试

设置启动参数,当前类可以同时运行多个

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

转载地址:http://cyxo.baihongyu.com/

你可能感兴趣的文章
multiprocessing.Pool:map_async 和 imap 有什么区别?
查看>>
MySQL Connector/Net 句柄泄露
查看>>
multiprocessor(中)
查看>>
mysql CPU使用率过高的一次处理经历
查看>>
Multisim中555定时器使用技巧
查看>>
MySQL CRUD 数据表基础操作实战
查看>>
multisim变压器反馈式_穿过隔离栅供电:认识隔离式直流/ 直流偏置电源
查看>>
mysql csv import meets charset
查看>>
multivariate_normal TypeError: ufunc ‘add‘ output (typecode ‘O‘) could not be coerced to provided……
查看>>
MySQL DBA 数据库优化策略
查看>>
multi_index_container
查看>>
mutiplemap 总结
查看>>
MySQL Error Handling in Stored Procedures---转载
查看>>
MVC 区域功能
查看>>
MySQL FEDERATED 提示
查看>>
mysql generic安装_MySQL 5.6 Generic Binary安装与配置_MySQL
查看>>
Mysql group by
查看>>
MySQL I 有福啦,窗口函数大大提高了取数的效率!
查看>>
mysql id自动增长 初始值 Mysql重置auto_increment初始值
查看>>
MySQL in 太多过慢的 3 种解决方案
查看>>