一、服务器端:

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();
            f.channel().closeFuture().sync();
        } finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }

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

二、MultiChatServerHandler类,实现服务器端的消息处理逻辑,包括用户登录、聊天室列表、消息发送和私聊功能。

import io.netty.channel.ChannelFuture;
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;

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];

        switch (command) {
            case 'LOGIN':
                handleLogin(ctx, tokens[1], tokens[2]);
                break;
            case 'LIST':
                handleList(ctx);
                break;
            case 'MSG':
                handleMessage(ctx, tokens[1], tokens[2]);
                break;
            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:
');
        for (Map.Entry<String, ChannelHandlerContext> entry : userMap.entrySet()) {
            sb.append(entry.getKey()).append('
');
        }
        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('
');
        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('
');
        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();
    }
}

三、客户端:

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;
                }
                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();
    }
}

四、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();
    }
}

如何运行:

  1. 先运行服务器端程序MultiChatServer,可以通过命令行或者IDE运行。
  2. 再运行多个客户端程序MultiChatClient,每个客户端可以通过命令行或者IDE运行。
  3. 在客户端程序中输入命令进行登录、查看聊天室列表、发送消息等操作。可以在多个客户端之间进行聊天和私聊。

说明:

  • 服务器端使用 Netty 构建,并使用 ConcurrentHashMap 来存储用户连接信息。
  • 客户端使用 Netty 连接服务器,并使用 BufferedReader 从控制台读取用户输入。
  • 消息处理逻辑在 MultiChatServerHandlerMultiChatClientHandler 类中实现。
  • 用户登录后,可以通过 LIST 命令查看所有在线用户。
  • 用户可以向聊天室发送消息,消息会广播给所有在线用户。
  • 用户可以向特定用户发送私聊消息。

本示例只是一个简单的多用户聊天室应用,可以根据实际需求进行扩展,例如:

  • 添加用户注册功能。
  • 添加房间管理功能,用户可以创建、加入和离开房间。
  • 添加文件传输功能。
  • 添加用户权限管理功能。
  • 添加消息加密功能。
  • 添加数据库持久化功能,保存用户聊天记录。

希望本示例可以帮助您了解使用 Netty 开发网络应用的基本方法。

基于 Netty 实现多用户聊天室:服务器端、客户端和消息处理

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

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