防止ftp写入数据时被其他程序读取_程序员:Java NIO 三大部件你都知道吗?

Netty是什么?

  • Netty是由JBOSS提供的一个java开源框架,现为 Github上的独立项目。Netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。
  • 也就是说,Netty 是一个基于NIO的客户、服务器端编程框架,使用Netty 可以确保你快速和简单的开发出一个网络应用,例如实现了某种协议的客户、服务端应用。Netty相当于简化和流线化了网络应用的编程开发过程,例如:基于TCP和UDP的socket服务开发。
  • “快速”和“简单”并不用产生维护性或性能上的问题。Netty 是一个吸收了多种协议(包括FTP、SMTP、HTTP等各种二进制文本协议)的实现经验,并经过相当精心设计的项目。最终,Netty 成功的找到了一种方式,在保证易于开发的同时还保证了其应用的性能,稳定性和伸缩性。

java NIO包括三大部件

从哪哪哪读(写)数据,数据读(写)到哪里,看看这里或者那里能不能读(写)。

  1. Channel (通道)
  2. Buffer(缓冲器)
  3. Selector(选择器)

在Java NIO里的所有IO操作都从Channel开始。数据可以从 Channel 读取到 Buffer 中,也可以从 Buffer 写到 Channel 中。如下图所示

4d71823210956b6d4837bbc985b84bd3.png

Channel 必须配合 Buffer 使用,总是先读取到一个 Buffer 中,又或者是向一个 Buffer 写入。也就是说,我们无法绕过 Buffer ,直接向 Channel 写入数据

Channel的实现

Channel在Java中作为一个接口,java.nio.channels.Channel 定义IO操作的联通与关闭

package java.nio.channels;

import java.io.IOException;

import java.io.Closeable;

public interface Channel extends Closeable {

public boolean isOpen();

//判断通道是否开启

public void close() throws IOException;

//关闭通道

}

Channel实现类众多,最重要的四个Channel实现类如下:

SocketChannel :一个客户端用来发起 TCP 的 Channel 。

ServerSocketChannel :一个服务端用来监听新进来的连接的 TCP 的 Channel 。对于每一个新进来的连接,都会创建一个对应的 SocketChannel 。

DatagramChannel :通过 UDP 读写数据。

FileChannel :从文件中,读写数据。

关于Buffer

Buffer在java.nio包中实现,被定义成抽象类

Buffer有四个重要属性 capacity、limit、 position 、 mark

public abstract class Buffer {

// Invariants: mark <= position <= limit <= capacity 不变量

private int mark = -1;

private int position = 0;

private int limit;

private int capacity;

// Used only by direct buffers

// NOTE: hoisted here for speed in JNI GetDirectBufferAddress

long address;

Buffer(int mark, int pos, int lim, int cap) { // package-private

if (cap < 0)

throw new IllegalArgumentException("Negative capacity: " + cap);

this.capacity = cap;

limit(lim);

position(pos);

if (mark >= 0) {

if (mark > pos)

throw new IllegalArgumentException("mark > position: ("

+ mark + " > " + pos + ")");

this.mark = mark;

}

}

//省略具体方法的代码

}

一个 Buffer ,本质上是内存中的一块,是不是一下子就想通四个属性存在必要啦

capacity 在Buffer创建时被赋值,永远不能被更改

Buffer分为读、写模式两种。两种模式下

position 和 limit 属性分别代表不同的含义。

public final Buffer clear() {

position = 0;

limit = capacity;

mark = -1;

return this;

}

public final Buffer flip() {

limit = position;

position = 0;

mark = -1;

return this;

}

position属性 意为位置,初值为0

(position像是真的数据存入所占的内存所占的相对位置)

在写模式中,往Buffer中写入一个值,position 就自动加 1 ,代表下一次的写入位置。

在读模式中,从 Buffer 中读取一个值,position 就自动加 1 ,代表下一次的读取位置。( 和写模式类似 )

limit属性 意为上限。

写模式下,代表最大能写入的数据上限位置,这个时候 limit 等于 capacity 。

读模式:在Buffer完成数据写入后,通过调用 #flip() 方法,切换到读模式。此时,limit 等于 Buffer 中实际的数据大小(position)。因为 Buffer 不一定被写满,所以不能使用 capacity 作为实际的数据大小。

mark 属性,标记,通过 #mark() 方法,记录当前 position ;通过 reset() 方法,恢复 position 为标记。

写模式下,标记上一次写位置。

读模式下,标记上一次读位置。

四个属性的大小关系遵循:

mark <= position <= limit <= capacity

关于Selector

Selector , 一般称为选择器。它是 Java NIO 核心组件中的一个,用于轮询一个或多个 NIO Channel 的状态是否处于可读、可写。如此,一个线程就可以管理多个 Channel ,也就说可以管理多个网络连接。也因此,Selector 也被称为多路复用器。

将Channel注册到Selector中,Selector就知道他需要管理哪些Channel。

Selector 会不断地轮询注册在其上的 Channel 。如果某个 Channel 上面发生了读或者写事件,这个 Channel 就处于就绪状态,会被 Selector 轮询出来,然后通过 SelectionKey 可以获取就绪 Channel 的集合,进行后续的 I/O 操作。

082f7662436bb745b0880409d55269bd.png

① 优点

使用一个线程能够处理多个 Channel 的优点是,只需要更少的线程来处理 Channel 。事实上,可以使用一个线程处理所有的 Channel 。对于操作系统来说,线程之间上下文切换的开销很大,而且每个线程都要占用系统的一些资源( 例如 CPU、内存 )。因此,使用的线程越少越好。

② 缺点

因为在一个线程中使用了多个 Channel ,因此会造成每个 Channel 处理效率的降低。

在Netty中,对Buffer的操作少了#filp()的操作, 他的基本属性设计为:通过readerIndex和writerIndex两个属性操作。

0 <= readerIndex <= writerIndex <= capacity

通过n个线程处理Channel,解决Channel处理效率低的问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值