本篇主旨在於client端下載server端的檔案後,進行MD5 checksum的檢查,確認檔案是否無誤!
程式撰寫如下:
1. 建立Server.java,等待Client端連線,連線上之後呈列目前可供下載的檔案
2. 建立Client.java,與Server端連線後,選擇檔案後進行下載
3. 建立Main.java,代表程式入口,可輸入相關參數選擇要執行哪一種模式(Server or Client)
#Server.java
package service;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import main.Main;
public class Server {
private ServerSocket server;
private File sharePath;
public Server(int port, File sharePath) throws IOException {
this.sharePath = sharePath;
this.server = new ServerSocket(port);
}
public void startService() {
while(!server.isClosed()) {
try {
System.out.println("Waiting for the Client connection...");
Socket socket = server.accept();
String client = socket.getInetAddress().getHostAddress();
System.out.println("Connection received from: "+client);
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
File listFiles[] = sharePath.listFiles();
oos.writeObject("The files that can be downloaded are as follows:");
int index = 0;
oos.writeObject(listFiles.length);
for(File f : listFiles) {
oos.writeObject("("+(++index)+")"+f.getName());
}
while (!socket.isClosed()) {
System.out.println("Waiting for the "+client+" to send option id");
Object selection = ois.readObject();
if(selection instanceof Integer) {
int sel = (int) selection;
System.out.println("Client send option id is "+sel);
if(sel == 0) {
socket.close();
break;
}
if(sel > listFiles.length) {
System.out.println("File non-exist!!");
oos.writeLong(-1L);
oos.flush();
continue;
}
File sendFile = listFiles[sel - 1];
oos.writeLong(sendFile.length());
oos.writeObject(sendFile.getName());
String md5 = Main.getCheckSumByMD5(sendFile.getAbsolutePath());
oos.writeObject(md5);
InputStream is = new FileInputStream(sendFile);
int read;
byte[] buf = new byte[1024];
while((read = is.read(buf, 0, buf.length)) != -1) {
oos.write(buf, 0, read);
oos.flush();
}
is.close();
System.out.println("File "+sendFile.getName()+" transfer completed!");
System.out.println("===========================");
}
}
System.out.println("Client "+client+" disconnected!\n");
ois.close();
oos.close();
}catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
terminateService();
}
}
}
public void terminateService() {
try {
this.server.close();
System.out.println("Shutdown server");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
client連上後,server傳送檔案清單,當收到項目的編號後,依序將檔案size(bytes)、名稱、md5 checksum傳給client,接下來就是data部分,buffer設定1024 bytes分批傳送! 傳送完畢後等待client下一個項目編號!
PS. 在這邊只示範傳送檔案,若是目錄不在測試範圍內
#Client.java
package service;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
import main.Main;
public class Client {
private File dPath;
public Client(File downloadPath) {
this.dPath = downloadPath;
}
public void startService() {
InetAddress host;
Scanner input = new Scanner(System.in);
try {
host = InetAddress.getLocalHost();
Socket socket = new Socket(host.getHostName(), 5880);
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
System.out.println(ois.readObject());
int num = (int) ois.readObject();
int i = 0;
while(i++ < num) {
System.out.println(ois.readObject());
}
while(!socket.isClosed()) {
System.out.println("Waiting to send the option id [1 ~ "+num+"] to download file from server...");
System.out.println("Note. Terminate connection please input option 0");
int option = input.nextInt();
oos.writeObject(option);
if(option == 0) {
socket.close();
System.exit(-1);
}
System.out.println("Send option id is "+option);
long totalByte = ois.readLong();
if(totalByte == -1L) {
System.out.println("Download file non-exist!!");
System.out.println("===========================");
continue;
}
System.out.println("Download file total size is "+totalByte+" bytes");
String filename = (String) ois.readObject();
String checksum = (String) ois.readObject();
String path = dPath.getAbsolutePath() + File.separator + filename;
System.out.println("Download to "+path);
byte[] buffer = new byte[1024];
long cur = 0L;
FileOutputStream fos = new FileOutputStream(path);
while(cur < totalByte) {
int len = ois.read(buffer);
cur += len;
fos.write(buffer, 0, len);
double percent = ((double)cur / totalByte) * 100;
System.out.println("Download current size = "+cur + " bytes, percent = "+percent+"%");
}
System.out.println("Download completed!!\n");
fos.close();
System.out.println("Check if the file is correct>>>");
String md5 = Main.getCheckSumByMD5(path);
System.out.println("Transferred file checksum => "+checksum);
System.out.println("Downloaded file checksum => "+md5);
if(md5.equals(checksum)) {
System.out.println("Yes. It is corrent!");
}else {
System.out.println("No. It is incorrent!");
}
System.out.println("===========================");
}
input.close();
ois.close();
oos.close();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
client端連上server後,收到檔案清單,傳送項目編號後,收到檔案大小判斷是否存在,開始接收data後,計算當下下載進度,完畢後計算檔案md5 checksum,與server端的checksum進行比對,確認是否檔案傳輸正確!
#Main.java
package main;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import org.apache.commons.codec.digest.DigestUtils;
import service.Client;
import service.Server;
public class Main {
private static final int PORT = 5880;
public static void main(String[] args) {
// TODO Auto-generated method stub
if(args.length == 0) {
System.out.println("<<File Transfer Service>>"
+ "\nStart client mode -> java -jar ftransfer.jar client [target path]"
+ "\nStart server mode -> java -jar ftransfer.jar server [share path]");
}else {
if(args.length == 1) {
System.out.println("Please specify path");
}else {
File path = new File(args[1]);
if(!path.exists()) {
System.out.println("The path non-exist");
}else {
String mode = args[0];
if(mode.equals("server")) {
Server server = null;
try {
server = new Server(PORT, path);
server.startService();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if(server != null) {
server.terminateService();
}
}
}else if(mode.equals("client")) {
Client client = new Client(path);
client.startService();
}
}
}
}
}
public static String getCheckSumByMD5(String filepath) throws IOException {
try (InputStream is = Files.newInputStream(Paths.get(filepath))) {
return DigestUtils.md5Hex(is);
}
}
}
依據主程式輸入的參數來決定開啟server or client mode
最後DEMO如下:
1. 透過eclipse輸出成可執行的jar檔FileTransfer.jar進行示範
2. 執行java -jar FileTransfer.jar (展現提示)
3. 啟動server,指定分享路徑D:\server
4. 啟動client,指定下載存放目錄E:\
5. server端輸出client端資訊,並且等待項目編號的回應
6. client端下載項目1
7. server端顯示收到需傳送項目1的檔案,傳送完畢後等待下一個項目要求
8. client端輸入無效id & terminate server connection
9. server端顯示檔案不存在 & terminate client connection
上面的步驟對照下面的圖示如下
留言
張貼留言