pom.xml包引入
com.google.protobuf
protobuf-java
3.5.1
com.googlecode.protobuf-java-format
protobuf-java-format
1.2
io.netty
netty-codec
4.1.24.Final
Service端代码
package cn.shuzilm.interf.rtb;
import cn.shuzilm.backend.rtb.RuleMatching;
import cn.shuzilm.bean.youyi.BidserverSsp;
import cn.shuzilm.common.AppConfigs;
import cn.shuzilm.common.jedis.JedisManager;
import io.netty.bootstrap.*;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.protobuf.ProtobufDecoder;
import io.netty.handler.codec.protobuf.ProtobufEncoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender;
import io.netty.handler.timeout.IdleStateHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.Connection;
/**
* @Description: netty4 + protobuf
* @Author: houkp
* @CreateDate: 2018/11/20 19:35
* @UpdateUser: houkp
* @UpdateDate: 2018/11/20 19:35
* @UpdateRemark: 修改内容
* @Version: 1.0
*/
public class RtbServer {
private static RuleMatching ruleMatching;
private static JedisManager jedisManager;
private static AppConfigs configs = null;
private static final String FILTER_CONFIG = "filter.properties";
private static final Logger log = LoggerFactory.getLogger(RtbServer.class);
public static void main(String[] args) {
try {
//configs = AppConfigs.getInstance(FILTER_CONFIG);
//初始化redis
//jedisManager = JedisManager.getInstance();
//初始化广告
//ruleMatching = RuleMatching.getInstance();
RtbServer server = new RtbServer();
//server.start(configs.getInt("RTB_PORT"));
server.start(8710);
} catch (Exception e) {
log.error("创建服务异常", e);
}
}
public void start(int port) {
// boss线程池
EventLoopGroup bossGroup = new NioEventLoopGroup();
// worker线程池
EventLoopGroup workerGroup = new NioEventLoopGroup();
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workerGroup);
// 使用TCP
bootstrap.channel(NioServerSocketChannel.class);
// BACKLOG用于构造服务端套接字ServerSocket对象,标识当服务器请求处理线程全满时,用于临时存放已完成三次握手的请求的队列的最大长度。如果未设置或所设置的值小于1,Java将使用默认值50。
bootstrap.option(ChannelOption.SO_BACKLOG, 128);
// 是否启用心跳保活机制。在双方TCP套接字建立连接后(即都进入ESTABLISHED状态)并且在两个小时左右上层没有任何数据传输的情况下,这套机制才会被激活。
bootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);
// 初始化配置的处理器
bootstrap.childHandler(new ServerPipelineFactory());
try {
ChannelFuture f = bootstrap.bind(port).sync();
f.channel().closeFuture().sync();
} catch (InterruptedException e) {
log.error("服务启动异常", e);
e.printStackTrace();
} finally {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
private class ServerPipelineFactory extends ChannelInitializer {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pipeline = socketChannel.pipeline();
// ----Protobuf处理器,这里的配置是关键----
pipeline.addLast("frameDecoder", new ProtobufVarint32FrameDecoder());// 用于decode前解决半包和粘包问题(利用包头中的包含数组长度来识别半包粘包)
//配置Protobuf解码处理器,消息接收到了就会自动解码,ProtobufDecoder是netty自带的,Message是自己定义的Protobuf类
pipeline.addLast("protobufDecoder", new ProtobufDecoder(BidserverSsp.BidRequest.getDefaultInstance()));
// 用于在序列化的字节数组前加上一个简单的包头,只包含序列化的字节长度。
pipeline.addLast("frameEncoder", new ProtobufVarint32LengthFieldPrepender());
//配置Protobuf编码器,发送的消息会先经过编码
pipeline.addLast("protobufEncoder", new ProtobufEncoder());
// ----Protobuf处理器END----
pipeline.addLast("handler", new RtbHandler());//自己定义的消息处理器,接收消息会在这个类处理
}
}
}
package cn.shuzilm.interf.rtb;
import cn.shuzilm.bean.youyi.BidserverSsp;
import cn.shuzilm.interf.rtb.parser.RtbRequestParser;
import com.google.protobuf.Message;
import com.googlecode.protobuf.format.JsonFormat;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.UnsupportedEncodingException;
import java.util.List;
/**
* 对应不同版本的SDK,netty需要做相应的修改: 1、队列名 2、日志路径 3、maven包名,用端口号做区分
*
* @author
*/
public class RtbHandler extends SimpleChannelInboundHandler {
private static final Logger log = LoggerFactory.getLogger(RtbHandler.class);
private static BidserverSsp.BidRequest bidRequest = BidserverSsp.BidRequest.newBuilder().buildPartial();
RtbRequestParser parser = null;
public RtbHandler() {
parser = new RtbRequestParser();
System.out.println(Thread.currentThread().getName() + " rtb parser 初始化成功。。。");
}
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, Message message) throws Exception {
System.out.println(message.getClass());
bidRequest = (BidserverSsp.BidRequest) message;
String sessionId = bidRequest.getSessionId();
List adzoneList = bidRequest.getAdzoneList();
BidserverSsp.BidRequest.Exchange exchange = bidRequest.getExchange();
// System.out.println(adzoneList);
// System.out.println(exchange.toBuilder());
// String jsonString =JsonFormat.printToString(bidRequest);
// log.debug("jsonString",jsonString);
log.debug("sessionId:{}",sessionId);
log.debug("channelHandlerContext:{}", channelHandlerContext);
log.debug("channelHandlerContext:{}", channelHandlerContext.channel().remoteAddress());
BidserverSsp.BidResponse bidResponse = BidserverSsp.BidResponse.newBuilder().setSessionId(sessionId).build();
// 返回客户端消息 - 我已经接收到了你的消息
channelHandlerContext.writeAndFlush(bidResponse);
}
/*
* 覆盖 channelActive 方法 在channel被启用的时候触发 (在建立连接的时候)
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("RamoteAddress : " + ctx.channel().remoteAddress() + " active !");
String welcome = "Welcome to " + InetAddress.getLocalHost().getHostName() + " service!";
BidserverSsp.BidResponse bidResponse = BidserverSsp.BidResponse.newBuilder().setSessionId(welcome).build();
ctx.writeAndFlush(bidResponse);
super.channelActive(ctx);
}
/**
* 解析进来的请求数据
*
* @throws UnsupportedEncodingException
*/
public String parseRequest(String url, String dataStr, String remoteIp) throws Exception {
/********** POST主业务逻辑 ***************/
String resultData = parser.parseData(url, dataStr, remoteIp);//SDK 2.0.1
// byte[] content = null;
// content = resultData.getBytes("utf-8");
return resultData;
}
}
Client端代码
package cn.shuzilm.interf.rtb.parser.client;
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 String host = "172.17.129.124";
public static int port = 9710;
public static void main(String[] args) {
EventLoopGroup worker = new NioEventLoopGroup();
Bootstrap b = new Bootstrap();
b.group(worker);
b.channel(NioSocketChannel.class);
b.handler(new ClientInitializer());
try {
ChannelFuture f = b.connect(host, port).sync();
f.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
worker.shutdownGracefully();
}
}
}
package cn.shuzilm.interf.rtb.parser.client;
import cn.shuzilm.bean.youyi.BidserverSsp;
import com.google.protobuf.Message;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import java.util.UUID;
public class ClientHandler extends SimpleChannelInboundHandler {
/**
*
*/
protected void channelRead0(ChannelHandlerContext ctx, Message msg) throws Exception {
System.out.println("Server say : " + msg.getClass());
BidserverSsp.BidResponse bidRequest = (BidserverSsp.BidResponse) msg;
System.out.println(bidRequest.getSessionId());
}
/**
*
*/
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("Client active ");
String id = UUID.randomUUID().toString().replaceAll("-", "");
BidserverSsp.BidRequest bidRequest = BidserverSsp.BidRequest.newBuilder().setSessionId(id).build();
ctx.writeAndFlush(bidRequest);
super.channelActive(ctx);
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
System.out.println("Client close ");
super.channelInactive(ctx);
}
}
package cn.shuzilm.interf.rtb.parser.client;
import cn.shuzilm.bean.youyi.BidserverSsp;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.codec.protobuf.ProtobufDecoder;
import io.netty.handler.codec.protobuf.ProtobufEncoder;
public class ClientInitializer extends ChannelInitializer {
protected void initChannel(SocketChannel ch) throws Exception {
// decoded
// ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(1024, 0, 4, 0, 4));
//这里是收到服务端发过来的消息,所以是对服务端的response解码
ch.pipeline().addLast(new ProtobufDecoder(BidserverSsp.BidResponse.getDefaultInstance()));
// encoded
// ch.pipeline().addLast(new LengthFieldPrepender(4));
ch.pipeline().addLast(new ProtobufEncoder());
// 注册handler
ch.pipeline().addLast(new ClientHandler());
}
}