java 简单的文件上传下载服务器模型(NIO 版本)

前面写了一篇文章是基于IO+多线程的文件上传下载服务器模型,这篇文章是它的后续,基于NIO实现文件的上传下载功能。

服务端的代码:

package com.myftpnio.server;

import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.util.Iterator;

import com.myftpnio.handler.NioHandler;
import com.myftpnio.handler.ServerHandler;

public class FtpNioServer {
	public static final int PORT = 5000;
	public static int connum = 0;
	public static final int MAX = 5000;
	public static final String ROOT = "D:/FtpDir/";
	
	public static void main(String argv[]) {
		
		try {
			Selector selector = Selector.open();
			ServerSocketChannel ssc = ServerSocketChannel.open();
			ssc.configureBlocking(false);
			
			ServerSocket ss = ssc.socket();
			ss.bind(new InetSocketAddress(PORT));
			
			SelectionKey skey = ssc.register(selector, SelectionKey.OP_ACCEPT);
			skey.attach(new ServerHandler(ssc, selector));
			
			System.out.println("Start ftp server on " + PORT);
			
			while(!Thread.interrupted()) {
				int n = selector.select();
				if (n == 0) {
					continue;
				}
				Iterator<SelectionKey> it = selector.selectedKeys().iterator();
				while(it.hasNext()) {
					SelectionKey key = it.next();
					it.remove();
					
					NioHandler handler = (NioHandler)key.attachment();
					handler.execute(key);
				}
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public static String ByteBufferToString(ByteBuffer dst) {
		String ret = null;
		if (dst != null) {
			dst.flip();
			byte[] tempb = new byte[dst.limit()];
			dst.get(tempb);
			ret = new String(tempb);
		}
		return ret;
	}
	
	public static ByteBuffer StringToByteBuffer(String s) {
		ByteBuffer other = null;
		if (s != null) {
			other = ByteBuffer.wrap(s.getBytes());
		}
		return other;
	}
	
	public static int AnalyCmd(String cmd) {
		int ret = -1;
		
		if (cmd.toLowerCase().startsWith("upload")) {
			ret = 0;
		} else if (cmd.toLowerCase().startsWith("download")) {
			ret = 1;
		} else if (cmd.toLowerCase().equals("ls")) {
			ret = 2;
		}
		
		return ret;
	}
}

package com.myftpnio.handler;

import java.nio.channels.SelectionKey;

public interface NioHandler {
	void execute(SelectionKey key);
}

package com.myftpnio.handler;

import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;

import com.myftpnio.server.FtpNioServer;

public class ServerHandler implements NioHandler {

	private ServerSocketChannel ssc;
	private Selector selector;
	
	public ServerHandler(ServerSocketChannel ssc, Selector selector) {
		this.ssc = ssc;
		this.selector = selector;
	}
	
	@Override
	public void execute(SelectionKey key) {
		// TODO Auto-generated method stub
		try {
			String cmd = null;
			
			SocketChannel sc = ssc.accept();
			
			//读取客户端的命令,并且给客户端回应消息
			ByteBuffer dst = ByteBuffer.allocate(1024);
			int ret = sc.read(dst);
			if (ret > 0) {
				cmd = FtpNioServer.ByteBufferToString(dst);
				int n = FtpNioServer.AnalyCmd(cmd);
				if (n != -1) {
					String s = "ack";
					ByteBuffer b = ByteBuffer.wrap(s.getBytes());
					sc.write(b);
				} else {
					String s = "cmd is invalid, please check and try again!!!";
					ByteBuffer b = ByteBuffer.wrap(s.getBytes());
					sc.write(b);
					sc.close();
					return;
				}
			} else {
				System.out.println("client no send cmd!!!");
				sc.close();
				return;
			}
			
			//配置客户端Socket为非阻塞
			sc.configureBlocking(false);
			
			//new 一个新的客户端对象
			ClientHandler h = new ClientHandler(sc, selector);
			h.InitClientHandler(cmd);
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}

package com.myftpnio.handler;

import java.io.File;
import java.io.IOException;
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 com.myftpnio.server.FtpNioServer;

public class ClientHandler implements NioHandler {

	private String cmd;
	private Selector selector;
	private SocketChannel sc = null;
	private FileChannel fileChannel = null;
	private ByteBuffer buf = ByteBuffer.allocate(1024);
	
	private long sum = 0;

	public ClientHandler(SocketChannel sc, Selector selector) {
		this.sc = sc;
		this.selector = selector;
				
		FtpNioServer.connum++;
		System.out.println(FtpNioServer.connum + " Client:" + sc.socket().getRemoteSocketAddress().toString() + " open");
	}
	
	public int InitClientHandler(String cmd) {
		// 参数判空
		if (cmd == null) {
			return 1;
		}
		this.cmd = cmd;
		
		try {
			SelectionKey key = null;
			int n = FtpNioServer.AnalyCmd(this.cmd);
			if (n == 0) {
				key = this.sc.register(this.selector, SelectionKey.OP_READ);
				key.attach(this);
			} else {
				key = this.sc.register(this.selector, SelectionKey.OP_WRITE);
				key.attach(this);
			}
		} catch (Exception e) {
			e.printStackTrace();
			return 1;
		}
		return 0;
	}
	
	@Override
	public void execute(SelectionKey key) {		
		if (key.isReadable()) {
			try {
				int n = FtpNioServer.AnalyCmd(this.cmd);
				switch(n) {
					case 0:
						proccessUpLoadCmd(key);
						break;
				}
			} catch (Exception e) {
				e.printStackTrace();
				return;
			}
			return;
		}
		
		if (key.isWritable()) {
			try {
				int n = FtpNioServer.AnalyCmd(this.cmd);
				switch(n) {
					case 1:
						proccessDownLoadCmd(key);
						break;
					case 2:
						proccessLsCmd(key);
						break;
				}
			} catch (Exception e) {
				e.printStackTrace();
				return;
			}
			return;
		}
	}
	
	private void proccessUpLoadCmd(SelectionKey key) {
		
		String s[] = this.cmd.split(":");
		String filepath = FtpNioServer.ROOT + s[1];
		
		try {
			int n = sc.read(buf);
			if (n >= 0) {
				sum += n;
				WriteToFile(filepath, buf);
			} else {
				ReleaseResource(key);
				System.out.println(FtpNioServer.connum + " read sum:" + sum + " Client:" + sc.socket().getRemoteSocketAddress().toString() + " close");
				FtpNioServer.connum--;
				return;
			}
		} catch (IOException e) {
			try {
				ReleaseResource(key);
				FtpNioServer.connum--;
			} catch (IOException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
			System.out.println("IOException " + FtpNioServer.connum + " Client:" + sc.socket().getRemoteSocketAddress().toString() + " close");
			return;
		}
	}
	
	private void proccessDownLoadCmd(SelectionKey key) {
		
		String s[] = this.cmd.split(":");
		String filepath = FtpNioServer.ROOT + s[1];
		
		try {
			int n = ReadFromFile(filepath, buf);
			if (n >= 0) {
				sum += n;
				buf.flip();
				sc.write(buf);
			} else {
				ReleaseResource(key);
				System.out.println(FtpNioServer.connum + " send sum:" + sum + " Client:" + sc.socket().getRemoteSocketAddress().toString() + " close");
				FtpNioServer.connum--;
				return;
			}			
		} catch (Exception e) {
			try {
				ReleaseResource(key);
				FtpNioServer.connum--;
			} catch (IOException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
			System.out.println("IOException " + FtpNioServer.connum + " Client:" + sc.socket().getRemoteSocketAddress().toString() + " close");
			return;
		}
	}
	
	private void proccessLsCmd(SelectionKey key) throws IOException {
		File dir = new File(FtpNioServer.ROOT);
		File files[] = dir.listFiles();
		
		String ret = null;
		for (File f : files) {
			if (ret == null) {
				ret = f.getName();
			} else {
				ret += ";";
				ret += f.getName();
			}
		}
		
		ByteBuffer src = null;
		if (ret != null) {
			src = ByteBuffer.wrap(ret.getBytes());
		} else {
			String error = "cmd execute fail!!!";
			src = ByteBuffer.wrap(error.getBytes());
		}
		
		// write data to client socket channel
		this.sc.write(src);
		
		ReleaseResource(key);
		
		System.out.println(FtpNioServer.connum + " Client:" + sc.socket().getRemoteSocketAddress().toString() + " close");
		
		FtpNioServer.connum--;
	}
	
	private void WriteToFile(String path, ByteBuffer buf) throws IOException {
		
		if (fileChannel == null) {
			fileChannel = new RandomAccessFile(path, "rw").getChannel();
		}
		
		buf.flip();
		fileChannel.write(buf);
		buf.clear();
	}
	
	@SuppressWarnings("resource")
	private int ReadFromFile(String path, ByteBuffer buf) throws IOException {
		
		if (fileChannel == null) {
			fileChannel = new RandomAccessFile(path, "r").getChannel();
		}
		
		buf.clear();
		return fileChannel.read(buf);
	}
	
	private void ReleaseResource(SelectionKey key) throws IOException {
		
		sc.close();
		key.cancel();

		if (fileChannel != null) {
			fileChannel.close();
		}
	}
}






  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值