Java网络编程(二)NIO和Netty实现多人聊天功能

这篇具有很好参考价值的文章主要介绍了Java网络编程(二)NIO和Netty实现多人聊天功能。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

NIO实现

服务端

package com.bierce.io;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.Set;
//服务器端
public class NIOChatServer {
public static void main(String[] args) {
	try {
		new NIOChatServer().startServer(); //启动服务器
	} catch (IOException e) {
		throw new RuntimeException(e);
	}
}
//服务端启动方法
public void startServer() throws IOException {
	//1. 创建Selector选择器
	Selector selector = Selector.open();
	//2.创建ServerSocketChannel通道
	ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
	//3.channel通道绑定监听端口,并设置为非阻塞模式
	serverSocketChannel.bind(new InetSocketAddress(8000));
	serverSocketChannel.configureBlocking(false);
	//4.channel注册到selector上,设置为就绪接收状态
	serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
	System.out.println("Server starts Successfully!");
	//5.自旋,实时监听客户端状态
	for (;;) {
		//获取所有就绪的Channel
		int readChannels = selector.select();
		if (readChannels == 0){ //没有接入的客户端
			continue;
		}
		Set<SelectionKey> selectionKeys = selector.selectedKeys();
		//遍历可用的Channel
		Iterator<SelectionKey> iterator = selectionKeys.iterator();
		while (iterator.hasNext()){
			SelectionKey selectionKey = iterator.next();
			//6.根据就绪状态,调用对应方法实现具体业务操作
			//6.1 accept状态
			if (selectionKey.isAcceptable()){
				acceptOperator(serverSocketChannel,selector);
			}
			//6.2 readable状态
			if (selectionKey.isReadable()){
				readOperator(selector,selectionKey);
			}
			iterator.remove(); //获取成功后没有必要保留需要移除
		}
	}
}
//处理可读状态的方法实现
private void readOperator(Selector selector, SelectionKey selectionKey) throws IOException {
	//从SelectionKey获取到已经就绪的通道
	SocketChannel socketChannel = (SocketChannel)selectionKey.channel();
	ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
	//自旋读取客户端信息
	int readLength = socketChannel.read(byteBuffer);
	String message = "";
	if (readLength > 0){
		byteBuffer.flip(); //切换读模式
		message += Charset.forName("UTF-8").decode(byteBuffer);
	}
	//注册channel到selector,监听可读状态
	socketChannel.register(selector, SelectionKey.OP_READ);
	if (message.length() > 0){
		//把客户端发送过来的信息广播到其他客户端
		System.out.println(message);
		castOtherClients(message,selector,socketChannel);
	}
}
//把客户端发送的消息广播给其他客户端
private void castOtherClients(String message, Selector selector, SocketChannel socketChannel) throws IOException {
	//获取所有已经接入的Channel
	Set<SelectionKey> selectionKeys = selector.keys();
	//对除自己以外的channel进行广播
	for (SelectionKey selectionKey:selectionKeys) {
		//获取每个Channel
	   Channel targetChannel = selectionKey.channel();
	   if (targetChannel instanceof SocketChannel && targetChannel != socketChannel){ //排除服务器以及发送方客户端自己
		   ((SocketChannel) targetChannel).write(Charset.forName("UTF-8").encode(message));
	   }
	}
}
//处理可接收状态的方法实现
private void acceptOperator(ServerSocketChannel serverSocketChannel, Selector selector) throws IOException {
	//接入状态:创建socketChannel
	SocketChannel socketChannel = serverSocketChannel.accept();
	//socketChannel设置为非阻塞并注册到selector上
	socketChannel.configureBlocking(false);
	socketChannel.register(selector,SelectionKey.OP_READ);
	//回复给客户端信息
	socketChannel.write(Charset.forName("UTF-8")
			.encode("Welcome to MyChatRoom, Please notice your Info!")); //UTF-8编码
}
}

客户端

