java 简单的文件上传下载服务器模型(IO + 多线程)

最近学习网络编程,多线程,IO等知识,综合这些知识写了个简单的文件上传下载服务器模型,目前是基于IO+多线程的方式,比较简单,异常基本没有处理,将就一下,哈

哈。后续会将其改造为NIO的方式,最后再将其改造成NIO+多线程的方式,敬请期待,^_^

服务器端基于Java IO+多线程

package com.myftp.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 java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

import com.myftp.handler.FtpHandler;
import com.myftp.handler.FtpServerHandler;

public class FtpServer {
	public final static int PORT = 5000;
	public final static String ROOT = "D:/FtpDir/";
	public static AtomicInteger connum = new AtomicInteger(0);
	
	public static ExecutorService exc = Executors.newCachedThreadPool();
	
	public static void main(String argv[]) {
		
		try {
			Selector s = Selector.open();
			ServerSocketChannel ssc = ServerSocketChannel.open();
			ssc.configureBlocking(false);
			SelectionKey key = ssc.register(s, SelectionKey.OP_ACCEPT);
			key.attach(new FtpServerHandler(s, ssc));
			
			ServerSocket ss = ssc.socket();
			ss.bind(new InetSocketAddress(PORT));
			
			System.out.println("Start ftp server on " + PORT);
			
			while (!Thread.interrupted()) {
				
				int n = s.select();
				
				if (n == 0) {
					continue;
		        }
				
				Iterator<SelectionKey> it = s.selectedKeys().iterator();
	            while (it.hasNext()) 
	            {
	                SelectionKey sk = it.next();
	                it.remove();
	                
	                FtpHandler handler = (FtpHandler) sk.attachment();
					handler.execute(sk);
	            }
			}
			
		} 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;
	}
}

package com.myftp.handler;

import java.io.File;
import java.io.IOException;
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.myftp.downloadthread.DownLoadFile;
import com.myftp.server.FtpServer;
import com.myftp.uploadthread.UpLoadFile;

public class FtpServerHandler implements FtpHandler {

	private ServerSocketChannel ssc;
	
	public FtpServerHandler(Selector selector, ServerSocketChannel ssc) {
		this.ssc = ssc;
	}
	
