使用NIO在网络上传输文件

NIO,官方说法为New IO,我们也可以理解为Non Blocking IONIO需要JDK1.7以上支持。

package channel;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Date;
import java.util.Iterator;
import java.util.Set;
import org.junit.Test;

public class TestNIO {
	
	@Test
	public void client(){
		try {
			SocketChannel sc = SocketChannel.
					open(new InetSocketAddress("127.0.0.1", 8080));
			//设置为非阻塞模式
			sc.configureBlocking(false);
			FileInputStream fis = new FileInputStream(new File("1.jpg"));
			FileChannel inChannel = fis.getChannel();			
			ByteBuffer dst = ByteBuffer.allocate(1024);
			while(inChannel.read(dst) != -1){
				dst.flip();
				sc.write(dst);
				dst.clear();
			}
			inChannel.close();
			fis.close();
			sc.close();
			
		} catch (IOException e) {
			e.printStackTrace();
		}		
	}
	
	@Test
	public void test2(){
		try {
			SocketChannel sc  = SocketChannel.open(new InetSocketAddress("127.0.0.1", 8080));
			sc.configureBlocking(false);
			ByteBuffer src = ByteBuffer.allocate(1024);
			src.put(new Date().toString().getBytes());
			src.flip();
			sc.write(src);
			src.clear();
			sc.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	@Test
	public void server(){
		try {
			ServerSocketChannel ssc = ServerSocketChannel.open();//1
			//设置为非阻塞模式
			ssc.configureBlocking(false);//2
			ssc.bind(new InetSocketAddress(8080));//3
			ByteBuffer buf = ByteBuffer.allocate(1024);			
			FileOutputStream fos = new FileOutputStream(new File("2.jpg"));
			FileChannel outChannel = fos.getChannel();
			SocketChannel sc = null;
			//用open()获取选择器
			Selector selector = Selector.open();//4
			/**注册通道到选择器上,指定监控状态(SelectionKey选择键)
			 * SelectionKey.OP_ACCEPT---接收事件
			 * SelectionKey.OP_CONNECT---连接事件
			 * SelectionKey.OP_READ---读事件
			 * SelectionKey.OP_WRITE---写事件
			 * 若监听事件不止一个时,可以使用"位或"操作符连接;
				int ops = SelectionKey.OP_ACCEPT | SelectionKey.OP_READ;
			 */			
			ssc.register(selector, SelectionKey.OP_ACCEPT);//5
			//轮询获取选择器上准备就序的监听事件
			while(selector.select() > 0){//selector.select()>0说明至少有一个通道准备就序
				Set<SelectionKey> keys = selector.selectedKeys();
				Iterator<SelectionKey> its = keys.iterator();
				while(its.hasNext()){
					SelectionKey selectionKey = its.next();
					//遍历所有准备就序的监听事件SelectionKey,并进行判断
					if(selectionKey.isAcceptable()){//可以启动单独的线程来处理
						//若接收就序就打开服务端连接
						sc = ssc.accept();
						sc.configureBlocking(false);
						sc.register(selector, SelectionKey.OP_READ);						
						//...后序读操作
					}else if(selectionKey.isConnectable()){
						//可以启动单独的线程来处理
						
					}else if(selectionKey.isReadable()){//可以启动单独的线程来处理
						sc = (SocketChannel) selectionKey.channel();
						//sc.configureBlocking(false);
						//sc.register(selector, SelectionKey.OP_READ);
						int len = -1;
						while((len = sc.read(buf))!= -1){
							buf.flip();
							outChannel.write(buf);
							buf.clear();				
						}
					}else if(selectionKey.isWritable()){
						//可以启动单独的线程来处理
					}
				}
				//selectionKey用完后取消掉
				its.remove();
			}
			
			outChannel.close();
			fos.close();
			sc.close();
			ssc.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	}
}


展开阅读全文

没有更多推荐了,返回首页