package com.bierce.io;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Scanner;
//客户端实现
public class NIOChatClient {
public void startClient(String name) throws IOException {
	//客户端连接服务器端
	SocketChannel socketChannel =
			SocketChannel.open(new InetSocketAddress("127.0.0.1",8000));
	//接收服务器端响应数据
	Selector selector = Selector.open();
	socketChannel.configureBlocking(false);
	socketChannel.register(selector, SelectionKey.OP_READ);
	//创建客户端线程
	new Thread(new ClientThread(selector)).start();
	//模拟向服务器发送消息
	Scanner sc = new Scanner(System.in);
	while (sc.hasNextLine()){
		String msg = sc.nextLine();
		if (msg.length() >0){
			socketChannel.write(Charset.forName("UTF-8").encode(name + ":" + msg));
		}
	}
}
}
class ClientThread implements Runnable{
    private Selector selector;
    public ClientThread(Selector selector) {
        this.selector = selector;
    }
    @Override
    public void run() {
        try {
            for (;;) {
                //获取所有就绪的Channel
                int readChannels = selector.select();
                if (readChannels == 0){ //没有接入的客户端
                    continue;
                }
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                //遍历可用的Channel
                Iterator<SelectionKey> iterator = selectionKeys.iterator();
                while (iterator.hasNext()){
                    SelectionKey selectionKey = iterator.next();
                    iterator.remove(); //获取成功后没有必要保留需要移除
                    //readable状态
                    if (selectionKey.isReadable()){
                        readOperator(selector,selectionKey);
                    }
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    //处理可读状态的方法实现
    private void readOperator(Selector selector, SelectionKey selectionKey) throws IOException {
        //从SelectionKey获取到已经就绪的通道
        SocketChannel socketChannel = (SocketChannel)selectionKey.channel();
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
        //自旋读取客户端信息
        int readLength = socketChannel.read(byteBuffer);
        String message = "";
        if (readLength > 0){
            byteBuffer.flip(); //切换读模式
            message += Charset.forName("UTF-8").decode(byteBuffer);
        }
        //注册channel到selector,监听可读状态
        socketChannel.register(selector, SelectionKey.OP_READ);
        if (message.length() > 0){
            System.out.println(message); //该客户端控制台输出服务端发送过来的信息
        }
    }
}
//客户端A
package com.bierce.io;
import java.io.IOException;
public class TestAClient {
    public static void main(String[] args) {
        try {
            new NIOChatClient().startClient("A");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}
//客户端B
package com.bierce.io;
import java.io.IOException;
public class TestBClient {
    public static void main(String[] args) {
        try {
            new NIOChatClient().startClient("B");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

效果图

Java网络编程(二)NIO和Netty实现多人聊天功能,# Java,java,网络,nio

Java网络编程(二)NIO和Netty实现多人聊天功能,# Java,java,网络,nio

Java网络编程(二)NIO和Netty实现多人聊天功能,# Java,java,网络,nio

Netty实现

服务端

package com.bierce.io.netty.chatGroup;
/**
 * 简易群聊功能Netty服务端实现
 */
public class ChatGroupServer {
    private int port;
    private String nowTime = "北京时间-" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss")) + ": ";
    public ChatGroupServer(int port) {
        this.port = port;
    }
    public void run(){
        NioEventLoopGroup bossGroup = new NioEventLoopGroup(1);
        NioEventLoopGroup workerGroup = new NioEventLoopGroup(); //默认初始8个线程

        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();

            serverBootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class) //设置为服务端通道
                    .option(ChannelOption.SO_BACKLOG,128)
                    .childOption(ChannelOption.SO_KEEPALIVE,true)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline pipeline = ch.pipeline();
                            pipeline.addLast("decoder",new StringDecoder());
                            pipeline.addLast("encoder",new StringEncoder());
                            pipeline.addLast(new ChatGroupServerHandler(nowTime)); //自定义业务处理handler
                        }
                    });
            System.out.println(nowTime + "NettyServer start Successful !!!");
            ChannelFuture cf = serverBootstrap.bind(port).sync();
            cf.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
    public static void main(String[] args) {
        new ChatGroupServer(9999).run();
    }
}
class ChatGroupServerHandler extends SimpleChannelInboundHandler<String> {
    //定义Channel组,管理所有的Channel,其中GlobalEventExecutor.INSTANCE为全局事件执行器
    private static ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
    private String nowTime; //北京时间
    public ChatGroupServerHandler(String nowTime) {
        this.nowTime = nowTime;
    }
    //channelActive方法表示活动状态,如提示xxx上线
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println(nowTime + "[客户端]" + ctx.channel().remoteAddress() + " 上线了~\n");
    }
    //channelActive方法表示非活动状态,如提示xxx离线
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        System.out.println(nowTime + "[客户端]" + ctx.channel().remoteAddress() + " 已离线~\n");
    }
    //handlerAdded方法表示连接建立后立刻执行
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();;
        //将该客户端发送的消息进行广播,writeAndFlush方法会遍历所有Channel并发送消息
        channelGroup.writeAndFlush(nowTime + "[客户端]" + channel.remoteAddress() + " 进入聊天室\n");
        channelGroup.add(channel);
        System.out.println(nowTime + "有新进来的客户端,当前在线客户端数量=" + channelGroup.size());
    }
    //handlerRemoved方法表示断开连接,如将该客户端离开信息发送给在线的其他客户端
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        channelGroup.writeAndFlush(nowTime + "[客户端]" + ctx.channel().remoteAddress() + " 已离开了~\n");
        System.out.println(nowTime + "有刚离开的客户端,当前在线客户端数量=" + channelGroup.size());
    }
    //读取客户端信息并作出响应
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        Channel channel = ctx.channel();
        channelGroup.forEach(ch -> {
            if (channel != ch){ //给非自己的其他客户端广播信息
                ch.writeAndFlush(nowTime + "[客户端]" + ctx.channel().remoteAddress() + "发送了消息:" + msg + "\n");
            }else {
                ch.writeAndFlush(nowTime + "[客户端自己]" + ctx.channel().remoteAddress() + "发送了消息:" + msg + "\n");
            }
        });
    }
    //发生异常时关闭该通道Channel
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
}

客户端

package com.bierce.io.netty.chatGroup;
/**
 * 简易群聊功能Netty客户端实现
 */
public class ChatGroupClient {
    private String host;
    private int port;
    private String nowTime = "北京时间-" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss")) + ": ";
    public ChatGroupClient(String host, int port){
        this.host = host;
        this.port = port;
    }
    public void run(){
        NioEventLoopGroup eventLoopGroup = new NioEventLoopGroup();
        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(eventLoopGroup)
                    .channel(NioSocketChannel.class)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline pipeline = ch.pipeline();
                            pipeline.addLast("decoder",new StringDecoder());
                            pipeline.addLast("encoder",new StringEncoder());
                            pipeline.addLast(new ChatGroupClientHandler(nowTime)); //自定义业务处理handler
                        }
                    });
            ChannelFuture cf = bootstrap.connect(host, port).sync();
            Channel channel = cf.channel();
            System.out.println(nowTime + "Client"+ channel.localAddress()+ " start Successful!!!");
            Scanner sc = new Scanner(System.in);
            while (sc.hasNextLine()){
                String msg = sc.nextLine();
                channel.writeAndFlush(msg + "\r\n");
            }
            cf.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            eventLoopGroup.shutdownGracefully();
        }
    }
    public static void main(String[] args) {
        new ChatGroupClient("127.0.0.1",9999).run();
    }
}
class ChatGroupClientHandler extends SimpleChannelInboundHandler<String> {
    private String nowTime;
    public ChatGroupClientHandler(String nowTime) {
        this.nowTime = nowTime;
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        System.out.println(nowTime + msg.trim() + "{,前面消息都是服务端广播的信息~~~~}");
    }
}

