用java nio模擬下載服務

/**

 * Fly_m at 2009-5-20

 */

package com.m_ylf.study.nio;

 

import java.io.File;

import java.io.FileInputStream;

import java.net.InetSocketAddress;

import java.nio.ByteBuffer;

import java.nio.channels.*;

import java.util.HashMap;

import java.util.Iterator;

import java.util.Map;

import java.util.concurrent.Callable;

 

/** @author Fly_m */

//模擬下載服務

public class DownloadServer<T> implements Callable<T>{

private Selector selector;//創建全局selector

private Map<SocketChannel, Handle> map = new HashMap<SocketChannel, Handle>();//socketChannel和handle之間的映射

 

//創建一個服務器serverSocketChannel,並與selector進行註冊

public DownloadServer() throws Exception {

selector = Selector.open();

ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();

serverSocketChannel.configureBlocking(false);

serverSocketChannel.socket().bind(new InetSocketAddress(1234));

serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

}

 

//對selector.select進行迭代,並依次進行處理

public T call() throws Exception {

System.out.println("startTo listen in 1234....");

for(; ;) {

selector.select();

Iterator<SelectionKey> keyIterator = selector.selectedKeys().iterator();

while(keyIterator.hasNext()) {

SelectionKey key = keyIterator.next();

if(key.isValid())

handle(key);

keyIterator.remove();

}

}

}

 

//處理每個key,對於acceptable的key,由主類進行處理,而其他事件,則由內部類進行處理

private void handle(final SelectionKey key) throws Exception {

if(key.isAcceptable()) {

ServerSocketChannel channel = (ServerSocketChannel) key.channel();

SocketChannel socketChannel = channel.accept();

socketChannel.configureBlocking(false);

socketChannel.register(selector, SelectionKey.OP_READ);//註冊讀事件

map.put(socketChannel, new Handle());//把socket和handle進行綁定

}

//用map中的handle處理read和write事件,以模擬多個文件同時進行下載

if(key.isReadable() || key.isWritable()) {

SocketChannel socketChannel = (SocketChannel) key.channel();

final Handle handle = map.get(socketChannel);

if(handle != null)

handle.handle(key);

}

}

 

//內部類,模擬一個內部類處理一個文件下載服務,多個類可以處理多個文件下載服務

private class Handle{

private StringBuilder message;

private boolean writeOK = true;

private ByteBuffer byteBuffer = ByteBuffer.allocate(1024);

private FileChannel fileChannel;

private String fileName;

 

private void handle(SelectionKey key) throws Exception {

if(key.isReadable()) {

SocketChannel socketChannel = (SocketChannel) key.channel();

if(writeOK)

message = new StringBuilder();

while(true) {

byteBuffer.clear();

int r = socketChannel.read(byteBuffer);

if(r == 0)

break;

if(r == -1) {

socketChannel.close();

key.cancel();

return;

}

message.append(new String(byteBuffer.array(), 0, r));

}

//將接收到的信息轉化成文件名,以映射到服務器上的指定文件

if(writeOK && invokeMessage(message)) {

socketChannel.register(selector, SelectionKey.OP_WRITE);

writeOK = false;

}

}

//向客戶端寫數據

if(key.isWritable()) {

if(!key.isValid())

return;

SocketChannel socketChannel = (SocketChannel) key.channel();

if(fileChannel == null)

fileChannel = new FileInputStream(fileName).getChannel();

byteBuffer.clear();

int w = fileChannel.read(byteBuffer);

//如果文件已寫完,則關掉key和socket

if(w <= 0) {

fileName = null;

fileChannel.close();

fileChannel = null;

writeOK = true;

socketChannel.close();

key.channel();

return;

}

byteBuffer.flip();

socketChannel.write(byteBuffer);

}

}

 

//將信息轉化成文件名

private boolean invokeMessage(StringBuilder message) {

String m = message.toString();

try {

File f = new File(m);

if(!f.exists())

return false;

fileName = m;

return true;

} catch(Exception e) {

return false;

}

}

 

}

 

public static void main(String[] args) throws Exception {

/*

ExecutorService executorService = Executors.newSingleThreadExecutor();

executorService.submit(new DownloadServer<Object>());

executorService.shutdown();

*/

new DownloadServer().call();

}

}

/**
 * Fly_m at 2009-5-20
 */
package com.m_ylf.study.nio;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.net.InetSocketAddress;
/** @author Fly_m */
//模擬下載客戶端
public class DownloadClient<T> implements Callable<T>{
private FileChannel fileChannel;
private static Selector selector;
private ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
private String serverFileName;//服務器上的文件
private String localFileName;//下載到客戶端的文件名
public DownloadClient(String serverFileName, String localFileName) {
this.serverFileName = serverFileName;
this.localFileName = localFileName;
}
public T call() throws Exception {
//開啓selector,並建立socket到指定端口的連接
if(selector == null)
selector = Selector.open();
SocketChannel channel = SocketChannel.open();
channel.configureBlocking(false);
channel.connect(new InetSocketAddress("localhost", 1234));
channel.register(selector, SelectionKey.OP_CONNECT);
//進行信息讀取
for(; ;) {
selector.select();
Iterator<SelectionKey> keyIterator = selector.selectedKeys().iterator();
while(keyIterator.hasNext()) {
SelectionKey key = keyIterator.next();
keyIterator.remove();
//連接事件
if(key.isConnectable()) {
SocketChannel socketChannel = (SocketChannel) key.channel();
if(socketChannel.isConnectionPending())
socketChannel.finishConnect();
socketChannel.write(ByteBuffer.wrap(serverFileName.getBytes()));//向服務器發信息,信息中即服務器上的文件名
socketChannel.register(selector, SelectionKey.OP_READ);
}
//讀事件
if(key.isReadable()) {
SocketChannel socketChannel = (SocketChannel) key.channel();
byteBuffer.clear();
if(!socketChannel.isConnected())
return null;
//向本機下載文件創建文件channel
if(fileChannel == null)
fileChannel = new RandomAccessFile(localFileName, "rw").getChannel();
int r = socketChannel.read(byteBuffer);
//如果文件下載完畢,則關掉channel,同時關掉socketChannel
if(r <= 0) {
if(fileChannel != null)
fileChannel.close();
channel.close();
key.cancel();
return null;
}
byteBuffer.flip();
//寫到下載文件中
fileChannel.write(byteBuffer);
}
}
}
}
//客戶端用10個線程向服務器端下載文件,並保存爲不同的文件
public static void main(String[] args) throws Exception {
ExecutorService executorService = Executors.newSingleThreadExecutor();
for(int i = 0; i < 10; i++) {
executorService.submit(new DownloadClient<Object>("d:/log4j.log", "d:/down" + i + ".log"));
}
executorService.shutdown();
}
}
發佈了171 篇原創文章 · 獲贊 4 · 訪問量 15萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章