Java NIO实现聊天系统

使用Java的NIO写的一个小的聊天系统,供大家参考,具体内容如下

一、服务端

/**
 * 群聊的服端
 *
 * @author :breakpoint/赵立刚
 * @date : 2020/08/13
 */
public class GroupChatServer {

    // 定义相关的属性
    private Selector selector;
    private ServerSocketChannel listenChannel;
    private static final int port = 6667;

    // 构造器
    // 进行初始化的操作
    public GroupChatServer() {
        try {
            // 获取选择器
            selector = Selector.open();
            // 获取到 listenChannel
            listenChannel = ServerSocketChannel.open();
            // 设定端口
            listenChannel.bind(new InetSocketAddress(port));
            // 设定非阻塞模式
            listenChannel.configureBlocking(false);
            // 将该 listenChannel 注册到 selector上 完成操作
            listenChannel.register(selector, SelectionKey.OP_ACCEPT);
            System.out.println("服务器启动了。。。。");
        } catch (IOException e) {

        }

    }

    // 监听的代码

    public void listen() {
        try {
            // 循环处理
            while (true) {
                int count = selector.select(2000);
                if (count > 0) {
                    // 有事件需要处理
                    // 遍历处理 得到selectionKeys集合
                    Set<SelectionKey> selectionKeys = selector.selectedKeys();
                    Iterator<SelectionKey> selectionKeyIterator = selectionKeys.iterator();
                    while (selectionKeyIterator.hasNext()) {
                        // 得到selectionKey
                        SelectionKey selectionKey = selectionKeyIterator.next();
                        // 监听到了 accept
                        if (selectionKey.isAcceptable()) {
                            // 获取到连接
                            SocketChannel sc = listenChannel.accept();
                            sc.configureBlocking(false);
                            sc.register(selector, SelectionKey.OP_READ, ByteBuffer.allocate(1024));
                            // 提示上线
                            System.out.println(sc.getRemoteAddress() + ":上线啦。。。。");
                        }

                        if (selectionKey.isReadable()) {
                            // 读取事件 通道是可以读的状态 //专门写
                            readData(selectionKey);
                        }

                        // 移除当前的删除 防止重复处理操作
                        selectionKeyIterator.remove();
                    }

                } else {
                    System.out.println("等待中。。。。。。");
                }
            }

        } catch (Exception e) {

        } finally {

        }
    }

    // 读取客户端的消息

    private void readData(SelectionKey selectionKey) {
        // 获取 socketChannel

        SocketChannel channel = null;
        try {
            channel = (SocketChannel) selectionKey.channel();
            ByteBuffer byteBuffer = (ByteBuffer) selectionKey.attachment();
            int count = channel.read(byteBuffer);
            // 分情况处理
            if (count > 0) {
                // 获取到数据专程
                String msg = new String(byteBuffer.array(), 0, count);
                byteBuffer.clear();
                System.out.println(channel.getRemoteAddress() + "来自客户端" + msg);
                // 向其他的客户端转发消息
                sendInfoToOtherClients(msg, channel);
            }

        } catch (IOException e) {
            // 如果发生异常 提示说明离线了
            try {
                System.out.println(channel.getRemoteAddress() + "离线了。。。。");
                // 取消注册
                selectionKey.cancel();
                // 关闭通道
                channel.close();
            } catch (IOException e1) {
                //e1.printStackTrace();
            }
        } finally {

        }
    }

    // 转发消息给其他的客户端 去掉自己的客户端
    private void sendInfoToOtherClients(String msg, SocketChannel self) throws IOException {
        System.out.println("服务器转发消息。。。。。");
        // 进行遍历操作
        Set<SelectionKey> keys = selector.keys();
        for (SelectionKey key : keys) {
            // 取出来所有的
            Channel targetChannel = key.channel();
            // 排除自己
            if (targetChannel instanceof SocketChannel && targetChannel != self) {
                SocketChannel dest = (SocketChannel) targetChannel;
                ByteBuffer byteBuffer = ByteBuffer.wrap(msg.getBytes());
                // 发送数据
                dest.write(byteBuffer);
            }
        }
    }

    public static void main(String[] args) {
        GroupChatServer groupChatServer = new GroupChatServer();
        groupChatServer.listen();
    }
}

二、客户端代码

/**
 * @author :breakpoint/赵立刚
 * @date : 2020/08/13
 */
public class GroupChatClient {

    // 定义相关属性

