Netty(五) - 通道Channel

一、基本介绍

1)、NIO 的通道类似于流,但有些区别如下:

  • 通道可以同时进行读写,而流只能读或者只能写
  • 通道可以实现异步读写数据
  • 通道可以从缓冲读数据,也可以写数据到缓冲

Channel和Buffer2)、BIO 中的 stream 是单向的,例如 FileInputStream 对象只能进行读取数据的操作,而 NIO 中的通道(Channel)是双向的,可以读操作,也可以写操作。

3)、Channel 在 NIO 中是一个接口
public interface Channel extends Closeable

4)、常用的 Channel 类有:FileChannel、DatagramChannel、ServerSocketChannel 和 SocketChannel

5)、FileChannel 用于文件的数据读写,DatagramChannel 用于 UDP 的数据读写,ServerSocketChannel 和 SocketChannel 用于 TCP 的数据读写。

二、常用方法

2.1 FileChannel 类

FileChannel 主要用来对本地文件进行 IO 操作,常见的方法有:

方法描述
int read(ByteBuffer dst)从通道读取数据并放到缓冲区中
int write(ByteBuffer src)把缓冲区的数据写到通道中
long transferFrom(ReadableByteChannel src, long position, long count)从目标通道中复制数据到当前通道
long transferTo(long position, long count, WritableByteChannel target)把数据从当前通道复制给目标通道

三、应用案例

3.1 本地文件写数据

案例要求

1)、使用 ByteBuffer(缓冲)和 FileChannel(通道),将"Hello,World!",写入到 file01.txt 中
2)、文件不存在就创建
3)、代码演示

public class NIOFileChannel01 {

    public static void main(String[] args) throws IOException {

        String str = "Hello,World!";

        // 创建一个输出流->channel
        FileOutputStream fileOutputStream = new FileOutputStream("d:\\file01.txt");

        // 通过 fileOutputStream 获取对应的 FileChannel
        // 这个 fileChannel 真实类型是 FileChannelImpl
        FileChannel fileChannel = fileOutputStream.getChannel();

        // 创建一个缓冲区 ByteBuffer
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);

        // 将 str 放入到 byteBuffer
        byteBuffer.put(str.getBytes());

        // 对 byteBuffer 进行反转(flip)
        byteBuffer.flip();

        // 将 byteBuffer 数据写入到 fileChannel
        fileChannel.write(byteBuffer);
        fileOutputStream.close();
    }
    
}

3.2 本地文件读数据

案例要求

1)、使用 ByteBuffer(缓冲)和 Channel(通道),将 file01.txt 中的数据读入到程序,并显示在控制台
2)、假定文件已经存在
3)、代码演示

public class NIOFileChannel02 {

    public static void main(String[] args) throws IOException {

        // 创建文件的输入流
        File file = new File("d:\\file01.txt");
        FileInputStream fileInputStream = new FileInputStream(file);

        // 通过 fileInputStream 获取对应的 FileChannel->FileChannelImpl
        FileChannel fileChannel = fileInputStream.getChannel();

        // 创建缓冲区
        ByteBuffer byteBuffer = ByteBuffer.allocate((int)file.length());

        // 将通道的数据读入到 byteBuffer 中
        fileChannel.read(byteBuffer);

        // 将 byteBuffer 中的字节数据转成字符串
        System.out.println(new String(byteBuffer.array()));

        fileInputStream.close();
    }

}

3.3 使用一个 Buffer 完成文件读取

案例要求

1)、使用 FileChannel(通道)和 方法 read、write,完成文件的拷贝
2)、拷贝一个文本文件 1.txt,放在项目下即可 2.txt
3)、全程只使用一个 Buffer

使用一个 Buffer 完成文件读取

4)、代码演示

public class NIOFileChannel03 {

    public static void main(String[] args) throws IOException {

        FileInputStream fileInputStream = new FileInputStream("1.txt");
        FileChannel fileChannel01 = fileInputStream.getChannel();

        FileOutputStream fileOutputStream = new FileOutputStream("2.txt");
        FileChannel fileChannel02 = fileOutputStream.getChannel();

        ByteBuffer byteBuffer = ByteBuffer.allocate(512);

        while (true){ // 循环读取

            // 这里有一个重要的操作,一定不要忘了
            /*public final Buffer clear() {
                position = 0;
                limit = capacity;
                mark = -1;
                return this;
            }*/
            byteBuffer.clear(); // 清空 buffer

            int read = fileChannel01.read(byteBuffer);
            System.out.println("read =" + read);
            System.out.println(new String(byteBuffer.array()));

            if(read == -1){ // 表示读取完毕
                break;
            }

            // 将 buffer 中的数据写入到 fileChannel02 --> 2.txt
            byteBuffer.flip();
            fileChannel02.write(byteBuffer);
        }

        // 关闭流
        fileInputStream.close();
        fileOutputStream.close();
    }

}

3.4 使用transferFrom拷贝文件

案例要求

1)、使用 FileChannel(通道)和 方法 transferFrom,完成文件的拷贝
2)、拷贝一张图片
3)、代码演示

public class NIOFileChannel04 {

