package org.example;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.concurrent.DefaultEventExecutorGroup;
import io.netty.util.concurrent.EventExecutorGroup;

import java.util.concurrent.ConcurrentHashMap;

public class MultiChatServer {
    private final int port;
    private final ConcurrentHashMap<String, ChannelHandlerContext> userMap = new ConcurrentHashMap<>();
    private final EventExecutorGroup group = new DefaultEventExecutorGroup(16);

    public MultiChatServer(int port) {
        this.port = port;
    }

    public void run() throws Exception {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        public void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline().addLast(new StringDecoder(), new StringEncoder(), new MultiChatServerHandler(userMap, group));
                        }
                    })
                    .option(ChannelOption.SO_BACKLOG, 128)
                    .childOption(ChannelOption.SO_KEEPALIVE, true);

            ChannelFuture f = b.bind(port).sync();
            System.out.println("Server started on port " + port);
            f.channel().closeFuture().sync();
        } finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }

    public static void main(String[] args) throws Exception {
        int port = 8080;
        new MultiChatServer(port).run();
    }
}

// 客户端:
package org.example;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;

import java.io.BufferedReader;
import java.io.InputStreamReader;
//客户端:
public class MultiChatClient {
    private final String host;
    private final int port;
    private ChannelHandlerContext ctx;
    // 构造函数,初始化主机和端口
    public MultiChatClient(String host, int port) {
        this.host = host;
        this.port = port;
    }
    // 客户端运行方法
    public void run() throws Exception {
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            Bootstrap b = new Bootstrap();
            b.group(group)
                    .channel(NioSocketChannel.class)
                    .option(ChannelOption.SO_KEEPALIVE, true)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        public void initChannel(SocketChannel ch) throws Exception {
                            // 添加解码器和编码器,以及客户端处理程序
                            ch.pipeline().addLast(new StringDecoder(), new StringEncoder(), new MultiChatClientHandler());
                        }
                    });
             // 连接到服务器
            ChannelFuture f = b.connect(host, port).sync();
            ctx = f.channel().pipeline().context(MultiChatClientHandler.class);
            // 从控制台读取输入,并将其发送到服务器
            BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
            while (true) {
                String line = in.readLine();
                if (line == null) {
                    break;
                }
                if (line.equals("LIST")) {
                    String username = null;
                    ctx.writeAndFlush(line + "|" + username + "\n");
                } else {
                    ctx.writeAndFlush(line + "\n");
                }
            }
             /*
            BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
            while (true) {
                String line = in.readLine();
                if (line == null) {
                    break;
                }
                ctx.writeAndFlush(line + "\n");
            }


              */

        } finally {
            // 关闭事件循环组
            group.shutdownGracefully();
        }
    }
    // 主方法,创建客户端实例并运行
    public static void main(String[] args) throws Exception {
        String host = "localhost";
        int port = 8080;
        new MultiChatClient(host, port).run();
    }
}


package org.example;
//MultiChatClientHandler类,实现了客户端的消息处理逻辑,包括接收服务器端的消息和向服务器端发送消息。

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;

public class MultiChatClientHandler extends SimpleChannelInboundHandler<String> {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        // 读取服务器发送的消息并打印到控制台
        System.out.println(msg);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        // 发生异常时打印异常堆栈信息并关闭连接
        cause.printStackTrace();
        ctx.close();
    }
}

