1、Netty实现服务端与客户端数据传输
1)、依赖
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.12.Final</version>
</dependency>
<!-- 序列化框架marshalling -->
<dependency>
<groupId>org.jboss.marshalling</groupId>
<artifactId>jboss-marshalling</artifactId>
<version>1.3.0.CR9</version>
</dependency>
<dependency>
<groupId>org.jboss.marshalling</groupId>
<artifactId>jboss-marshalling-serial</artifactId>
<version>1.3.0.CR9</version>
</dependency>
<dependency>
<groupId>com.lmax</groupId>
<artifactId>disruptor</artifactId>
<version>3.3.2</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
</dependency>
2)、common
@Data
public class TranslatorData implements Serializable {
private String id;
private String name;
private String message;
}
/**
* Marshalling工厂
*/
public final class MarshallingCodeCFactory {
/**
* 创建Jboss Marshalling解码器MarshallingDecoder
*
* @return MarshallingDecoder
*/
public static MarshallingDecoder buildMarshallingDecoder() {
// 首先通过Marshalling工具类的精通方法获取Marshalling实例对象 参数serial标识创建的是java序列化工厂对象。
final MarshallerFactory marshallerFactory = Marshalling.getProvidedMarshallerFactory("serial");
// 创建了MarshallingConfiguration对象,配置了版本号为5
final MarshallingConfiguration configuration = new MarshallingConfiguration();
configuration.setVersion(5);
// 根据marshallerFactory和configuration创建provider
UnmarshallerProvider provider = new DefaultUnmarshallerProvider(marshallerFactory, configuration);
// 构建Netty的MarshallingDecoder对象,俩个参数分别为provider和单个消息序列化后的最大长度
return new MarshallingDecoder(provider, 1024 * 1024 * 1);
}
/**
* 创建Jboss Marshalling编码器MarshallingEncoder
*
* @return MarshallingEncoder
*/
public static MarshallingEncoder buildMarshallingEncoder() {
final MarshallerFactory marshallerFactory = Marshalling.getProvidedMarshallerFactory("serial");
final MarshallingConfiguration configuration = new MarshallingConfiguration();
configuration.setVersion(5);
MarshallerProvider provider = new DefaultMarshallerProvider(marshallerFactory, configuration);
// 构建Netty的MarshallingEncoder对象,MarshallingEncoder用于实现序列化接口的POJO对象序列化为二进制数组
return new MarshallingEncoder(provider);
}
}
3)、服务端
public class NettyServer {
public NettyServer() {
// 创建两个工作线程组:一个用于接收网络请求的,另一个用于实际处理业务的
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
ServerBootstrap serverBootstrap = new ServerBootstrap();
try {
serverBootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 1024)
// 缓存区动态调配(自适应)
.option(ChannelOption.RCVBUF_ALLOCATOR, AdaptiveRecvByteBufAllocator.DEFAULT)
// 缓冲区池化操作
.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel sc) throws Exception {
sc.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingDecoder());
sc.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingEncoder());
sc.pipeline().addLast(new ServerHandler());
}
});
// 绑定端口,同步等等请求连接
ChannelFuture cf = serverBootstrap.bind(8765).sync();
System.out.println("Server Startup...");
cf.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// 优雅停机
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
System.out.println("Sever ShutDown...");
}
}
}
public class ServerHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
TranslatorData request = (TranslatorData) msg;
System.out.println("Server端:id=" + request.getId()
+ ", name=" + request.getName()
+ ", message=" + request.getMessage());
TranslatorData response = new TranslatorData();
response.setId("resp:" + request.getId());
response.setName("resp:" + request.getName());
response.setMessage("resp:" + request.getMessage());
ctx.writeAndFlush(response);
}
}
@SpringBootApplication
public class NettyServerApplication {
public static void main(String[] args) {
SpringApplication.run(NettyServerApplication.class, args);
new NettyServer();
}
}
4)、客户端
public class NettyClient {
public static final String HOST = "127.0.0.1";
public static final int PORT = 8765;
private EventLoopGroup group = new NioEventLoopGroup();
private Channel channel;
private ChannelFuture cf;
public NettyClient() {
this.connect(HOST, PORT);
}
private void connect(String host, int port) {
Bootstrap bootstrap = new Bootstrap();
try {
bootstrap.group(group)
.channel(NioSocketChannel.class)
// 缓存区动态调配(自适应)
.option(ChannelOption.RCVBUF_ALLOCATOR, AdaptiveRecvByteBufAllocator.DEFAULT)
// 缓冲区池化操作
.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
.handler(new LoggingHandler(LogLevel.INFO))
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel sc) throws Exception {
sc.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingDecoder());
sc.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingEncoder());
sc.pipeline().addLast(new ClientHandler());
}
});
this.cf = bootstrap.connect(host, port).sync();
System.out.println("Client connected...");
this.channel = cf.channel();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void sendData() {
for (int i = 0; i < 10; i++) {
TranslatorData request = new TranslatorData();
request.setId("" + i);
request.setName("请求消息名称" + i);
request.setMessage("请求消息内容" + i);
this.channel.writeAndFlush(request);
}
}
public void close() throws Exception {
cf.channel().closeFuture().sync();
// 优雅停机
group.shutdownGracefully();
System.out.println("Sever ShutDown...");
}
}
public class ClientHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
try {
TranslatorData response = (TranslatorData) msg;
System.out.println("Client端:id=" + response.getId()
+ ", name=" + response.getName()
+ ", message=" + response.getMessage());
} finally {
// 释放缓存
ReferenceCountUtil.release(msg);
}
}
}
@SpringBootApplication
public class NettyClientApplication {
public static void main(String[] args) {
SpringApplication.run(NettyClientApplication.class, args);
// 建立连接并发送消息
new NettyClient().sendData();
}
}
2、集成Disruptor
1)、common
@Data
public class TranslatorDataWrapper {
private TranslatorData translatorData;
private ChannelHandlerContext channelHandlerContext;
}
@Data
public abstract class MessageConsumer implements WorkHandler<TranslatorDataWrapper> {
protected String consumerId;
public MessageConsumer(String consumerId) {
this.consumerId = consumerId;
}
}
public class MessageProducer {
private String producerId;
private RingBuffer<TranslatorDataWrapper> ringBuffer;
public MessageProducer(String producerId,
RingBuffer<TranslatorDataWrapper> ringBuffer) {
this.producerId = producerId;
this.ringBuffer = ringBuffer;
}
public void sendData(TranslatorData data, ChannelHandlerContext ctx) {
long sequence = ringBuffer.next();
try {
TranslatorDataWrapper wrapper = ringBuffer.get(sequence);
wrapper.setTranslatorData(data);
wrapper.setChannelHandlerContext(ctx);
} finally {
ringBuffer.publish(sequence);
}
}
}
public class RingBufferWorkerPoolFactory {
private static class SingletonHolder {
static final RingBufferWorkerPoolFactory INSTANCE = new RingBufferWorkerPoolFactory();
}
private RingBufferWorkerPoolFactory() {
}
public static RingBufferWorkerPoolFactory getInstance() {
return SingletonHolder.INSTANCE;
}
private static Map<String, MessageProducer> producers = new ConcurrentHashMap<>();
private static Map<String, MessageConsumer> consumers = new ConcurrentHashMap<>();
private RingBuffer<TranslatorDataWrapper> ringBuffer;
private SequenceBarrier sequenceBarrier;
private WorkerPool<TranslatorDataWrapper> workerPool;
public void initAndStart(ProducerType producerType,
int bufferSize,
WaitStrategy waitStrategy,
MessageConsumer[] messageConsumers) {
// 1.构建ringBuffer对象
this.ringBuffer = RingBuffer.create(producerType,
new EventFactory<TranslatorDataWrapper>() {
@Override
public TranslatorDataWrapper newInstance() {
return new TranslatorDataWrapper();
}
},
bufferSize,
waitStrategy);
// 2.设置序号栅栏
this.sequenceBarrier = ringBuffer.newBarrier();
// 3.设置工作池
this.workerPool = new WorkerPool<>(
this.ringBuffer,
this.sequenceBarrier,
new EventExceptionHandler(),
messageConsumers);
// 4.把所构建的消费者置入池中
for (MessageConsumer consumer : messageConsumers) {
consumers.put(consumer.getConsumerId(), consumer);
}
// 5.添加sequences
this.ringBuffer.addGatingSequences(this.workerPool.getWorkerSequences());
// 6.启动工作池
this.workerPool.start(
Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() / 2)
);
}
public MessageProducer getMessageProducer(String producerId) {
MessageProducer messageProducer = producers.get(producerId);
if (null == messageProducer) {
messageProducer = new MessageProducer(producerId, this.ringBuffer);
producers.put(producerId, messageProducer);
}
return messageProducer;
}
static class EventExceptionHandler implements ExceptionHandler<TranslatorDataWrapper> {
@Override
public void handleEventException(Throwable ex, long sequence, TranslatorDataWrapper event) {
}
@Override
public void handleOnStartException(Throwable ex) {
}
@Override
public void handleOnShutdownException(Throwable ex) {
}
}
}
2)、服务端
public class ServerHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
TranslatorData request = (TranslatorData) msg;
String producerId = "code:sessionId:001";
MessageProducer messageProducer = RingBufferWorkerPoolFactory.getInstance().getMessageProducer(producerId);
messageProducer.sendData(request, ctx);
}
}
public class MessageConsumerImplForServer extends MessageConsumer {
public MessageConsumerImplForServer(String consumerId) {
super(consumerId);
}
@Override
public void onEvent(TranslatorDataWrapper event) throws Exception {
TranslatorData translatorData = event.getTranslatorData();
System.out.println("Server端:id=" + translatorData.getId()
+ ", name=" + translatorData.getName()
+ ", message=" + translatorData.getMessage());
TranslatorData response = new TranslatorData();
response.setId("resp:" + translatorData.getId());
response.setName("resp:" + translatorData.getName());
response.setMessage("resp:" + translatorData.getMessage());
event.getChannelHandlerContext().writeAndFlush(response);
}
}
@SpringBootApplication
public class NettyServerApplication {
public static void main(String[] args) {
SpringApplication.run(NettyServerApplication.class, args);
MessageConsumer[] consumers = new MessageConsumer[4];
for (int i = 0; i < consumers.length; ++i) {
consumers[i] = new MessageConsumerImplForServer("code:serverId:" + i);
}
RingBufferWorkerPoolFactory.getInstance().initAndStart(
ProducerType.MULTI,
1024 * 1024,
new BlockingWaitStrategy(),
consumers);
new NettyServer();
}
}
3)、客户端
public class ClientHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
TranslatorData response = (TranslatorData) msg;
String producerId = "code:sessionId:002";
MessageProducer messageProducer = RingBufferWorkerPoolFactory.getInstance().getMessageProducer(producerId);
messageProducer.sendData(response, ctx);
}
}
public class MessageConsumerImplForClient extends MessageConsumer {
public MessageConsumerImplForClient(String consumerId) {
super(consumerId);
}
@Override
public void onEvent(TranslatorDataWrapper event) throws Exception {
TranslatorData translatorData = event.getTranslatorData();
try {
System.out.println("Client端:id=" + translatorData.getId()
+ ", name=" + translatorData.getName()
+ ", message=" + translatorData.getMessage());
} finally {
// 释放缓存
ReferenceCountUtil.release(translatorData);
}
}
}
@SpringBootApplication
public class NettyClientApplication {
public static void main(String[] args) {
SpringApplication.run(NettyClientApplication.class, args);
MessageConsumer[] consumers = new MessageConsumer[4];
for (int i = 0; i < consumers.length; ++i) {
consumers[i] = new MessageConsumerImplForClient("code:clientId:" + i);
}
RingBufferWorkerPoolFactory.getInstance().initAndStart(
ProducerType.MULTI,
1024 * 1024,
new BlockingWaitStrategy(),
consumers);
// 建立连接并发送消息
new NettyClient().sendData();
}
}
推荐资料: