開梱粘度TCPパケット
1.TCPは、複数のパケットのためのより効果的な毛髪接続指向ストリーム指向の、信頼性の高いサービス、受信機と送信機であり、従って、ソケットの11ペアを持っている必要があり、受信側へ送信端相互に、最適化手法(Nagleアルゴリズム)を用いて、ギャップはデータの一つの大きなブロックへのデータのデータ小さいと複数の少量で、パケットは、そうすることがすることは効率を増加させるが、受信側を区別することは困難です完全なパケットストリーム指向通信メッセージの保護には、境界ではありませんので
2保護縁なしTCPメッセージ、国境問題は、受信側でメッセージを対処する必要があるので、それは問題を開梱、我々はスティックパッケージと呼んでいます。
開梱示すTCPスティックパッケージ、
クライアントは、サービス終了時刻を読み取ることにより、バイト数に、それぞれ、サーバへの2個のパケットD1 D2を送信する不確実であるため、4例があるかもしれないと仮定
1)サーバ2つに二度読み取られます別のデータ・パケット、スティッキーD1 D2パッケージとアンパックされない
)2をサーバ時間は、スティックパッケージTCPに一緒に結合した2個のパケットD1 D2受信し
たデータが二回読み出すサーバと3)パケット、初めて完全なリードパケットパッケージのD1とD2の部分は、開梱TCPと呼ばれるD2の残りの内容の第二読取
4)がサーバ・データ・パケット2回読み出され、リードパケットD1_1の最初の部分- D1、パッケージの内容D1 D1_2 D2及び完全なパッケージの残りの部分に対する第2の読取。
TCPスティック包装と開梱ソリューション
1.カスタム+解決するためのコーデックプロトコル。
2.キーは、この問題を解決するために、たびに読み出したデータの長さを、サーバの問題を解決することであり、それはそれによって、多かれ少なかれ、プライマリサーバ上の問題にリードデータを読むことはありません開梱、TCPスティック包装を避けます。
カスタムTCPはパケット:
二つの特性、長さ、コンテンツがあります。
package com.jym.protocoltcp;
/**
* @program: NettyPro
* @description:
* @author: jym
* @create: 2020/02/12
*/
public class MessageProtocol {
private int len;
private byte[] bytes;
public int getLen() {
return len;
}
public void setLen(int len) {
this.len = len;
}
public byte[] getBytes() {
return bytes;
}
public void setBytes(byte[] bytes) {
this.bytes = bytes;
}
}
カスタムコーデック:
エンコーダー:
package com.jym.protocoltcp;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
/**
* @program: NettyPro
* @description:
* @author: jym
* @create: 2020/02/12
*/
public class MessageEncoder extends MessageToByteEncoder<MessageProtocol> {
private int count;
@Override
protected void encode(ChannelHandlerContext channelHandlerContext, MessageProtocol messageProtocol, ByteBuf byteBuf) throws Exception {
System.out.println("MessageEncoder encode方法被调用"+(++this.count)+"次");
byteBuf.writeInt(messageProtocol.getLen());
byteBuf.writeBytes(messageProtocol.getBytes());
}
}
デコーダー:
package com.jym.protocoltcp;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ReplayingDecoder;
import java.util.List;
/**
* @program: NettyPro
* @description:
* @author: jym
* @create: 2020/02/12
*/
public class MessageDecoder extends ReplayingDecoder<Void> {
private int count;
@Override
protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception {
System.out.println("MessageDecoder 方法被调用"+(++this.count));
// 将二进制字节码 -> messageProtocol
int length = byteBuf.readInt();
byte[] content = new byte[length];
byteBuf.readBytes(content);
// 分装成messageProtocol 给下一个handler去处理
MessageProtocol messageProtocol = new MessageProtocol();
messageProtocol.setLen(length);
messageProtocol.setBytes(content);
list.add(messageProtocol);
}
}
サーバー:
package com.jym.protocoltcp;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
/**
* @program: NettyPro
* @description:
* @author: jym
* @create: 2020/02/11
*/
public class TcpServer {
public static void main(String[] args) {
EventLoopGroup boosGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(boosGroup,workerGroup).channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG,128)
.childOption(ChannelOption.SO_KEEPALIVE,true)
.childHandler(new TcpSeverInitializer());
ChannelFuture sync = serverBootstrap.bind(7000).sync();
sync.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
boosGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
初期化子サーバとハンドラ
package com.jym.protocoltcp;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
/**
* @program: NettyPro
* @description:
* @author: jym
* @create: 2020/02/12
*/
public class TcpSeverInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pipeline = socketChannel.pipeline();
pipeline.addLast(new MessageDecoder());
pipeline.addLast(new MessageEncoder());
pipeline.addLast(new TcpSeverHandler());
}
}
package com.jym.protocoltcp;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import java.nio.charset.Charset;
import java.util.UUID;
/**
* @program: NettyPro
* @description:
* @author: jym
* @create: 2020/02/12
*/
public class TcpSeverHandler extends SimpleChannelInboundHandler<MessageProtocol> {
private int count;
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
ctx.close();
}
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, MessageProtocol messageProtocol) throws Exception {
int len = messageProtocol.getLen();
byte[] bytes = messageProtocol.getBytes();
System.out.println("服务端接收信息如下");
System.out.println("长度=" + len);
System.out.println("内容=" + new String(bytes, Charset.forName("utf-8")));
System.out.println("服务器接受消息包的数量" +(++this.count));
// 回复消息
String s = UUID.randomUUID().toString();
int length = s.getBytes("utf-8").length;
MessageProtocol resp = new MessageProtocol();
resp.setLen(length);
resp.setBytes(s.getBytes("utf-8"));
channelHandlerContext.writeAndFlush(resp);
}
}
クライアント:
package com.jym.protocoltcp;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
/**
* @program: NettyPro
* @description:
* @author: jym
* @create: 2020/02/11
*/
public class TcpClient {
public static void main(String[] args) {
NioEventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(group).channel(NioSocketChannel.class)
.handler(new TcpClientInitializer());
ChannelFuture sync = bootstrap.connect("127.0.0.1", 7000).sync();
sync.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
group.shutdownGracefully();
}
}
}
初期化子サーバとハンドラ
package com.jym.protocoltcp;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
/**
* @program: NettyPro
* @description:
* @author: jym
* @create: 2020/02/12
*/
public class TcpClientInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pipeline = socketChannel.pipeline();
pipeline.addLast(new MessageEncoder());
pipeline.addLast(new MessageDecoder());
pipeline.addLast(new TcpClientHandler());
}
}
package com.jym.protocoltcp;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import java.nio.charset.Charset;
/**
* @program: NettyPro
* @description:
* @author: jym
* @create: 2020/02/12
*/
public class TcpClientHandler extends SimpleChannelInboundHandler<MessageProtocol> {
private int count;
/**
* 使用客户端发送10条数据,保温杯里泡枸杞
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
for(int i = 0; i < 10; i++){
String message = "保温杯里泡枸杞";
byte[] bytes = message.getBytes(Charset.forName("utf-8"));
int length = message.getBytes(Charset.forName("utf-8")).length;
// 创建协议包
MessageProtocol messageProtocol = new MessageProtocol();
messageProtocol.setLen(length);
messageProtocol.setBytes(bytes);
ctx.writeAndFlush(messageProtocol);
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
ctx.close();
}
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, MessageProtocol messageProtocol) throws Exception {
System.out.println("从服务端接受到消息:");
System.out.println("接收到的长度为:"+ messageProtocol.getLen());
System.out.println("接收到的内容为:"+ new String(messageProtocol.getBytes(),Charset.forName("utf-8")));
}
}
主にカスタム・データ・パケットを通過するので、各プロセスパケットハンドラという、読み取りデータ長は解決するために