Java NIO流--二

来源:互联网 发布:三维人像建模软件 编辑:程序博客网 时间:2024/06/05 16:45

       上篇说到NIO未完待续,其实我已经不知道该往下写些什么了,这就是拖得太久的毛病啊!

      书接上回,上回说到NIO最主要的特性就是缓冲区和通道以及选择器了。之前的《BIO,NIO,AIO初体验》里头已经提到了这些东西,而《Java NIO流》中已经算是介绍了缓冲区了,主要就是四个属性,capacity(容量),limt(上线),position(当前位置),以及mark(标记一下)。一般来说都是postion<=limit<=capacity,至于mark也是<=capacity的。我大概的理解就是我有一个箱子(缓冲区),大小是有8个格子(Capacity),但是由于有2个格子坏了,最大为6(limit),而且我已经用了2个格子了,于是position为3。理解有误的话,我以后会更新的。

然后剩下的就是通道和选择器了。

        首先通道Channel,是用于在字节缓冲区和位于通道另一侧的实体(通常是一个文件或套接字)之间有效的传输数据的。

        大概就是这样

        字节缓冲区---data----通道---data---文件,他们在传输数据。

举个栗子就是:(-->表示对应)

载体-->缓冲区;

支票-->数据;

导管-->通道;

出纳员-->I/O服务;

        在一个银行里,给一个出纳员支票,通过导管给过去。(我不知道银行是不是这么干的,反正举这个例子的人是这么说的)。

        首先将支票放到载体上,然后将载体放到导管中,导管将载体送到出纳员手中,出纳员从载体中拿出支票,然后处理。

        也就是将数据放到缓冲区中,然后将缓冲区放到通道中,通道将缓冲区送到I/O操作手中,I/O操作取出数据,进行业务操作。

        概念大概理解了,但是不影响我还是不会用。

通道类一般有read(),write(),close(),isOpen()和postion()等方法,若通道实现read()或write()中的一个,则是单向通道,2个都实现,就是双向通道。

通道常见的实现类有FileChannel,SocketChannel和ServerSocketChannel。


        其中FileChannel是阻塞的;Socket和Pipe可以是非阻塞的,他们是面向流的通道,永远不会让调用的线程休眠,请求的结果要么立即完成,要么返回一个结果表明未进行任何操作。

对于Socket通道,概念太多,懒得写了。

由于Socket通道可以运行非阻塞模式并且是可选的,我们可以用一个或几个线程就可以管理成百上千个活动socket连接了,而且基本不影响性能。

        Socket通道类,在被实例化时,会有一个socket对象与之对应,而调用socket通道类的socket()方法就能获取对等的socket对象。而socket对象调用getChannel()也能获取到对应的socket通道类。如SocketChannel-->Socket,ServerSocketChannel-->ServerSocket,以及DatagramChannel-->DatagramSocket。但是他们的关系是单向的,socket通道类都有对应的socket对象,但是socket对象并不一定有对应的socket通道类,所以直接实例化socket对象,是没有socket通道类与之对应的。

        刚刚说了socket通道是非阻塞的,通过设置configureBlocking()为false就可以设置为非阻塞模式,同理设置为true就是阻塞模式。而且还有isBlocking()来判断socket通道处于哪个模式。

        而非阻塞模式,服务端会经常使用,因为这样服务端管理多个socket就可以变得比较容易。当然客户端也可以使用。

        下面单个介绍一下ServerSocketChannel和SocketChannel。

        ServerSocketChannel,基于通道的socket监听器。它和java.net.ServerSocket做的事基本相同,只是因为添加了通道,所以可以在非阻塞模式下运行。

        使用static的open()工厂方法create一个新的ServerSocketChannel对象,会返回和一个未绑定的ServerSocket关联的通道。该对等ServerSocket可以通过ServerSocketChannel对象的socket()方法获取。

        通道不能被封装在随意的socket对象外面,由于服务器的socket通道对象没有bind()方法,因此需要靠对等的socket来bind到一个端口上开始监听连接。

        ServerSocketChannel和ServerSocket都有accept方法,只要是有对等socket的通道,这两个类调用哪个都行,

但是他们的效果不是一样的,若用serverSocket的accept方法,则都是总是阻塞,并返回一个socket对象。而用

serverSocketChannel则会返回一个socketChannel对象,并且该对象可以在非阻塞模式下运行。

        SocketChannel,和socket类封装点对点的、有序的网络连接,类似于TCP/IP网络连接。SocketChannel扮演客户端,

发起到同一个监听服务器的连接,直到连接成功,它才能收到数据并且只会从连接到的地址接收消息。

        也就是说对于SocketChannel一次只能连接到一个服务器上,而ServerSocketChannel则可以接收多个客户端的请求。

和ServerSocketChannel类似,用static的open()方法创建新的SocketChannel,调用通道的socket可以获得对等的socket对

象,而在对等的Socket上调用getChannel()可以获取SocketChannel对象。

        新的socketChannel打开但没有连接,需要使用通道或对等socket的connect()连接到一个服务端上,一旦连接上,

就会一直保持连接直到关闭。使用isConnected来判断socketChannel当前是否连接。当然和serversocketchannel一样,

用对等对象的connect()是阻塞的,而用socketChannel的则可以是非阻塞的,需要指定,若不指定,默认也是阻塞的;若

指定为非阻塞模式,则socketChannel提供并发连接,它发起的请求会立即返回结果,若为true,则表示连接上了,若

返回false,说明暂时还连不上,但是会并发的继续发送连接

        面向流的socket建立连接很费时间,因为两个待连接系统之间必须进行包对话以建立维护流socket所需的状态信

息。跨越开放的互联网连接到远程系统会特别的耗时。若某个socketChannel上当前正有一个并发连接,

isConnectPending()方法就会返回true值。

        finishConnect()可以用来完成连接过程,非阻塞的socketchannel调用finishConnect()会出现

1.connect()方法尚未调用,产生NoConnectionPendingException异常;

2.连接建立过程正在进行中,尚未完成,什么也不会发生,立即返回false;

3.在非阻塞的模式下调用connect()方法之后,socketChannel又切回了阻塞模式,那么如果有必要的话,调用线程会

阻塞直到连接建立完成,finishConnect就可以返回true了。

4.在初次调用connect或最后一次调用finishConnect()之后,建立连接的过程已经完成。那么socketChannel对象的

内部状态被更新得已连接状态,返回true,然后socketChannel就可以传输数据了。

5.连接已经建立,什么都不发生,返回true。

        Channel介绍完毕,下面是选择器了。



原创粉丝点击