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