用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();
}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值