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

Java使用Netty生成代理需要使用动态代理技术。下面是一个简单的示例代码,演示了如何使用Netty生成代理: ```java import io.netty.bootstrap.Bootstrap; import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; 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; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; interface MyService { String hello(String name); } class MyServiceHandler extends ChannelInboundHandlerAdapter { private Object result; public Object getResult() { return result; } @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { result = msg; ctx.close(); } } class MyServiceProxy implements InvocationHandler { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { EventLoopGroup group = new NioEventLoopGroup(); try { MyServiceHandler handler = new MyServiceHandler(); Bootstrap bootstrap = new Bootstrap(); bootstrap.group(group) .channel(NioSocketChannel.class) .option(ChannelOption.TCP_NODELAY, true) .handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(handler); } }); Channel channel = bootstrap.connect("localhost", 8888).sync().channel(); channel.writeAndFlush(args[0]); channel.closeFuture().sync(); return handler.getResult(); } finally { group.shutdownGracefully(); } } } public class NettyProxyExample { public static void main(String[] args) { MyService myService = (MyService) Proxy.newProxyInstance( NettyProxyExample.class.getClassLoader(), new Class[]{MyService.class}, new MyServiceProxy() ); String result = myService.hello("World"); System.out.println(result); } } ``` 以上示例代码中,定义了一个`MyService`接口,代表需要代理的服务。`MyServiceHandler`是Netty的`ChannelInboundHandlerAdapter`的子类,用于处理接收到的响应消息,并将结果存储在`result`变量中。`MyServiceProxy`是动态代理的实现类,它通过Netty客户端与服务器进行通信,并将代理方法的参数发送给服务器,然后等待服务器返回结果。 在`NettyProxyExample`的`main`方法中,使用`Proxy.newProxyInstance`方法创建了一个代理对象,该代理对象实现了`MyService`接口,并使用`MyServiceProxy`作为其调用处理器。通过代理对象调用接口方法时,实际上是调用了`MyServiceProxy`的`invoke`方法,在该方法内部使用Netty进行远程调用并获取结果。 请注意,以上示例仅仅是一个简单的示例,实际应用中可能需要根据具体需求进行适当修改和扩展。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值