由於需要研究了下用 java socket 傳輸檔案,由於需要傳輸多個檔案,因此,採用了多線程設計。用戶端每個線程建立一個 socket 串連,每個 socket 串連負責傳輸一個檔案,服務端的ServerSocket每次 accept 一個 socket 串連,建立一個線程用於接收用戶端傳來的檔案。
1、服務端
import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.FileOutputStream; import java.net.ServerSocket; import java.net.Socket; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class TransferServer { private int defaultBindPort = Constants.DEFAULT_BIND_PORT; //預設監聽連接埠號碼為10000 private int tryBindTimes = 0; //初始的綁定連接埠的次數設定為0 private ServerSocket serverSocket; //服務通訊端等待對方的串連和檔案發送 private ExecutorService executorService; //線程池 private final int POOL_SIZE = 4; //單個CPU的線程池大小 /** * 不帶參數的構造器,選用預設的連接埠號碼 * @throws Exception */ public TransferServer() throws Exception{ try { this.bingToServerPort(defaultBindPort); executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * POOL_SIZE); System.out.println("開闢線程數 : " + Runtime.getRuntime().availableProcessors() * POOL_SIZE); } catch (Exception e) { throw new Exception("綁定連接埠不成功!"); } } /** * 帶參數的構造器,選用使用者指定的連接埠號碼 * @param port * @throws Exception */ public TransferServer(int port) throws Exception{ try { this.bingToServerPort(port); executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * POOL_SIZE); } catch (Exception e) { throw new Exception("綁定連接埠不成功!"); } } private void bingToServerPort(int port) throws Exception{ try { serverSocket = new ServerSocket(port); System.out.println(port); System.out.println("服務啟動!"); } catch (Exception e) { this.tryBindTimes = this.tryBindTimes + 1; port = port + this.tryBindTimes; if(this.tryBindTimes >= 20){ throw new Exception("您已經嘗試很多次了,但是仍無法綁定到指定的連接埠!請重新選擇綁定的預設連接埠號碼"); } //遞迴綁定連接埠 this.bingToServerPort(port); } } public void service(){ Socket socket = null; while (true) { try { socket = serverSocket.accept(); executorService.execute(new Handler(socket)); } catch (Exception e) { e.printStackTrace(); } } } class Handler implements Runnable{ private Socket socket; public Handler(Socket socket){ this.socket = socket; } public void run() { System.out.println("New connection accepted " + socket.getInetAddress() + ":" + socket.getPort()); DataInputStream dis = null; DataOutputStream dos = null; int bufferSize = 8192; byte[] buf = new byte[bufferSize]; try { dis = new DataInputStream(new BufferedInputStream(socket.getInputStream())); String savePath = Constants.RECEIVE_FILE_PATH + dis.readUTF(); long length = dis.readLong(); dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(savePath))); int read = 0; long passedlen = 0; while ((read = dis.read(buf)) != -1) { passedlen += read; dos.write(buf, 0, read); System.out.println("檔案[" + savePath + "]已經接收: " + passedlen * 100L/ length + "%"); } System.out.println("檔案: " + savePath + "接收完成!"); } catch (Exception e) { e.printStackTrace(); System.out.println("接收檔案失敗!"); }finally{ try { if(dos != null){ dos.close(); } if(dis != null){ dis.close(); } if(socket != null){ socket.close(); } } catch (Exception e) { e.printStackTrace(); } } } } public static void main(String[] args) throws Exception{ new TransferServer().service(); } }
2、用戶端
import java.io.BufferedInputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.net.Socket; import java.util.ArrayList; import java.util.Random; import java.util.Vector; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class TransferClient { private static ArrayList<String> fileList = new ArrayList<String>(); private String sendFilePath = Constants.SEND_FILE_PATH; /** * 帶參數的構造器,使用者設定需要傳送檔案的檔案夾 * @param filePath */ public TransferClient(String filePath){ getFilePath(filePath); } /** * 不帶參數的構造器。使用預設的傳送檔案的檔案夾 */ public TransferClient(){ getFilePath(sendFilePath); } public void service(){ ExecutorService executorService = Executors.newCachedThreadPool(); Vector<Integer> vector = getRandom(fileList.size()); for(Integer integer : vector){ String filePath = fileList.get(integer.intValue()); executorService.execute(sendFile(filePath)); } } private void getFilePath(String dirPath){ File dir = new File(dirPath); File[] files = dir.listFiles(); if(files == null){ return; } for(int i = 0; i < files.length; i++){ if(files[i].isDirectory()){ getFilePath(files[i].getAbsolutePath()); } else { fileList.add(files[i].getAbsolutePath()); } } } private Vector<Integer> getRandom(int size){ Vector<Integer> v = new Vector<Integer>(); Random r = new Random(); boolean b = true; while(b){ int i = r.nextInt(size); if(!v.contains(i)) v.add(i); if(v.size() == size) b = false; } return v; } private static Runnable sendFile(final String filePath){ return new Runnable(){ private Socket socket = null; private String ip ="localhost"; private int port = 10000; public void run() { System.out.println("開始傳送檔案:" + filePath); File file = new File(filePath); if(createConnection()){ int bufferSize = 8192; byte[] buf = new byte[bufferSize]; try { DataInputStream fis = new DataInputStream(new BufferedInputStream(new FileInputStream(filePath))); DataOutputStream dos = new DataOutputStream(socket.getOutputStream()); dos.writeUTF(file.getName()); dos.flush(); dos.writeLong(file.length()); dos.flush(); int read = 0; int passedlen = 0; long length = file.length(); //獲得要傳送檔案的長度 while ((read = fis.read(buf)) != -1) { passedlen += read; System.out.println("已經完成檔案 [" + file.getName() + "]百分比: " + passedlen * 100L/ length + "%"); dos.write(buf, 0, read); } dos.flush(); fis.close(); dos.close(); socket.close(); System.out.println("檔案 " + filePath + "傳輸完成!"); } catch (Exception e) { e.printStackTrace(); } } } private boolean createConnection() { try { socket = new Socket(ip, port); System.out.println("串連伺服器成功!"); return true; } catch (Exception e) { System.out.println("串連伺服器失敗!"); return false; } } }; } public static void main(String[] args){ new TransferClient().service(); } }
3、常量類
public interface Constants { public final static String RECEIVE_FILE_PATH = "E:\\receive\\"; public final static String SEND_FILE_PATH = "E:\\send"; public final static int DEFAULT_BIND_PORT = 10000; }
轉自【http://software.intel.com/zh-cn/user/817741】