package org.example;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.util.concurrent.EventExecutorGroup;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
//MultiChatServerHandler类,实现服务器端的消息处理逻辑,包括用户登录、聊天室列表、消息发送和私聊功能。
public class MultiChatServerHandler extends SimpleChannelInboundHandler<String> {
    // 用户映射表,用于保存用户和上下文的映射关系
    private final ConcurrentHashMap<String, ChannelHandlerContext> userMap;
    private final EventExecutorGroup group;
    // 构造函数,初始化用户映射表和事件执行器组
    public MultiChatServerHandler(ConcurrentHashMap<String, ChannelHandlerContext> userMap, EventExecutorGroup group) {
        this.userMap = userMap;
        this.group = group;
    }
    // 当客户端连接到服务器时调用的方法
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("Client connected: " + ctx.channel().remoteAddress());
    }
    // 当客户端断开连接时调用的方法
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("Client disconnected: " + ctx.channel().remoteAddress());
        // 从用户映射表中移除断开连接的客户端上下文
        userMap.values().remove(ctx);
    }
    // 接收到客户端消息时调用的方法
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        // 将接收到的消息按照指定格式进行分割
        String[] tokens = msg.split("|");
        String command = tokens[0];


        System.out.println("Received message from client: " + msg);
        // 处理消息逻辑...

        switch (command) {
            //登入
            case "LOGIN":
                handleLogin(ctx, tokens[1], tokens[2]);
                break;
            //查看聊天室列表:在客户端中输入 `LIST`,按下回车键查看当前可用的聊天室列表。服务器端会返回当前可用的聊天室列表
            case "LIST":
                handleList(ctx);
                break;
            //发送消息:在客户端中输入 `MSG|聊天室名|消息内容`,
            // 例如 `MSG|room1|Hello, world!`,按下回车键发送消息。
            // 服务器端会将消息发送给指定的聊天室内的所有用户。
            case "MSG":
                handleMessage(ctx, tokens[1], tokens[2]);
                break;
            //私聊:在客户端中输入 `PRIVATE|用户名|消息内容`,
            // 例如 `PRIVATE|Bob|How are you?`,
            // 按下回车键发送私聊消息。服务器端会将消息发送给指定的用户。
            case "PRIVATE":
                handlePrivateMessage(ctx, tokens[1], tokens[2]);
                break;
            default:
                ctx.writeAndFlush("Invalid command: " + command);
                break;
        }
    }
//登入
    private void handleLogin(ChannelHandlerContext ctx, String username, String password) {
        if (userMap.containsKey(username)) {
            ctx.writeAndFlush("User already logged in: " + username);
        } else {
            // 将用户和上下文添加到用户映射表中
            userMap.put(username, ctx);
            ctx.writeAndFlush("Login successful: " + username);
        }
    }
//查看列表
private void handleList(ChannelHandlerContext ctx) {
    StringBuilder sb = new StringBuilder();
    sb.append("Available chat rooms:\n");
    for (Map.Entry<String, ChannelHandlerContext> entry : userMap.entrySet()) {
        sb.append(entry.getKey()).append("\n");
    }
    boolean username = false;
    if (userMap.containsKey(username)) {
        sb.append("Your information:\n");
        sb.append(username).append("\n");
    }
    ctx.writeAndFlush(sb.toString());
}

    /*
    private void handleList(ChannelHandlerContext ctx) {
        StringBuilder sb = new StringBuilder();
        sb.append("Available chat rooms:\n");
        // 遍历用户映射表,获取聊天室列表
        for (Map.Entry<String, ChannelHandlerContext> entry : userMap.entrySet()) {
            sb.append(entry.getKey()).append("\n");
        }
        ctx.writeAndFlush(sb.toString());
    }

     */
//群发
    private void handleMessage(ChannelHandlerContext ctx, String roomName, String message) {
        StringBuilder sb = new StringBuilder();
        sb.append("[").append(ctx.channel().remoteAddress()).append("] ").append(message).append("\n");
        // 遍历用户映射表,向指定聊天室中的用户发送消息
        for (Map.Entry<String, ChannelHandlerContext> entry : userMap.entrySet()) {
            if (entry.getKey().equals(roomName)) {
                entry.getValue().writeAndFlush(sb.toString());
            }
        }
    }
//私发
    private void handlePrivateMessage(ChannelHandlerContext ctx, String recipient, String message) {
        StringBuilder sb = new StringBuilder();
        sb.append("[").append(ctx.channel().remoteAddress()).append("] (private) ").append(message).append("\n");
        if (userMap.containsKey(recipient)) {
            // 如果用户映射表中存在目标用户,则向目标用户发送私密消息
            userMap.get(recipient).writeAndFlush(sb.toString());
        } else {
            ctx.writeAndFlush("User not found: " + recipient);
        }
    }
    // 异常处理方法,打印异常信息并关闭连接
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
}

这个代码有群聊功能吗,扎不是一下运行结果群聊功能示例内容:是的,这段代码实现了群聊功能。当客户端发送消息时,服务器会将消息发送给指定的聊天室内的所有用户。具体实现逻辑可以参考handleMessage方法。

Netty 多用户聊天室服务器和客户端代码示例

原文地址: http://www.cveoy.top/t/topic/f3qp 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录