ネッティーは、2つのTCPスティックパッケージ開梱とネッティーTCPスティック包装を解く開梱を学びます

1、開梱TCPスティックパッケージ

オペレーティングシステム

我々は、すべてのオペレーティング・システム・カーネルのコアは、通常の外のアプリケーションとは独立して、あなたが保護されたメモリ空間にアクセスできることを知っているだけでなく、基盤となるハードウェアへのすべてのアクセス。
直接カーネルの安全性を確保するために、カーネルの操作にアクセスすることができないユーザのプロセスを保護するため、オペレーティングシステムは、2つの部分、カーネル空間に対して1つの、ユーザ空間の別の部分に分割されます。

I/O模型

セキュリティは、オペレーティングシステムの理由で、プロセスは、各I / Oデバイスは、バッファ(バッファ)を維持するためのI / O操作がシステムコールを介してカーネル、カーネルを要求する必要があり完了するために、直接I / Oデバイスにアクセスすることができません

全体のプロセスが要求されます。

カーネルは、I / Oデバイスへのバッファからデータを取得するための要求を受信した後1、利用者は、要求処理を開始し
2を、データがユーザプロセスのアドレス空間内のバッファコピーし
、クライアント3への応答の後、再び、ユーザプロセスがデータを取得し、終了

スティック包装と開梱

オペレーティング・システムは、第1データバッファに格納されているTCPプロトコルを介してデータを送信する場合も同様に、バッファサイズは1024バイトと仮定されます

スティックパッケージ

パケット送信は、バッファのサイズよりもはるかに小さく、比較的小さい場合、TCPパケットは、スティックパッケージを発生し、複数のデータパケットに結合します

開梱

パケット送信は、バッファのサイズよりもはるかに大きく、比較的大きい場合、TCPパケットはアンパック発生する複数のデータパケットに分割され

  • サーバーは二度2つの独立したデータ・パケットを、それぞれD1およびD2を読み、開梱パッケージを貼りません
  • サーバーは、2つの、D1およびD2が一緒に固執するパケットを受信し、それがスティックパッケージを発生しました
  • D2 D2_2の残りの部分を読むためにパッケージの一部、第二のパッケージ - Serverは二回2つのデータパケット、完全な読み取りパケットD1およびD2 D2_1を読みます
  • サーバーは二回2つのデータパケット、読み出し部ポイントD1_1 D1、およびパケットの完全なパッケージD1_2 D1およびD2の残りを読むために第二を読みます

2、解決開梱TCPスティックパッケージ

TCPスティック包装のためのソリューションの以下の4種類、問題を開梱

(1)このような各パケットのサイズとして固定長のメッセージは、128バイトであり、そうでない場合、隙間を埋めます

(2)その後、次のパケットを介して送信した後\ R \ nは、その後に供待つパケットが分割されている場合、例えば\ Rの\ nに対して、各パケットの固定端デリミタを使用してクライアントスプリットヘッド部分は、このように完全なパッケージを得ること、バッグの前面の残りの部分と合流した後

(3)メッセージ・ヘッダとメッセージ本体に、メッセージヘッダの長さ全体に格納された電流は、十分な長さの読み取りが完了したメッセージとして考慮すべき唯一の後にメッセージが読み取ら

(4)スティックパッケージとアンパック処理カスタムプロトコルによって実行されます

開梱3、ネッティー模範的なスティック包装

クライアントは、メッセージクライアント3にメッセージや返信を受け取った後、サーバー、サーバーへの3つのメッセージを送信します

クライアント

public class HelloWorldClient {

    private int port;
    private String address;

    public HelloWorldClient(int port, String address) {
        this.port = port;
        this.address = address;
    }

    public void start() {
        EventLoopGroup group = new NioEventLoopGroup();

        Bootstrap bootstrap = new Bootstrap();
        bootstrap.group(group).channel(NioSocketChannel.class)
                .handler(new ChannelInitializer<SocketChannel>(){

                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        ChannelPipeline pipeline = socketChannel.pipeline();
                        
                        pipeline.addLast("decoder", new StringDecoder());// 字符串解码和编码
                        pipeline.addLast("encoder", new StringEncoder());
                        pipeline.addLast("handler", new ChannelInboundHandlerAdapter(){
                            
                            @Override
                            public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                                System.out.println("客户端收到消息:[" + msg + "]");
                            }
                        });//自定义handler
                    }
                });

        try {
            ChannelFuture future = bootstrap.connect(address,port).sync();
            Channel channel = future.channel();
            channel.writeAndFlush("我是客户端,地址:" + channel.remoteAddress());
            channel.closeFuture().sync();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            group.shutdownGracefully();
        }
    }

    public static void main(String[] args) {
        HelloWorldClient client = new HelloWorldClient(8888, "127.0.0.1");
        client.start();
    }
}

サーバー

public class HelloWorldServer {

    private int port;
    
    public HelloWorldServer(int port) {
        this.port = port;
    }
    
    public void start(){
        EventLoopGroup bossGroup = new NioEventLoopGroup();//创建父子线程组
        EventLoopGroup workGroup = new NioEventLoopGroup();
        
        ServerBootstrap server = new ServerBootstrap();
        server.group(bossGroup, workGroup)
              .channel(NioServerSocketChannel.class)//指定处理客户端的通道
              .childHandler(new ChannelInitializer<SocketChannel>(){

                @Override
                protected void initChannel(SocketChannel socketChannel) throws Exception {
                    ChannelPipeline pipeline = socketChannel.pipeline();
                    
                    pipeline.addLast("decoder", new StringDecoder());// 字符串解码和编码
                    pipeline.addLast("encoder", new StringEncoder());
                    pipeline.addLast("handler", new ChannelInboundHandlerAdapter(){
                        
                        @Override
                        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                            System.out.println("服务端收到消息:[" + msg + "]");
                            ctx.writeAndFlush(Unpooled.copiedBuffer("我是服务端".getBytes()));
                            ctx.writeAndFlush(Unpooled.copiedBuffer("我是服务端".getBytes()));
                            ctx.writeAndFlush(Unpooled.copiedBuffer("我是服务端".getBytes()));
                        }
                    });//自定义handler
                }
              });//通道初始化
        try {
            ChannelFuture future = server.bind(port).sync();
            future.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally{
            bossGroup.shutdownGracefully();
            workGroup.shutdownGracefully();
        }
    }

    public static void main(String[] args) {
        HelloWorldServer server = new HelloWorldServer(8888);
        server.start();
    }
}

結果:
サーバー

クライアント

あなたが見ることができ、クライアントは、3件のメッセージが一緒に立ち往生している受信しました

4、ネッティーは開梱スティックパッケージを解きます

4.1、固定長の使用が解決

クライアントは、治療せずに、サーバーをFixedLengthFrameDecoderニュース固定長のデコーダを追加します

業績

あなたが見ることができる漢字の顔に、文字化けが発生するので、クライアントによって受信されたメッセージは、実際に、固定長の区切り文字である、バイト数で割ったが、原因メッセージの長さに10の以上のバイトです欠点

4.2、区切り文字を使用して

クライアントが定義された$の区切り文字として、initChannel方法を変更します

メッセージサーバのカスタムセパレータプラス$の終わりに

だから、メッセージは、クライアントが別々のメッセージ、ノースティックパッケージを受信することです

おすすめ

転載: www.cnblogs.com/lmj612/p/10976194.html