Netty的聊天室开发
实现一个群聊天器,client登录连接到服务器,可以发送msg,其他的client也可以看到。
Netty的写法比较模板化,核心在于Handler的编写
服务端:
public class NettyServer {
public static void main(String[] args) throws InterruptedException {
NioEventLoopGroup bossGroup = new NioEventLoopGroup(1);
NioEventLoopGroup workerGroup = new NioEventLoopGroup();
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup,workerGroup).channel(NioServerSocketChannel.class)
.childOption(ChannelOption.SO_BACKLOG,128)
.childOption(ChannelOption.SO_KEEPALIVE,Boolean.TRUE)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast("decoder",new StringDecoder());
socketChannel.pipeline().addLast("encoder",new StringEncoder());
socketChannel.pipeline().addLast(new MyNettyServerHandler());
}
});
//启动服务并绑定端口
ChannelFuture future = bootstrap.bind(9999).sync();
future.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
if (future.isSuccess()) {
System.out.println("端口绑定成功!");
} else {
System.out.println("端口绑定失败!");
}
}
});
System.out.println("聊天室服务端启动成功.");
System.out.println("连接成功");
future.channel().closeFuture().sync();
//关闭连接池
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
MyNettyServerHandler
public class MyNettyServerHandler extends SimpleChannelInboundHandler<String> {
public static List<Channel> channelList = new ArrayList<>();
/**
* 当客户端和服务端建立联系之后,会回调该方法
* 当有新的连接出现时候就要将通道放到集合之中
* @param channelHandlerContext
* @throws Exception
*/
@Override
public void channelActive(ChannelHandlerContext channelHandlerContext) throws Exception {
System.out.println("当客户端和服务端,连接建立。。。。。");
System.out.println("当前上线的连接是:"+channelHandlerContext.channel().remoteAddress().toString().substring(1));
Channel channel = channelHandlerContext.channel();
channelList.add(channel);
}
/**
* 某个连接断开之后的操作
* @param channelHandlerContext
* @throws Exception
*/
@Override
public void channelInactive(ChannelHandlerContext channelHandlerContext) throws Exception {
Channel channel = channelHandlerContext.channel();
//当有客户端断开连接的时候,就移除对应的通道
channelList.remove(channel);
System.out.println("[Server]:" + channel.remoteAddress().toString().substring(1) + "下线.");
}
/**
* 读取客户端的消息
* 服务端收到客户端的消息
* @param channelHandlerContext
* @param o
* @throws Exception
*/
/*@Override
public void channelRead(ChannelHandlerContext channelHandlerContext, Object o) throws Exception {
Channel channel = channelHandlerContext.channel();
channel.writeAndFlush("来自服务器的数据");
ByteBuffer byteBuffer = (ByteBuffer)o;
System.out.println("服务端收到客户端的消息"+byteBuffer.toString());
}*/
/**
* 客户端连接过来的msg在这里面可以读出来
* @param channelHandlerContext
* @param s
* @throws Exception
*/
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, String s) throws Exception {
Channel channel = channelHandlerContext.channel();
for (Channel channel1 : channelList){
if (channel != channel1){
channel1.writeAndFlush("[" +
channel.remoteAddress().toString().substring(1) + "]说:" + s);
}else {
channel1.writeAndFlush("[ 自己 ]发送了数据:" + s);
}
}
}
@Override
public void exceptionCaught(ChannelHandlerContext channelHandlerContext, Throwable throwable) throws Exception {
throwable.printStackTrace();
Channel channel = channelHandlerContext.channel();
//移除集合
channelList.remove(channel);
System.out.println("[Server]:" + channel.remoteAddress().toString().substring(1) + "异常.");
}
}
客户端
客户端可以启动多个
public class Client {
public static void main(String[] args) throws InterruptedException {
//客户端的netty程序
EventLoopGroup clientGroup = new NioEventLoopGroup();
try{
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(clientGroup).channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
//添加编解码器
socketChannel.pipeline().addLast("decoder",new StringDecoder());
socketChannel.pipeline().addLast("encoder",new StringEncoder());
//8. 向pipeline中添加自定义业务处理handler
socketChannel.pipeline().addLast(new MyNettyClientHandler());
}
});
ChannelFuture channelFuture = bootstrap.connect("127.0.0.1", 9999).sync();
Channel channel = channelFuture.channel();
System.out.println("-------" + channel.localAddress().toString().substring(1) + "--------");
Scanner scanner = new Scanner(System.in);
while (scanner.hasNextLine()){
String msg = scanner.nextLine();
//向服务端发送消息
channel.writeAndFlush(msg);
}
System.out.println("连接成功");
channelFuture.channel().closeFuture().sync();
}catch(Exception e){
}finally {
clientGroup.shutdownGracefully();
}
}
}
public class MyNettyClientHandler extends SimpleChannelInboundHandler<String> {
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, String s) throws Exception {
System.out.println(s);
}
}
分别启动server和俩个client 效果:
在client中输入聊天语句: