Java使用netty

netty,io與nio的區別,先上代碼在分析:

<dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-all</artifactId>
    <version>4.1.0.Final</version>
</dependency>

依賴引入

 

io與nio雖然目標不一樣,但操作還是一樣的:

 

 

接收請求服務類代碼:

package com.kaige123.daomu.bootjsp.netty;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;

public class server {

    private int port = 8081;

    public void run() throws Exception {
        //bossGroup 用來接收進來的連接
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        //workerGroup 用來處理已經被接收的連接
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            //啓動 NIO 服務的輔助啓動類
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        public void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline().addLast(new serverHandle());
                        }
                    })
                    .option(ChannelOption.SO_BACKLOG, 128)
                    .childOption(ChannelOption.SO_KEEPALIVE, true);

            // 服務器綁定端口
            ChannelFuture f = b.bind(port).sync();
            // 等待服務器 socket 關閉 。
            f.channel().closeFuture().sync();
        } finally {
            // 出現異常終止
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
            System.out.println("連接關閉等異常");
        }
    }

    public static void main(String[] args) throws Exception {
        new server().run();
    }

}

 

服務器綁定端口,綁定收到請求後的處理者,有2個類注意:

bossGroup 與workerGroup ,一個是收到請求池,一個是已連接池。當客戶端斷開後,應該從這裏面剔除

 

 

 

處理請求服務類代碼:

package com.kaige123.daomu.bootjsp.netty;

import com.sun.xml.internal.bind.v2.runtime.unmarshaller.XsiNilLoader;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

import java.io.*;
import java.util.Arrays;

public class serverHandle extends ChannelInboundHandlerAdapter {

    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf result = (ByteBuf) msg;
        byte[] result1 = new byte[result.readableBytes()];
        // msg中存儲的是ByteBuf類型的數據,把數據讀取到byte[]中
        result.readBytes(result1);
        String resultStr = new String(result1);
        // 釋放資源,這行很關鍵
        result.release();

        FileOutputStream fileOutputStream = new FileOutputStream("D:\\Java_apiCopy.rar", true);
        Savedisk(fileOutputStream, result1);

        sendMsg(ctx);
    }

    // 寫入本地磁盤
    public void Savedisk(FileOutputStream fileOutputStream, byte[] bytes) throws IOException {
        fileOutputStream.write(bytes, 0, bytes.length);
        fileOutputStream.close();
    }

    // 向客戶端發送消息
    public void sendMsg(ChannelHandlerContext ctx) {
        String response = "OK BYTES Client!";
        // 發送的數據必須轉換成ByteBuf字節數據數組,進行傳輸
        ByteBuf encoded = ctx.alloc().buffer(response.length());
        encoded.writeBytes(response.getBytes());
        ctx.write(encoded);
        ctx.flush();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        // 當出現異常就關閉連接
        cause.printStackTrace();
        ctx.close();
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ctx.flush();
    }

}

msg字節數據,readableBytes一口氣讀取到本次共傳輸的數據

 

 

客戶端請求代碼:

package com.kaige123.daomu.bootjsp.netty;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;

public class client {

    public void connect(String host, int port) throws Exception {
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try {
            Bootstrap b = new Bootstrap();
            b.group(workerGroup);
            b.channel(NioSocketChannel.class);
            b.option(ChannelOption.SO_KEEPALIVE, true);
            b.handler(new ChannelInitializer<SocketChannel>() {
                @Override
                public void initChannel(SocketChannel ch) throws Exception {
                    ch.pipeline().addLast(new clientHandle());
                }
            });

            // 連接發服務器地址
            ChannelFuture f = b.connect(host, port).sync();
            // 關閉連接
            f.channel().closeFuture().sync();
        } finally {
            workerGroup.shutdownGracefully();
            System.out.println("連接關閉等異常");
        }
    }

    public static void main(String[] args) throws Exception {
        client client = new client();
        client.connect("127.0.0.1", 8081);
    }
}

發送請求,並註冊當連接後,自己的處理者

 

 

客戶端處理代碼:

package com.kaige123.daomu.bootjsp.netty;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

import java.io.FileInputStream;

public class clientHandle extends ChannelInboundHandlerAdapter {

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println("客戶端收到處理");
        ByteBuf result = (ByteBuf) msg;
        byte[] result1 = new byte[result.readableBytes()];
        result.readBytes(result1);
        System.out.println("收到數據:" + result1 + "收到長度: " + result1.length);
        result.release();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        // 當出現異常就關閉連接
        cause.printStackTrace();
        ctx.close();
    }


    // 連接成功後,向server發送消息
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {

        FileInputStream fileInputStream = new FileInputStream("D:\\Java_api.rar");
        byte[] bytes = new byte[1024 * 8];
        int len = -1;
        while ((len = fileInputStream.read(bytes)) != -1) {
            ByteBuf encoded = ctx.alloc().buffer(len);
            encoded.writeBytes(bytes, 0, len);
            ctx.write(encoded);
            ctx.flush();
        }

    }
}

 

io與nio

 

io的分析:一個客戶端一個socket連接,獲得in與out流,在建立的相互相互通信。

1:當有n人來時,一人一個服務就吃不住了。(這點不重要)

2:當雙方連接上時,數據並不是要一直交互的,資源就一直耗着,等對方的信息,這段等待時間是無意義的

 

nio猜測,io有切實幹過n個例題,nio僅是接觸了netty,下面是猜測:

1:netty是一個池,客戶來了養池中,客戶請求抓服務去接待。pass,如果真是這樣,那麼我還不敢用。爲什麼?因爲這樣就不能保證請求者與服務器是同一個,這樣將出現數據混亂的問題

 

1例子求證:

客戶端分2次發出數據,第一次是給客戶端貼上標籤。第二次請求是看客戶端再次請求時,netty是取出貼在客戶端身上的標籤,還是空標籤。如果是取出標籤,說明處理者與客戶端始終是一個,如果是空,說明對象不是同一個

 

申請全局變量:String filename;

長度不爲3,是第一次請求去貼上標籤,並將標籤打印出來。

長度爲3,是第二次請求打印全局變量。如果是一對一,那麼這個標籤就會保持。如果抓新的來服務,標籤就是null,查看打印:

開啓2個客戶端去請求,第一次貼標籤,第二次打印標籤。打印的標籤與貼上的標籤一致。說明什麼?說明一開始去服務與過一段時間去服務的都是同一人同一對象。這樣則沒有問題,保證數據的一致性。否則我不敢用

 

 

區別在於:

 

阻塞與非阻塞,當在read或write時,在幹其他的時間可以的。但會出現問題。如上,第一次請求出來,修改10秒。第二次就收不到了,客戶端發完就死掉了。服務器休息完也沒拿到第二次數據。也就是,這個過程,就連讀連寫,過程不能在做其他事情

 

nio非阻塞,不需要阻塞來接收保證消息是在持續傳輸。即使這個過程中,我去幹其他時間,消息回頭還是會傳遞回來,正常收到。

 

阻塞非阻塞:

阻塞io:我一直等你來信息,保證消息持續傳輸

非阻塞你:我不用守着你來消息,即使這會我中途去幹其他時間浪費了時間,但最後我返回調用處後這個消息還會被處理得到。

這就是阻塞與非阻塞,其區別在於,傳輸過程中其形式不同,從netty切入到nio

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章