java NIO之通道学习笔记

通道:channel用于字节缓冲区和位于通道另一侧的实体(通常是文件或者套接字)之间有效的传输数据。

 

两种类型的通道:1FileChannel类(他总是一种阻塞式的)和

2、socket通道类:SocketChannel,ServerSocketChannel,DatagramSocket

Socket通道有可以直接创建socket通道的工厂方法,FileChannel对象只能在一个打开的RandomAccessFileFileInputStream,或者FileOutputStream对象上调用getChannel()方法获取,不能直接创建FileChannel对象。

通道使用,通道有单向和双向的,实现ReadableByteChannelWriteableByteChannel.其中之一的是单向通道,两者都实现了是双向通道即可读又可写。实现读的通道只能用read()方法,用write方法报错哪怕类中有这个方法。实现写的同理。也就是说:通道会连接一个特定I/O服务且通道实例的性能会受到他所链接的I/O服务特征限制。

文件通道

FileChannel是线程安全的,多个线程可以在同一个实例上并发调用方法不会引起任何问题,但是影响通道位置和文件大小的操作是单线程的。

访问文件:readwrite,文件位置position,自动随着读写更新位置。读到文件末尾是返回-1,写入文件末尾,也即是写的时候超出文件大小(通过size()方法获取)是,该文件会扩展以容纳新的字节(这一点和缓冲区不同)。

Socket通道

全部socket通道类(java.net....以上三种)在被实例化时都会创建一个对等socket对象。对等socket对象可以通过调用socket()方法从一个通道中获取,这三个类都有一个getchannel()方法。虽然每个socket通道都有关联一个socket对象,但并非所有socket对象都关联一个socket通道。传统方式(直接实例化)创建的socket对象就不会关联Socket通道,调用他的getchannel()方法返回为null

通道的阻塞模式可以设置通过configureBlockingboolean)方法设置,传入true是阻塞模式,false是非阻塞模式,isBlocking()检查是否阻塞(服务端一般用非阻塞模式)

ServerSocketChannel

是一个基于通道的socket监听器,用静态的open工厂方法创建一个serverSocketChannel对象,将会返回同一个未绑定的java.net.ServerSocket关联的通道,该serverSocket可以通过在返回的serverSocketChannel中调用socket()方法,这些serverSocket对象依赖于通道的实现。通道一般不能被随意的socket的对象外面,但是serversocketchannel没有bind()方法,因此有必要取出对等的socket来绑定到一个端口一开始监听链接,也可以通过serversocketAPI来根据需要设置socket的其他选项。

 

java.net.serversocket一样,serverSocketchannel也有accept()方法,一旦创建了serversocketchannel并用对等的socket绑定了它,然后就可以调用其中的socket方法。

serversocket上调用accept方法,和在其他serversocket上一样:总是阻塞并返回一个java.net.socket对象,在Serversocketchannel上调用accept方法,返回socketchannel对象,返回的对象是在非阻塞模式下运行,假如系统有一个安全管理器,则两种形式的方法执行相同的安全检查。

如果以非阻塞模式下被调用,当没有传入链接在等待时,serversocketchannel.accept()方法会立即返回一个null,这链接不阻塞实现可伸缩性和降低复杂度。可以使用一个选择器实例来注册serversocketchannel对象以实现新连接到达是自动通知。

 

Socketchannel

Socketchannel封装了点对点,有序网络链接,Socketchannel扮演客户端发送同一个监听服务器的链接,知道链接成功,他只能从链接成功的地址接受数据。静态的open方法会创建一个socketchannel对象,在该对象上调用socket返回一个socket,在该socket上调用getchannel则返回该socketchannel对象。

新创建出的socketchannel虽打开但没有链接。调用读写方法抛出NotYetConnectException异常.直接调用connect方法(阻塞直到链接成功,(并没有制定超时的设置)通道默认是阻塞的)或者关联的socket上调用connect方法链接(也就是传统的模式调用connect,阻塞或者超时,直到连接成功)两个链接过程一致。

connect在非阻塞模式下调用时,socketchannel提供并发链接,发起对请求地址的链接,并且立即返回值。True为成功,false为失败,如果链接不能成功则并发地继续链接建立过程。

在一个非阻塞模式下调用finishChannel()会出现下列情形之一:

1、connect()方法尚未被调用,那么将产生NoConnectionPendingException异常。

2、连接过程正在进行尚未完成,那么什么都没有发生,finishchannel()方法直接返回false

