最近学习网络编程,多线程,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);
}