    public static void main(String[] args) throws IOException {

        // 创建相关流
        FileInputStream fileInputStream = new FileInputStream("d:\\a.jpg");
        FileOutputStream fileOutputStream = new FileOutputStream("d:\\a2.jpg");

        // 获取各个流对应的filechannel
        FileChannel sourceCh = fileInputStream.getChannel();
        FileChannel destCh = fileOutputStream.getChannel();

        // 使用 transferFrom 完成拷贝
        destCh.transferFrom(sourceCh,0,sourceCh.size());

        // 关闭通道和流
        sourceCh.close();
        destCh.close();
        fileInputStream.close();
        fileOutputStream.close();
    }

}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
好的,以下是使用Netty-Mqtt-Client实现Mqtt客户端发布消息和订阅消息的核心Java代码,带注释说明: ```java import io.netty.buffer.Unpooled; import io.netty.handler.codec.mqtt.*; import io.netty.handler.codec.mqtt.MqttQoS; import io.netty.handler.codec.mqtt.MqttPublishMessage; import io.netty.handler.codec.mqtt.MqttSubscribeMessage; import io.netty.handler.codec.mqtt.MqttUnsubscribeMessage; import io.netty.handler.codec.mqtt.MqttMessageBuilders.*; // 创建一个Mqtt客户端类 public class MqttClient { private final String clientId; // 客户端ID private final String serverHost; // 服务器主机名 private final int serverPort; // 服务器端口号 private final String username; // 用户名 private final String password; // 密码 private final int keepAlive; // 心跳间隔时间 private EventLoopGroup group; // Netty线程组 private MqttClientInitializer initializer; // Netty客户端初始化器 private Channel channel; // Netty通道 // 构造方法,初始化Mqtt客户端配置 public MqttClient(String clientId, String serverHost, int serverPort, String username, String password, int keepAlive) { this.clientId = clientId; this.serverHost = serverHost; this.serverPort = serverPort; this.username = username; this.password = password; this.keepAlive = keepAlive; } // 连接服务器 public void connect() { group = new NioEventLoopGroup(); // 创建Netty线程组 initializer = new MqttClientInitializer(clientId, username, password, keepAlive); // 创建Netty客户端初始化器 Bootstrap bootstrap = new Bootstrap(); // 创建Netty客户端启动器 bootstrap.group(group) .channel(NioSocketChannel.class) .remoteAddress(serverHost, serverPort) .handler(initializer); try { ChannelFuture future = bootstrap.connect().sync(); // 连接服务器,同步等待连接完成 if (future.isSuccess()) { // 连接成功 channel = future.channel(); // 获取Netty通道 } } catch (InterruptedException e) { e.printStackTrace(); } } // 断开连接 public void disconnect() { if (channel != null && channel.isActive()) { channel.close(); // 关闭Netty通道 } if (group != null) { group.shutdownGracefully(); // 关闭Netty线程组 } } // 发布消息 public void publish(String topic, String message, MqttQoS qos) { MqttFixedHeader header = new MqttFixedHeader(MqttMessageType.PUBLISH, false, qos, false, 0); MqttPublishVariableHeader variableHeader = new MqttPublishVariableHeader(topic, 0); ByteBuf payload = Unpooled.buffer(); payload.writeBytes(message.getBytes()); MqttPublishMessage publishMessage = new MqttPublishMessage(header, variableHeader, payload); channel.writeAndFlush(publishMessage); // 发送Mqtt PUBLISH消息 } // 订阅主题 public void subscribe(String topic, MqttQoS qos) { MqttFixedHeader header = new MqttFixedHeader(MqttMessageType.SUBSCRIBE, false, MqttQoS.AT_LEAST_ONCE, false, 0); MqttMessageIdVariableHeader variableHeader = MqttMessageIdVariableHeader.from(1); MqttTopicSubscription topicSubscription = new MqttTopicSubscription(topic, qos); MqttSubscribePayload payload = new MqttSubscribePayload(Arrays.asList(topicSubscription)); MqttSubscribeMessage subscribeMessage = new MqttSubscribeMessage(header, variableHeader, payload); channel.writeAndFlush(subscribeMessage); // 发送Mqtt SUBSCRIBE消息 } // 取消订阅主题 public void unsubscribe(String topic) { MqttFixedHeader header = new MqttFixedHeader(MqttMessageType.UNSUBSCRIBE, false, MqttQoS.AT_LEAST_ONCE, false, 0); MqttMessageIdVariableHeader variableHeader = MqttMessageIdVariableHeader.from(1); MqttUnsubscribePayload payload = new MqttUnsubscribePayload(Arrays.asList(topic)); MqttUnsubscribeMessage unsubscribeMessage = new MqttUnsubscribeMessage(header, variableHeader, payload); channel.writeAndFlush(unsubscribeMessage); // 发送Mqtt UNSUBSCRIBE消息 } } ``` 以上代码中,我们创建了一个MqttClient类,该类通过Netty-Mqtt-Client实现了Mqtt客户端发布消息和订阅消息的功能。具体实现细节如下: - connect()方法:连接Mqtt服务器,其中我们通过Netty创建了一个NioEventLoopGroup线程组、一个MqttClientInitializer客户端初始化器和一个Bootstrap客户端启动器,并将它们配置好后发起连接请求; - disconnect()方法:断开Mqtt服务器连接,关闭Netty通道和线程组; - publish()方法:发布Mqtt消息,其中我们使用了MqttFixedHeader、MqttPublishVariableHeader、ByteBuf和MqttPublishMessage等Netty-Mqtt-Client提供的类来构建Mqtt PUBLISH消息,并通过Netty通道将其发送给服务器; - subscribe()方法:订阅Mqtt主题,其中我们使用了MqttFixedHeader、MqttMessageIdVariableHeader、MqttTopicSubscription、MqttSubscribePayload和MqttSubscribeMessage等Netty-Mqtt-Client提供的类来构建Mqtt SUBSCRIBE消息,并通过Netty通道将其发送给服务器; - unsubscribe()方法:取消订阅Mqtt主题,其中我们使用了MqttFixedHeader、MqttMessageIdVariableHeader、MqttUnsubscribePayload和MqttUnsubscribeMessage等Netty-Mqtt-Client提供的类来构建Mqtt UNSUBSCRIBE消息,并通过Netty通道将其发送给服务器。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yangxshn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值