效果图

Java网络编程(二)NIO和Netty实现多人聊天功能,# Java,java,网络,nio

Java网络编程(二)NIO和Netty实现多人聊天功能,# Java,java,网络,nio

Java网络编程(二)NIO和Netty实现多人聊天功能,# Java,java,网络,nio

Java网络编程(二)NIO和Netty实现多人聊天功能,# Java,java,网络,nio文章来源地址https://www.toymoban.com/news/detail-667266.html

到了这里,关于Java网络编程(二)NIO和Netty实现多人聊天功能的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Netty专题】【网络编程】从OSI、TCP/IP网络模型开始到BIO、NIO(Netty前置知识)

    我是有点怕网络编程的,总有点【谈网色变】的感觉。为了让自己不再【谈网色变】,所以我想过系统学习一下,然后再做个笔记这样,加深一下理解。但是真要系统学习,其实还是要花费不少时间的,所以这里也只是简单的,尽可能地覆盖一下,梳理一些我认为比较迫切需

    2024年02月06日
    浏览(62)
  • 多人聊天室(带私聊功能)Linux网络编程基础

    在和同学一起努力下终于完成了期末作业哈哈哈哈 文章目录 目录 前言 一、需求分析 二、功能设计 1.服务器端: 2.客户端: 三、流程图: 编程流程图: 服务器流程图: 客户端流程图: 四、运行效果: 项目源码: 服务器源码 客户端源码: 总结: Linux网络编程是我们这学

    2024年02月09日
    浏览(59)
  • Java网络编程----通过实现简易聊天工具来聊聊BIO

    IO模型即输入输出模型,我们今天主要来聊的是java网络编程中的IO模型---BIO模型。 BIO即阻塞式IO,Blocking IO blocking [ˈblɒkɪŋ] v.堵塞; 阻塞; 堵住(某人的路等); 挡住(某人的视线等); 妨碍; 阻碍; 那究竟什么是阻塞呢? 这里的阻塞和多线程并发控制中,对未持有锁的线程进行同步

    2024年02月04日
    浏览(45)
  • java网络编程——NIO架构

    目录 1.什么是NIO 2.NIO结构 3.基于NIO下的聊天系统实现 4.Netty NIO:java non-blocking IO,同步非阻塞IO。 BIO是阻塞IO,即每一个事件都需要分配一个进程给他,如果客户端没有连接上,则一直阻塞等待。 而NIO,异步 I/O 是一种没有阻塞地读写数据的方法:该架构下我们可以注册对特定

    2023年04月26日
    浏览(55)
  • Java 网络编程之NIO(selector)

                        本编文章意在循环渐进,可看最后一个就可以了                Selector selector = Selector.open();                首先channel必须是非阻塞的情况下                 channel.register(选择器,操作的类型,绑定的组件);返回的是选择键              1)Ch

    2023年04月11日
    浏览(43)
  • 快速入门java网络编程基础------Nio

    哔哩哔哩黑马程序员 netty实战视频 NIO(New I/O)是Java中提供的一种基于通道和缓冲区的I/O(Input/Output)模型。它是相对于传统的IO(InputStream和OutputStream)模型而言的新型I/O模型。NIO的主要特点包括: 1.通道与缓冲区: 2.NIO引入了通道(Channel)和缓冲区(Buffer)的概念。通道

    2024年01月20日
    浏览(55)
  • Java网络编程-深入理解BIO、NIO

    BIO BIO 为 Blocked-IO(阻塞 IO),在 JDK1.4 之前建立网络连接时,只能使用 BIO 使用 BIO 时,服务端会对客户端的每个请求都建立一个线程进行处理,客户端向服务端发送请求后,先咨询服务端是否有线程响应,如果没有就会等待或者被拒绝 BIO 基本使用代码: 服务端: 客户端:

    2024年02月04日
    浏览(40)
  • BIO、NIO、IO多路复用模型详细介绍&Java NIO 网络编程

    上文介绍了网络编程的基础知识,并基于 Java 编写了 BIO 的网络编程。我们知道 BIO 模型是存在巨大问题的,比如 C10K 问题,其本质就是因其阻塞原因,导致如果想要承受更多的请求就必须有足够多的线程,但是足够多的线程会带来内存占用问题、CPU上下文切换带来的性能问题

    2024年02月14日
    浏览(48)
  • Netty实战专栏 | Java网络编程深入解析

    ✅作者简介:大家好,我是Leo,热爱Java后端开发者,一个想要与大家共同进步的男人😉😉 🍎个人主页:Leo的博客 💞当前专栏: Netty实战专栏 ✨特色专栏: MySQL学习 🥭本文内容:Netty实战专栏 | Java网络编程深入解析 🖥️个人小站 :个人博客,欢迎大家访问 📚个人知识

    2024年02月06日
    浏览(54)
  • 使用Netty实现Socket网络编程

    ** ** Netty支持多种网络通信模型,包括传统的阻塞I/O、非阻塞I/O、多路复用I/O和异步I/O。其中,非阻塞I/O和多路复用I/O是Netty的核心特性。 非阻塞I/O :Netty通过使用Java的NIO(New I/O)库,实现了非阻塞的I/O操作。这意味着当一个操作正在进行时,不会阻塞线程,线程可以继续处

    2024年01月16日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包