Java基于Netty NIO的简单聊天室实现攻略
本文将介绍使用Netty NIO框架实现一个简单的聊天室的详细过程,包括环境搭建、项目结构、代码实现等。
环境搭建
首先需要安装Java环境,推荐使用JDK 1.8版本。
接着安装Maven,用于管理依赖项,可以在Maven官网(http://maven.apache.org)查看安装教程。
项目结构
创建一个Maven项目,命名为chat-room。
在src/main/java目录下创建两个包:server和client,分别用于存放服务器端和客户端的代码。
代码实现
1. 服务器端代码
首先需要引入Netty依赖。在chat-room项目的pom.xml文件中添加以下依赖:
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.25.Final</version>
</dependency>
接着创建一个ChatServer类,实现服务器端的主要逻辑。具体代码如下:
package com.example.chatroom.server;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
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.CharsetUtil;
public class ChatServer {
private int port;
public ChatServer(int port) {
this.port = port;
}
public static void main(String[] args) {
new ChatServer(8000).run();
}
public void run() {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap bootstrap = new 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(CharsetUtil.UTF_8));
pipeline.addLast("encoder", new StringEncoder(CharsetUtil.UTF_8));
pipeline.addLast(new ChatServerHandler());
}
});
System.out.println("ChatServer started.");
bootstrap.bind(port).sync().channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
private static class ChatServerHandler extends io.netty.channel.SimpleChannelInboundHandler<String> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
System.out.println("Received:" + msg);
ByteBuf responseBuf = Unpooled.copiedBuffer("Response from server: " + msg, CharsetUtil.UTF_8);
ctx.writeAndFlush(responseBuf);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
}
代码中,实现了NIO Server的启动、编解码器设置和数据的收发处理逻辑。
2. 客户端代码
接着创建一个ChatClient类,实现客户端的主要逻辑。具体代码如下:
package com.example.chatroom.client;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
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 io.netty.util.CharsetUtil;
import java.util.Scanner;
public class ChatClient {
private String host;
private int port;
public ChatClient(String host, int port){
this.host = host;
this.port = port;
}
public static void main(String[] args) {
new ChatClient("localhost", 8000).run();
}
public void run() {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap()
.group(group)
.channel(NioSocketChannel.class)
.option(ChannelOption.SO_KEEPALIVE, true)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("decoder", new StringDecoder(CharsetUtil.UTF_8));
pipeline.addLast("encoder", new StringEncoder(CharsetUtil.UTF_8));
pipeline.addLast(new ChatClientHandler());
}
});
// 连接服务器
ch = bootstrap.connect(host, port).sync().channel();
// 从命令行读取输入,并将其发送给服务器
Scanner scanner = new Scanner(System.in);
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
ByteBuf buf = Unpooled.copiedBuffer(line, CharsetUtil.UTF_8);
ch.writeAndFlush(buf);
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
group.shutdownGracefully();
}
}
private static class ChatClientHandler extends io.netty.channel.SimpleChannelInboundHandler<String> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
System.out.println("Received:" + msg);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
private static SocketChannel ch;
}
代码中,实现了NIO Client的启动、编解码器设置和数据的收发处理逻辑。
示例说明
示例一
在ChatServer类中的channelRead0方法前添加以下注释:
/**
* This method will be called after the decoded string is received from the client.
* Simply echo back the received message to the client.
*/
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
System.out.println("Received:" + msg);
ByteBuf responseBuf = Unpooled.copiedBuffer("Response from server: " + msg, CharsetUtil.UTF_8);
ctx.writeAndFlush(responseBuf);
}
这样,服务器将会将客户端发送来的消息以“Response from server: ”开头,再发送给客户端。
示例二
在ChatServer类中增加一个名为broadcast的方法:
private Map<Channel, String> channelMap = new HashMap<>();
private void broadcast(String message) {
channelMap.keySet().forEach(channel -> {
ByteBuf responseBuf = Unpooled.copiedBuffer(message, CharsetUtil.UTF_8);
channel.writeAndFlush(responseBuf);
});
}
这个方法将收到的消息广播给所有连接到服务器的客户端。
接着,在ChatServerHandler类中,修改channelRead0方法:
@Override
protected void channelRead0(ChannelHandlerContext ctx, String message) throws Exception {
String sender = channelMap.get(ctx.channel());
if (StringUtils.isBlank(sender)) {
// 如果发送者名称为空,将其设置为当前消息内容
channelMap.put(ctx.channel(), message);
broadcast(channelMap.get(ctx.channel()) + " joined the chat room.");
} else {
broadcast(sender + " : " + message);
}
}
这样,当一个客户端第一次发送消息时,服务器将把消息作为该客户端的名称,并将其加入到channelMap中。之后,客户端发送的消息将被广播给其他连接到服务器的客户端。
总结
Netty是一个非常强大的网络编程框架,在性能和可扩展性方面都表现优异。它为Java程序员提供了一种快速简便地实现基于NIO的网络应用程序的方法。本文就是一个简单的聊天室程序,利用了Netty NIO框架,实现了服务器端和客户端的数据通信功能。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:java基于netty NIO的简单聊天室的实现 - Python技术站