	@Override
	public void execute(SelectionKey key) {
		// TODO Auto-generated method stub
		
		try {
			// get client socket channel
			SocketChannel lsockChannel = null;
			lsockChannel = ssc.accept();
			
			// read data from client socket channel
			ByteBuffer dst = ByteBuffer.allocate(1024);
			lsockChannel.read(dst);
			String cmd = FtpServer.ByteBufferToString(dst);
			
			// set the connect number
			FtpServer.connum.set(FtpServer.connum.get() + 1);
			
			// print the client info
			System.out.println(FtpServer.connum.get() + " client:" + lsockChannel.socket().getRemoteSocketAddress().toString() + " cmd:" + cmd);
			
			// deal Command
			try {
				processCmd(cmd, lsockChannel);
			} catch (Exception e) {
				e.printStackTrace();
			}

		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public void processCmd(String cmd, SocketChannel lsockChannel) throws IOException {
		if (cmd.toLowerCase().equals("ls")) {
			lsCmd(cmd, lsockChannel);
			return;
		}
		
		if (cmd.toLowerCase().startsWith("download")) {
			downloadCmd(cmd, lsockChannel);
			return;
		}
		
		if (cmd.toLowerCase().startsWith("upload")) {
			uploadCmd(cmd, lsockChannel);
			return;
		}
		
		// send client with data:no match command
		ByteBuffer other = FtpServer.StringToByteBuffer("cmd not exist, please check you command and try again!!!");		
		lsockChannel.write(other);
		
		//close SocketChannel
		lsockChannel.close();
	}
	
	public void lsCmd(String cmd, SocketChannel lsockChannel) throws IOException {
		File dir = new File(FtpServer.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
		lsockChannel.write(src);
		
		//close SocketChannel
		lsockChannel.close();
	}
	
	public void downloadCmd(String cmd, SocketChannel lsockChannel) throws IOException {
		String f[] = cmd.split(":");
		String filepath = FtpServer.ROOT + f[1];
		
		Runnable r = new DownLoadFile(filepath, lsockChannel);
		FtpServer.exc.execute(r);
		
		return;
	}
	
	public void uploadCmd(String cmd, SocketChannel lsockChannel) throws IOException {
		String f[] = cmd.split(":");
		String tmp[] = f[1].split("/");
		String filepath = FtpServer.ROOT + tmp[tmp.length -1];
		
		Runnable r = new UpLoadFile(filepath, lsockChannel);
		FtpServer.exc.execute(r);
				
		return;
	}
}
package com.myftp.downloadthread;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.Arrays;

public class DownLoadFile implements Runnable {

	private String filepath;
	private SocketChannel lsockChannel;
	
	public DownLoadFile(String filepath, SocketChannel lsockChannel) {
		this.filepath = filepath;
		this.lsockChannel = lsockChannel;
	}
	
	@Override
	public void run() {
		
		try {
			FileInputStream fis = null;
			BufferedInputStream bis = null;
			fis = new FileInputStream(filepath);
			if (fis != null) {
				bis = new BufferedInputStream(fis);
				
				if (bis != null) {
					
					byte[] bs = new byte[512];	
					while(bis.available() > 512) {
						bis.read(bs);
						ByteBuffer src = ByteBuffer.wrap(bs);
						// write data to client socket channel
						lsockChannel.write(src);
						Arrays.fill(bs, (byte)0);
					}
					
					// 处理不足512的剩余部分
					int remain = bis.available(); 
					byte[] last = new byte[remain];
					bis.read(last);
					lsockChannel.write(ByteBuffer.wrap(last));
	             
					// release resource
					bis.close();
					fis.close();
					lsockChannel.close();
				} 
			}
						
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

package com.myftp.uploadthread;

import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;

public class UpLoadFile implements Runnable {
	private String path;
	private SocketChannel sc;
	
	public UpLoadFile(String path, SocketChannel sc) {
		this.path = path;
		this.sc = sc;
	}
	
	@Override
	public void run() {
		try {
			FileOutputStream fos = null;
			BufferedOutputStream bos = null;
			fos = new FileOutputStream(path);
			
			if (fos != null) {
				bos = new BufferedOutputStream(fos);
				if (bos != null) {
					ByteBuffer dst = ByteBuffer.allocate(512);
					while(true) {
						int n = sc.read(dst);
						if (n == 0) {
							continue;
						}
						
						if (n == -1) {
							break;
						}
						
						// write to file
						dst.flip();
						byte[] tempb = new byte[dst.limit()];
						dst.get(tempb);
						bos.write(tempb);	
						dst.clear();
					}
					
					// release resource
					bos.close();
					fos.close();
					sc.close();
				}
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

客户端基于C语言,阻塞方式。

#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/errno.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void processDownLoad(char* filename, int sock);
void processUpLoad(char* path, int sock);

char* path = "/home/ftpclient/";

int main(int argc, char** argv) 
{
	if (argc != 4) 
	{
		printf("Usage: %s server_ip server_port content\n", argv[0]);
		exit(1);
	}
	
	int ret = -1;
	int sock = -1;
	char buf[1024] = {0};
	
	struct sockaddr_in ftpserver;

	sock = socket(PF_INET, SOCK_STREAM, 0);
	if (sock == -1)
	{
		perror("create socket fail");
		exit(1);
	}

	memset(&ftpserver, 0 ,sizeof(ftpserver));

	ftpserver.sin_family = AF_INET;
	ftpserver.sin_addr.s_addr = inet_addr(argv[1]);
	ftpserver.sin_port = htons(atoi(argv[2]));

	ret = connect(sock, (struct sockaddr*)&ftpserver, sizeof(ftpserver));
	if (ret != -1) 
	{
		send(sock, argv[3], strlen(argv[3]), 0);

		char *down = NULL;
		down = strstr(argv[3], "download");
		if (down != NULL)
		{
			char filename[128] = {0};
			char *p = strstr(argv[3], ":");
			strcpy(filename, p+1);	
			processDownLoad(filename, sock);
			return 0;
		}

		char *up = NULL;
		up = strstr(argv[3], "upload");
		if (up != NULL)
		{
			char path[128] = {0};
			char *p = strstr(argv[3], ":");
			strcpy(path, p+1);
			processUpLoad(path, sock);
			return 0;
		}
		
		recv(sock, buf, 1024, 0);
		
		close(sock);
		printf("%s\n", buf);

	}
	else 
	{
		perror("connect socket fail");
		exit(1);
	}
		
	return 0;
}

void processDownLoad(char *filename, int sock)
{
	printf("processDownLoad\n");
	
	char buf[1024] = {0};
	
	char name[128] = {0};
	strcat(name, path);
	strcat(name, filename);
	
	FILE* f = fopen(name, "a");
	if (f != NULL)
	{
		int recv_len = recv(sock, buf, 1024, 0);
		while(recv_len > 0)
		{
			fwrite(buf, recv_len, 1, f);

			memset(buf, 0, 1024);
			recv_len = recv(sock, buf, 1024, 0);
		}
	}
	else
	{
		perror("open file fail!");
		close(sock);
		exit(1);
	}

	fclose(f);
	close(sock);
}

void processUpLoad(char* path, int sock)
{
	printf("processUpLoad\n");
	
	char buf[1024] = {0};

	FILE* f = fopen(path, "r+");
	if (f != NULL) 
	{
		int read_len = fread(buf, 1, 1024, f);
		while( read_len  >= 0)
		{
			send(sock, buf, read_len, 0);
			if (feof(f))
			{
				break;
			}
			
			memset(buf, 0, 1024);
			read_len = fread(buf, 1, 1024, f);
		}
	}
	else
	{
		perror("open file fail!");
		close(sock);
		exit(1);
	}
	
	close(f);
	close(sock);
}





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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值