用 Netty 实现简单的聊天功能 - Java 代码示例
首先,需要创建一个服务器来监听客户端连接请求,并处理来自客户端的消息。以下是一个简单的 Netty 聊天服务器的示例代码:
public class ChatServer {
private final int port;
public ChatServer(int port) {
this.port = port;
}
public void run() throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap bootstrap = new ServerBootstrap()
.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChatServerInitializer());
ChannelFuture future = bootstrap.bind(port).sync();
System.out.println('Chat server started on port ' + port);
future.channel().closeFuture().sync();
} finally {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception {
new ChatServer(8080).run();
}
}
在上面的代码中,我们创建了一个ChatServer类,它包含一个构造函数来指定服务器监听的端口号,并且有一个run()方法来启动服务器。在run()方法中,我们创建了两个EventLoopGroup,一个用于监听连接请求的bossGroup,另一个用于处理客户端请求的workerGroup。我们使用ServerBootstrap类来设置服务器的配置,包括使用NioServerSocketChannel通道、注册ChatServerInitializer类来处理客户端请求等。最后,我们绑定端口并等待服务器关闭。
接下来,我们需要创建一个ChatServerInitializer类来初始化服务器的通道管道(ChannelPipeline),并添加处理器来处理客户端请求。以下是一个示例代码:
public class ChatServerInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pipeline = socketChannel.pipeline();
pipeline.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
pipeline.addLast(new ChatServerHandler());
}
}
在ChatServerInitializer类中,我们重写initChannel()方法来初始化通道管道。首先,我们添加一个DelimiterBasedFrameDecoder处理器来解决粘包和拆包问题;然后,我们添加StringDecoder和StringEncoder处理器来将字节流转换为字符串,并将字符串转换为字节流;最后,我们添加一个自定义的ChatServerHandler处理器来处理客户端请求。
现在,我们需要创建一个ChatServerHandler类来实现自定义的处理器。以下是一个示例代码:
public class ChatServerHandler extends SimpleChannelInboundHandler<String> {
private static final Map<Channel, String> clients = new ConcurrentHashMap<>();
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
Channel channel = ctx.channel();
clients.put(channel, 'anonymous');
System.out.println('Client ' + channel.remoteAddress() + ' connected');
channel.writeAndFlush('Welcome to the chat room!
');
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
Channel channel = ctx.channel();
clients.remove(channel);
System.out.println('Client ' + channel.remoteAddress() + ' disconnected');
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
Channel channel = ctx.channel();
String name = clients.get(channel);
if (name.equals('anonymous')) {
clients.put(channel, msg.trim());
channel.writeAndFlush('Welcome, ' + msg.trim() + '!
');
} else {
broadcast(channel, name + ': ' + msg);
}
}
private void broadcast(Channel sender, String message) {
for (Channel channel : clients.keySet()) {
if (channel != sender) {
channel.writeAndFlush(message + '
');
}
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
Channel channel = ctx.channel();
clients.remove(channel);
System.out.println('Client ' + channel.remoteAddress() + ' caused exception: ' + cause.getMessage());
ctx.close();
}
}
在ChatServerHandler类中,我们继承了SimpleChannelInboundHandler类,并重写了几个方法,包括channelActive()、channelInactive()、channelRead0()、exceptionCaught()等。在channelActive()方法中,我们添加了一个新的客户端到clients映射中,并欢迎客户端加入聊天室;在channelInactive()方法中,我们从clients映射中删除客户端,并记录客户端断开连接的消息;在channelRead0()方法中,我们根据客户端发送的消息来处理不同的情况,如果是第一次连接,则将客户端名称添加到clients映射中,并欢迎客户端加入聊天室;否则,将客户端发送的消息广播给其他客户端;在broadcast()方法中,我们遍历clients映射中的所有客户端,并将消息发送给除发送者之外的所有客户端;在exceptionCaught()方法中,我们处理客户端异常,并从clients映射中删除客户端。
现在,我们已经完成了一个基本的 Netty 聊天服务器,可以使用 telnet 或其他 TCP 客户端连接到该服务器,并实现聊天功能。
原文地址: https://www.cveoy.top/t/topic/oOnX 著作权归作者所有。请勿转载和采集!