[关闭]
@huangyichun 2017-08-30T15:43:56.000000Z 字数 5154 阅读 1083

Java I/O的工作机制

I/O


image.png-234.3kB
Java I/O可以分成4组:

读和写文件I/O操作都调用操作系统提供的接口,因为磁盘设备是由操作系统管理的,应用程序要访问物理设备只能 通过系统调用的方式来工作。

直接I/O方式

所谓的直接I/O方式就是应用程序直接访问磁盘数据,而不经过操作系统内核数据缓冲区,这样做的目的是减少一次从内核缓冲区到用户程序缓存的数据复制。

内存映射的方式

指操作系统将内存中的某一块区域与磁盘中文件关联起来,当要访问内存中的一段数据时,转换为访问文件的某一段数据。这种方式的目的同样是减少数据从内核空间缓存到用户空间缓存的数据复制操作,因为两个空间的数据是共享的。

同步访问文件的方式

异步访问文件的方式

Java访问磁盘文件

    数据在磁盘中的唯一最小描述就是文件,因此上层应用程序只能通过文件来操作磁盘上的数据,文件也是操作系统和磁盘驱动器交互的最小单元。
注意: Java中File并不代表一个真实的存在的文件对象,当你指定一个描述符时,它就会返回一个代表这个路径的虚拟对象,这可能是一个真实存在的文件或者是一个包含很多文件目录。
只有当真正要读取这个文件时,例如FileInputStream类都是操作一个文件的接口,注意到在创建FileInputStream对象时会创建一个FileDescriptor对象,其实这个对象就是真正代表一个存在的文件对象的描述。我们可以调用FileDescriptor()方法将操作系统缓存中的数据强制刷新到物理磁盘中。

  1. public FileInputStream(File file) throws FileNotFoundException {
  2. String name = (file != null ? file.getPath() : null);
  3. SecurityManager security = System.getSecurityManager();
  4. if (security != null) {
  5. security.checkRead(name);
  6. }
  7. if (name == null) {
  8. throw new NullPointerException();
  9. }
  10. if (file.isInvalid()) {
  11. throw new FileNotFoundException("Invalid file path");
  12. }
  13. fd = new FileDescriptor();
  14. fd.attach(this);
  15. path = name;
  16. open(name);
  17. }

读取磁盘一段文本步骤:

当传入一个文件路径时,将会根据这个路径创建一个File对象来标识这个文件,然后根据这个File对象创建真正读取文件的操作对象,这时将会真正创建一个关联真实存在的磁盘文件的文件描述符FileDescriptor,通过这个对象可以直接控制这个磁盘文件。由于我们需要读取的是字符格式,所以需要StreamDecoder类将byte解码为char格式。至于如从磁盘驱动器上读取一段数据,操作系统会帮我们完成。

TCP状态转换

此处输入图片的描述

注:主动、被动 与 服务器、客户端没有明确的对应关系。
    这个图N多人都知道,它排除和定位网络或系统故障时大有帮助,但是怎样牢牢地将这张图刻在脑中呢?那么你就一定要对这张图的每一个状态,及转换的过程有深刻 的认识,不能只停留在一知半解之中。下面对这张图的11种状态详细解析一下,以便加强记忆!不过在这之前,先回顾一下TCP建立连接的三次握手过程,以及 关闭连接的四次握手过程。

1、建立连接协议(三次握手)

2、连接终止协议(四次握手)

   由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。这原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个 FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。


ESTABLISHED:这个容易理解了,表示连接已经建立了。

最后有2个问题的回答,我自己分析后的结论(不一定保证100%正确)

建立连接的过程是利用客户服务器模式,假设主机A为客户端,主机B为服务器端。

(1)TCP的三次握手过程:主机A向B发送连接请求;主机B对收到的主机A的报文段进行确认;主机A再次对主机B的确认进行确认。

(2)采用三次握手是为了防止失效的连接请求报文段突然又传送到主机B,因而产生错误。失效的连接请求报文段是指:主机A发出的连接请求没有收到主机B的确认,于是经过一段时间后,主机A又重新向主机B发送连接请求,且建立成功,顺序完成数据传输。考虑这样一种特殊情况,主机A第一次发送的连接请求并没有丢失,而是因为网络节点导致延迟达到主机B,主机B以为是主机A又发起的新连接,于是主机B同意连接,并向主机A发回确认,但是此时主机A根本不会理会,主机B就一直在等待主机A发送数据,导致主机B的资源浪费。

(3)采用两次握手不行,原因就是上面说的实效的连接请求的特殊情况。

同时打开

两个应用程序同时执行主动打开的情况是可能的,虽然发生的可能性较低。每一端都发送一个SYN,并传递给对方,且每一端都使用对端所知的端口作为本地端口。例如:主机a中一应用程序使用7777作为本地端口,并连接到主机b 8888端口做主动打开。主机b中一应用程序使用8888作为本地端口,并连接到主机a 7777端口做主动打开。tcp协议在遇到这种情况时,只会打开一条连接。这个连接的建立过程需要4次数据交换,而一个典型的连接建立只需要3次交换(即3次握手)但多数伯克利版的tcp/ip实现并不支持同时打开。
此处输入图片的描述
SYN_RCVD与SYN_SEND都是转换为ESTABLISHED的中间状态,目标是两端均转换到ESTABLISHED状态。

同时关闭

如果应用程序同时发送FIN,则在发送后会首先进入FIN_WAIT_1状态。在收到对端的FIN后,回复一个ACK,会进入CLOSING状态。在收到对端的ACK后,进入TIME_WAIT状态。这种情况称为同时关闭。同时关闭也需要有4次报文交换,与典型的关闭相同。
此处输入图片的描述

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注