    private final String HOST = "127.0.0.1"; //服务器地址
    private final int port = 6667; // 服务器端口
    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.register(selector, SelectionKey.OP_READ);
            userName = socketChannel.getLocalAddress().toString();
            System.out.println("客户端专备好啦");
        } catch (IOException e) {

        }
    }

    public void sendInfo(String info) {
        String msg = userName + "说:" + info;
        try {
            ByteBuffer wrap = ByteBuffer.wrap(msg.getBytes());
            socketChannel.write(wrap);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // 读取信息
    public void readInfo() {
        try {
            int readChannel = selector.select(2000);
            if (readChannel > 0) {
                // 有可以用的通道
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                Iterator<SelectionKey> iterator = selectionKeys.iterator();
                while (iterator.hasNext()) {
                    SelectionKey next = iterator.next();
                    if (next.isReadable()) {
                        SelectableChannel keyChannel = next.channel();
                        if (keyChannel instanceof SocketChannel) {
                            // 获取到我们的通道
                            SocketChannel channel = (SocketChannel) keyChannel;
                            ByteBuffer allocate = ByteBuffer.allocate(1024);
                            // 读取数据
                            int read = channel.read(allocate);
                            if (read > 0) {
                                // 输出我们的消息
                                System.out.println(new String(allocate.array(), 0, read));
                            }

                        }// end if
                    }
                    iterator.remove();
                }
            } else {
                System.out.println("没有可用的通道");
            }
        } catch (IOException e) {

        }
    }

    public static void main(String[] args) throws Exception {

        // 启动客户端的操作
        final GroupChatClient groupChatClient = new GroupChatClient();

        // 启动一个线程

        new Thread(() -> {
            while (true) {
                groupChatClient.readInfo();
                try {
                    Thread.currentThread().sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();

        Scanner scanner = new Scanner(System.in);

        while (scanner.hasNext()) {
            // 输入信息
            String s = scanner.nextLine();
            groupChatClient.sendInfo(s);
        }

        System.in.read();
    }
}

三、运行的结果

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。 

(0)

相关推荐

  • java基于netty NIO的简单聊天室的实现

    一.为何要使用netty开发 由于之前已经用Java中的socket写过一版简单的聊天室,这里就不再对聊天室的具体架构进行细致的介绍了,主要关注于使用netty框架重构后带来的改变.对聊天室不了解的同学可以先看下我的博客(<JAVA简单聊天室的实现>) 本篇博客所使用的netty版本为4.1.36,完整工程已上传到Github(https://github.com/Alexlingl/Chatroom),其中lib文件夹下有相应的netty jar包和source包,自行导入即可. 1.为何要

  • Java NIO实战之聊天室功能详解

    本文实例讲述了Java NIO实战之聊天室功能.分享给大家供大家参考,具体如下: 在工作之余花了两个星期看完了<Java NIO>,总体来说这本书把NIO写的很详细,没有过多的废话,讲的都是重点,只是翻译的中文版看的确实吃力,英文水平太低也没办法,总算也坚持看完了.<Java NIO>这本书的重点在于第四章讲解的"选择器",要理解透还是要反复琢磨推敲:愚钝的我花了大概3天的时间才将NIO的选择器机制理解透并能较熟练的运用,于是便写了这个聊天室程序. 下面直接上代

  • Java NIO实现多人聊天室

    本文实例为大家分享了Java NIO实现多人聊天室的具体代码,供大家参考,具体内容如下 1. 服务器端代码 ChatServer类: package nio.test.server; import java.io.Closeable; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.*; import java.n

  • Java实现NIO聊天室的示例代码(群聊+私聊)

    功能介绍 功能:群聊+私发+上线提醒+下线提醒+查询在线用户 文件 Utils 需要用maven导入下面两个包 <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.16.18</version> </dependency> <dependency> <group

  • Java NIO实现聊天室功能

    本文实例为大家分享了Java NIO实现聊天室功能的具体代码,供大家参考,具体内容如下 代码里面已经包含了必要的注释,这里不详述了.实现了基本的聊天室功能. 常量类: public class Constant { public static final int serverPort = 44444; } 服务端: package server; import java.io.IOException; import java.net.InetSocketAddress; import java.

  • Java NIO实现聊天功能

    本文实例为大家分享了Java NIO实现聊天功能的具体代码,供大家参考,具体内容如下 server code :  package com.tch.test.nio; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.ClosedChannelException; import java.nio.channels.S

  • Java BIO实现聊天程序

    本文实例为大家分享了Java BIO实现聊天程序的具体代码,供大家参考,具体内容如下 我们使用一个聊天程序来说本文的主题 1.BIO 客户端服务器通讯 public class ChatServer { public static void main(String[] args) throws IOException { ServerSocket serverSocket = new ServerSocket(9000); while (true) { try { System.out.prin

  • java NIO实现简单聊天程序

    本文实例为大家分享了java NIO实现简单聊天程序的具体代码,供大家参考,具体内容如下 服务端 功能: 1.接受客户端连接 2.发送消息 3.读取客户端消息 Server.java public class Server { private Selector selector; private ByteBuffer writeBuffer = ByteBuffer.allocate(1024); private ByteBuffer readBuffer = ByteBuffer.alloca

  • Java NIO实现聊天系统

    使用Java的NIO写的一个小的聊天系统,供大家参考,具体内容如下 一.服务端 /** * 群聊的服端 * * @author :breakpoint/赵立刚 * @date : 2020/08/13 */ public class GroupChatServer { // 定义相关的属性 private Selector selector; private ServerSocketChannel listenChannel; private static final int port = 66

  • java NIO 详解

    Java NIO提供了与标准IO不同的IO工作方式: Channels and Buffers(通道和缓冲区):标准的IO基于字节流和字符流进行操作的,而NIO是基于通道(Channel)和缓冲区(Buffer)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中. Asynchronous IO(异步IO):Java NIO可以让你异步的使用IO,例如:当线程从通道读取数据到缓冲区时,线程还是可以进行其他事情.当数据被写入到缓冲区时,线程可以继续处理它.从缓冲区写入通道也类似. S

  • Java NIO和IO的区别

    下表总结了Java NIO和IO之间的主要差别,我会更详细地描述表中每部分的差异. 复制代码 代码如下: IO                NIO面向流            面向缓冲阻塞IO            非阻塞IO无                选择器 面向流与面向缓冲 Java NIO和IO之间第一个最大的区别是,IO是面向流的,NIO是面向缓冲区的. Java IO面向流意味着每次从流中读一个或多个字节,直至读取所有字节,它们没有被缓存在任何地方.此外,它不能前后移动流中的数

  • java nio基础使用示例

    在jdk1.4中提出的技术,非阻塞IO,采用的是基于事件处理方式.传统的io技术为阻塞的,比如读一个文件,惹read方法是阻塞的,直到有数据读入.归纳为:1.java io为阻塞,在打开一个io通道后,read将一直等待在端口一边读取字节内容,如果没有内容进来,read相当于阻塞掉了.2.在1的基础上改进为,开设线程,serversocker.accept()后让线程去等待,但是当并发量高的时候,相当耗费资源的.3.java nio为非阻塞,采用的是reactor反应堆模式,或者说observe

  • Java NIO原理图文分析及代码实现

    前言: 最近在分析hadoop的RPC(Remote Procedure Call Protocol ,远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议.可以参考:http://baike.baidu.com/view/32726.htm )机制时,发现hadoop的RPC机制的实现主要用到了两个技术:动态代理(动态代理可以参考博客:http://weixiaolu.iteye.com/blog/1477774 )和java NIO.为了能够正确地分析

  • Java NIO:浅析IO模型_动力节点Java学院整理

    也许很多朋友在学习NIO的时候都会感觉有点吃力,对里面的很多概念都感觉不是那么明朗.在进入Java NIO编程之前,我们今天先来讨论一些比较基础的知识:I/O模型.下面本文先从同步和异步的概念 说起,然后接着阐述了阻塞和非阻塞的区别,接着介绍了阻塞IO和非阻塞IO的区别,然后介绍了同步IO和异步IO的区别,接下来介绍了5种IO模型,最后介绍了两种和高性能IO设计相关的设计模式(Reactor和Proactor). 以下是本文的目录大纲: 一.什么是同步?什么是异步? 二.什么是阻塞?什么是非阻塞

  • 支撑Java NIO与NodeJS的底层技术

    支撑Java NIO 与 NodeJS的底层技术 众所周知在近几个版本的Java中增加了一些对Java NIO.NIO2的支持,与此同时NodeJS技术栈中最为人称道的优势之一就是其高性能IO,那么我们今天要讨论的话题就是支撑这些技术的底层技术. 开始之前先要提出的一个问题是: 为什么NodeJS和Java NIO2没有在更早的时间出现? 答案:个人认为是底层的支撑技术还不成熟. 那么,底层技术指的是什么呢?对的,我想很多人已经猜到,是操作系统技术.本文提出的两个概念Java NIO2和Node

  • Java NIO实例UDP发送接收数据代码分享

    Java的NIO包中,有一个专门用于发送UDP数据包的类:DatagramChannel,UDP是一种无连接的网络协议, 一般用于发送一些准确度要求不太高的数据等. 完整的服务端程序如下: public class StatisticsServer { //每次发送接收的数据包大小 private final int MAX_BUFF_SIZE = 1024 * 10; //服务端监听端口,客户端也通过该端口发送数据 private int port; private DatagramChann

  • JDK1.7 之java.nio.file.Files 读取文件仅需一行代码实现

    JDK1.7中引入了新的文件操作类java.nio.file这个包,其中有个Files类它包含了很多有用的方法来操作文件,比如检查文件是否为隐藏文件,或者是检查文件是否为只读文件.开发者还可以使用Files.readAllBytes(Path)方法把整个文件读入内存,此方法返回一个字节数组,还可以把结果传递给String的构造器,以便创建字符串输出.此方法确保了当读入文件的所有字节内容时,无论是否出现IO异常或其它的未检查异常,资源都会关闭.这意味着在读文件到最后的块内容后,无需关闭文件.要注意

  • Java NIO Path接口和Files类配合操作文件的实例

    Path接口 1.Path表示的是一个目录名序列,其后还可以跟着一个文件名,路径中第一个部件是根部件时就是绝对路径,例如 / 或 C:\ ,而允许访问的根部件取决于文件系统: 2.以根部件开始的路径是绝对路径,否则就是相对路径: 3.静态的Paths.get方法接受一个或多个字符串,字符串之间自动使用默认文件系统的路径分隔符连接起来(Unix是 /,Windows是 \ ),这就解决了跨平台的问题,接着解析连接起来的结果,如果不是合法路径就抛出InvalidPathException异常,否则就

随机推荐