1、服务端代码:服务端配置、服务端自定义事件处理类。
自定义事件处理类 – NettyServerHandler :
- 继承类SimpleChannelInboundHandler,使用泛型,此处泛型的数据类型和接收的消息的数据类型一致
- 此类默认自动将接收到的消息转换成此类型数据
public class NettyServerHandler extends SimpleChannelInboundHandler<String> {
/**
* 注:此方法需设置成静态
*/
public static List<Channel> channelList = new ArrayList<>();
/**
* 通道就绪事件
* @param ctx
* @throws Exception
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
//获取就绪通道
Channel channel = ctx.channel(); //获取当前准备就绪通道
channelList.add(channel); //新增准备就绪通道
//获取通道的地址,转换成String类型,从下表为1的位置截取该字符串
System.out.println("[Server:"+channel.remoteAddress().toString().substring(1)+"] 上线!");
}
/**
* 通道未就绪事件
* @param ctx
* @throws Exception
*/
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
Channel channel = ctx.channel(); //获取当前为准备就绪通道
channelList.remove(channel); //移除当前未就绪通道
System.out.println("[Server:"+channel.remoteAddress().toString().substring(1)+"] 下线!");
}
/**
* 数据读取时间
* @param ctx
* @param msg
* @throws Exception
*/
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
Channel channel = ctx.channel(); //获取当前接发送消息的通道
//广播接收到的消息给除了当前通道对应客户端的其他通道客户端
for (Channel ch : channelList) { //遍历所有在线的通道
if (ch != channel){ //排除当前通道
ch.writeAndFlush("用户"+channel.remoteAddress().toString().substring(1)+"说:"+msg);
}
}
}
/**
* 异常处理事件
* @param ctx
* @param cause
* @throws Exception
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
System.out.println("通道"+ctx.channel().remoteAddress().toString().substring(1)+"捕获到异常!");
}
}
服务端配置类 – NettyServer :
public class NettyServer {
public static void main(String[] args) {
new NettyServer(8888).run();
}
private int port;
public NettyServer(int port){
this.port = port;
}
public void run(){
//网络连接线程组
EventLoopGroup bossGroup = new NioEventLoopGroup();
//IO操作线程组
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
//服务端启动助手
ServerBootstrap bs = new ServerBootstrap();
bs.group(bossGroup,workerGroup)
.channel(NioServerSocketChannel.class) //服务端通道的实现
.option(ChannelOption.SO_BACKLOG,512) //通道中允许连接等待的数量
.childOption(ChannelOption.SO_KEEPALIVE,true) //保持连接状态
.childHandler(new ChannelInitializer<SocketChannel>() {//自定义通道事件处理类初始化,往链中添加自定义的事件处理类
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline cpp = ch.pipeline(); //获取链
//解码
cpp.addLast("decoder",new StringDecoder());
//编码
cpp.addLast("encoder",new StringEncoder());
//添加自定义事件处理类,此处需要注意:自定义的事件处理类要在编解码配置后
cpp.addLast("handler",new NettyServerHandler());
}
});
//绑定服务端端口
ChannelFuture bf = bs.bind(port).sync();
System.out.println(".........服务端启动成功.........");
//关闭通道
bf.channel().closeFuture().sync();
} catch (Exception e) {
e.printStackTrace();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
2、客户端代码:客户端配置类、客户端自定义事件处理类
**客户端自定义事件处理类 – NettyClientHandler **
public class NettyClientHandler extends SimpleChannelInboundHandler<String> {
/**
* 数据读取事件
* @param ctx
* @param msg
* @throws Exception
*/
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
System.out.println(msg.trim());
}
}
客户端配置类 – NettyCient :
public class NettyCient {
public static void main(String[] args) {
new NettyCient("127.0.0.1",8888).run();
}
private String ipAddress;
private int port;
public NettyCient(String ipAddress,int port){
this.ipAddress = ipAddress;
this.port = port;
}
public void run(){
//客户端线程组
EventLoopGroup group = new NioEventLoopGroup();
try {
//客户端启动助手
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class) //客户端通道实现类
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline cpp = ch.pipeline();
cpp.addLast("decoder",new StringDecoder());
cpp.addLast("encoder",new StringEncoder());
cpp.addLast("handler",new NettyClientHandler());
}
});
//连接服务端
ChannelFuture cf = b.connect(ipAddress,port).sync();
System.out.println("---------客户端启动成功--------");
//java控制台输入
Scanner sc = new Scanner(System.in);
while(sc.hasNextLine()){
String str = sc.nextLine();
cf.channel().writeAndFlush(str+"\n"); //将控制台输入的值写入通道
}
//通道关闭
cf.channel().closeFuture().sync();
} catch (Exception e) {
e.printStackTrace();
} finally {
group.shutdownGracefully();
}
}
}