netty 开发的基本流程
实现客户端、服务器端
实现思路
netty 依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>netty-serv</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<!-- 服务器客户端分为两个模块 -->
<modules>
<module>netty-tcp-serv</module>
<module>netty-tcp-client</module>
</modules>
<dependencies>
<!-- netty依赖 -->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.50.Final</version>
</dependency>
</dependencies>
</project>
服务器代码实现
package org.skystep.tcpserv;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
public class Server {
public static void main(String[] args) {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup wokerGroup = new NioEventLoopGroup();
try {
//用于启动NIO服务
ServerBootstrap serverBootstrap = new ServerBootstrap();
//通过工厂方法设计模式实例化一个channel
serverBootstrap.group(bossGroup, wokerGroup).channel(NioServerSocketChannel.class)
.childHandler(new ServerInitializer());
//绑定服务器,该实例将提供有关IO操作的结果或状态的信息
ChannelFuture channelFuture = serverBootstrap.bind(8899).sync();
System.out.println("在" + channelFuture.channel().localAddress() + "上开启监听");
//阻塞操作,closeFuture()开启了一个channel的监听器(这期间channel在进行各项工作),直到链路断开
channelFuture.channel().closeFuture().sync();
} catch (InterruptedException e) {
bossGroup.shutdownGracefully();
wokerGroup.shutdownGracefully();
}
}
}
package org.skystep.tcpserv;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.CharsetUtil;
@ChannelHandler.Sharable
public class ServerHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
//处理收到的数据,并反馈消息到到客户端
ByteBuf in = (ByteBuf) msg;
System.out.println("收到客户端发过来的消息: " + in.toString(CharsetUtil.UTF_8));
//写入并发送信息到远端(客户端)
ctx.writeAndFlush(Unpooled.copiedBuffer("你好,我是服务端,我已经收到你发送的消息", CharsetUtil.UTF_8));
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception
{
//出现异常的时候执行的动作(打印并关闭通道)
cause.printStackTrace();
ctx.close();
}
}
package org.skystep.tcpserv;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
public class ServerInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pipeline = socketChannel.pipeline();
//自己定义的处理器
pipeline.addLast(new ServerHandler());
}
}
客户端代码实现
package org.skystep.tcpclient;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
public class Client {
public static void main(String[] args) {
EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(eventLoopGroup).channel(NioSocketChannel.class)
.handler(new ClientInitializer());
ChannelFuture channelFuture = bootstrap.connect("localhost", 8899).sync();
channelFuture.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
eventLoopGroup.shutdownGracefully();
}
}
}
package org.skystep.tcpclient;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.CharsetUtil;
public class ClientInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pipeline = socketChannel.pipeline();
pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8));
pipeline.addLast(new StringEncoder(CharsetUtil.UTF_8));
pipeline.addLast(new ClientHandler());
}
}
package org.skystep.tcpclient;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import java.time.LocalDateTime;
public class ClientHandler extends SimpleChannelInboundHandler<String> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
//服务端的远程地址
System.out.println(ctx.channel().remoteAddress());
System.out.println("client output: "+msg);
ctx.writeAndFlush("from client: "+ LocalDateTime.now());
}
/**
* 当服务器端与客户端进行建立连接的时候会触发,如果没有触发读写操作,则客户端和客户端之间不会进行数据通信,也就是channelRead0不会执行,
* 当通道连接的时候,触发channelActive方法向服务端发送数据触发服务器端的handler的channelRead0回调,然后
* 服务端向客户端发送数据触发客户端的channelRead0,依次触发。
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ctx.writeAndFlush("来自与客户端的问题!");
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
netty 关键知识点