3、在非阻塞模式下调用connect()之后,socketchannel又被切换了阻塞模式,如果有必要的话调用线程会阻塞直到连接简历完成finishchannel()方法接着返回true

4、在初次调用connect()或者最后一次调用finnishConnect()之后,连接建立过程已经完成,那么socketchannel对象的内部状态将被更新到已连接状态,finnishchannel()调用会返回true值,然后socketChannel对象就可以被用来传输数据。

5、连接已经建立完成,那么什么都不会发生,finiashchannel()直接返回true

Socket通道案例:

服务端:package it.com.Jerome;

import java.net.InetSocketAddress;

import java.nio.ByteBuffer;

import java.nio.IntBuffer;

import java.nio.channels.ServerSocketChannel;

import java.nio.channels.SocketChannel;

 

public class NIOSocketChannelServer {

 

private ByteBuffer buff=ByteBuffer.allocate(1024);

private IntBuffer intBuff = buff.asIntBuffer();

private SocketChannel clientChannel=null;

private ServerSocketChannel serverChannel =null;

//打开服务通道;

public void openChannel() throws Exception{

serverChannel = ServerSocketChannel.open();

serverChannel.socket().bind(new InetSocketAddress(8989));

System.out.println("服务器通道已经打开!");

}

//等待客户端请求链接;

public void waitReqConn() throws Exception{

while(true){

clientChannel=serverChannel.accept();

if(clientChannel!=null){

System.out.println("新的链接已加入!");

}

processReq();//处理请求

clientChannel.close();

}

}

public void processReq() throws Exception {

System.out.println("开始读取和处理客户端数据!");

buff.clear();//当前位置为0,上限值为容量的值。

clientChannel.read(buff);

int result = intBuff.get(0)+intBuff.get(1);

System.out.println(result);

buff.flip();

buff.clear();

intBuff.put(0, result);

clientChannel.write(buff);

System.out.println("客户端数据读取和处理完成!");

}  

public void start(){

try{

openChannel();

waitReqConn();

clientChannel.close();

System.out.println("服务端处理完成");

}catch(Exception e){

e.printStackTrace();

}

}

public static void main(String[] args) {

   new NIOSocketChannelServer().start();

}

}

客户端:

package it.com.Jerome;

import java.net.InetSocketAddress;

import java.nio.ByteBuffer;

import java.nio.IntBuffer;

import java.nio.channels.SocketChannel;

 

public class NIOSocketChannelClient {

 

private SocketChannel channel=null;

private ByteBuffer buff=ByteBuffer.allocate(8);

private IntBuffer intBuff = buff.asIntBuffer();

public SocketChannel connect() throws Exception{

return SocketChannel.open(new InetSocketAddress("127.0.0.1",8989));

}

public void sendRequest(int a,int b) throws Exception{

buff.clear();

intBuff.put(0, a);

intBuff.put(1, b);

channel.write(buff);

System.out.println("发送请求!");

}

 public int  receiveRequest() throws Exception{

 buff.clear();

 channel.read(buff);

 return intBuff.get(0);

 }

 public int getSum(int a,int b){

 int result=0;

 try{

 channel = connect();

 sendRequest(a,b);

 result=receiveRequest();

 }catch(Exception e){

 e.printStackTrace();

 }

 return result;

 }

public static void main(String[] args) {

 int result = new  NIOSocketChannelClient().getSum(45, 34);

 System.out.println("处理结果完成!"+result);

}

 

}

输出是79

 

文件通道案例:package it.com.Jerome;

 

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.nio.ByteBuffer;

import java.nio.channels.FileChannel;

 

public class FileSocketChannel {

 

public static void main(String[] args) {

fileChannelDemo();

}

private static void fileChannelDemo() {

try{

ByteBuffer buff=ByteBuffer.allocate(1024);

FileChannel inFc=new FileInputStream(

"C:/helloworld1.txt").getChannel();

FileChannel outFc=new FileOutputStream(

"C:/helloworld2.txt",true).getChannel();

buff.clear();

int len=inFc.read(buff);

System.out.println(new String(buff.array(),0,len));

ByteBuffer buff2=ByteBuffer.wrap("jack".getBytes());

outFc.write(buff2);

inFc.close();

outFc.close();

}catch(Exception e){

e.printStackTrace();

}

}

}

你可能感兴趣的:(java NIO之通道学习笔记)