<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.20.Final</version>
</dependency>
package com.example.demo;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
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.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
/**
* 群聊服务端
*/
public class GroupChatServer {
private int port;
public GroupChatServer(int port){
this.port=port;
}
public void run() throws InterruptedException {
EventLoopGroup boss=new NioEventLoopGroup();
EventLoopGroup woker=new NioEventLoopGroup();
try {
ServerBootstrap b=new ServerBootstrap();
b.group(boss,woker)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG,128)
.childOption(ChannelOption.SO_KEEPALIVE,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 GroupChatServerHandler());
}
});
//绑定端口
ChannelFuture sync = b.bind(port).sync();
//监听关闭
sync.channel().closeFuture().sync();
}finally {
//优雅关闭
woker.shutdownGracefully();
boss.shutdownGracefully();
}
}
public static void main(String[] args) throws InterruptedException {
GroupChatServer groupChatServer=new GroupChatServer(7777);
groupChatServer.run();
}
}
package com.example.demo;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.util.concurrent.GlobalEventExecutor;
import java.nio.channels.SocketChannel;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 服务器业务处理程序
*/
public class GroupChatServerHandler extends SimpleChannelInboundHandler<String> {
//定义一个通道组 管理所有的通道 全局事件的执行器
private static ChannelGroup channelGroup=new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//建立连接 第一个被执行 把通道加入 通道组
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
//将客户端上线的消息 发送给其他客户端
channelGroup.writeAndFlush("客户端:"+ctx.channel().remoteAddress()+"已加入群聊"+sdf.format(new Date()));
channelGroup.add(ctx.channel());
}
//通道激活
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println(ctx.channel().remoteAddress()+"上线了");
}
//通道非激活
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
System.out.println(ctx.channel().remoteAddress()+"下线了");
}
//断开连接 将xx客户端 离开的消息 发送给在线的客户端
@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
channelGroup.writeAndFlush(ctx.channel().remoteAddress()+"离开了");
System.out.println("当前管道组的长度:"+channelGroup.size());
}
//读取客户端发过来的数据
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, String s) throws Exception {
Channel channel = channelHandlerContext.channel();
channelGroup.forEach(x->{
if(x!=channel){
//如果不是自己的通道 那么给其他客户端 转发消息
x.writeAndFlush("客户端:"+channel.remoteAddress()+"发了消息:"+s);
}else {
//如果是自己
x.writeAndFlush("自己给自己发消息:"+s);
}
});
}
//异常 关闭通道
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
ctx.close();
}
}
package com.example.demo;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
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.util.Scanner;
//群聊客户端
public class GroupChatClient {
private final String host;
private final int port;
public GroupChatClient(String host,int port){
this.host=host;
this.port=port;
}
public void run() throws InterruptedException {
EventLoopGroup eventLoopGroup=new NioEventLoopGroup();
try {
Bootstrap bootstrap=new Bootstrap();
bootstrap.group(eventLoopGroup)
.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());
//向管道增加客户端的业务处理程序
socketChannel.pipeline().addLast(new GroupChatClientHandler());
}
});
ChannelFuture channelFuture = bootstrap.connect(host, port).sync();
Channel channel = channelFuture.channel();
//客户端已启动
System.out.println("-----------------"+channel.localAddress()+"-----------------");
//创建输入程序
Scanner scanner=new Scanner(System.in);
while (scanner.hasNextLine()){
String s = scanner.nextLine();
//把控制台输入的写入通道
channel.writeAndFlush(s);
}
}finally {
//优雅关闭
eventLoopGroup.shutdownGracefully();
}
}
public static void main(String[] args) throws InterruptedException {
//连接服务器
GroupChatClient groupChatClient=new GroupChatClient("127.0.0.1",7777);
groupChatClient.run();
}
}
package com.example.demo;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.SimpleChannelInboundHandler;
//客户端业务处理程序
public class GroupChatClientHandler extends SimpleChannelInboundHandler<String> {
//读取服务器发过来的消息
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, String s) throws Exception {
System.out.println(s);
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/5e3f40af61e3e1ee6175b65258271668.png)
![](https://i-blog.csdnimg.cn/blog_migrate/98b2f879072b93ca28a9bbb571105779.png)