採用 Client-Server 架構,Server 端維護一個執行緒池處理多客戶端連線,傳輸協定自訂簡易二進制協定:
[命令碼:1 byte] [檔名長度:2 bytes] [檔名] [檔案大小:8 bytes] [檔案內容]
// 接收檔案
public void receiveFile(Socket client) throws IOException {
DataInputStream in = new DataInputStream(client.getInputStream());
byte cmd = in.readByte();
if (cmd == CMD_FILE) {
int nameLen = in.readShort();
byte[] nameBytes = new byte[nameLen];
in.readFully(nameBytes);
String fileName = new String(nameBytes, StandardCharsets.UTF_8);
long fileSize = in.readLong();
try (FileOutputStream fos = new FileOutputStream("upload/" + fileName)) {
byte[] buffer = new byte[8192];
long remaining = fileSize;
while (remaining > 0) {
int read = in.read(buffer, 0, (int) Math.min(buffer.length, remaining));
if (read == -1) break;
fos.write(buffer, 0, read);
remaining -= read;
}
}
// 回覆成功
new DataOutputStream(client.getOutputStream()).writeByte(RESP_OK);
}
}
public void sendFile(String serverIp, int port, File file) throws IOException {
try (Socket socket = new Socket(serverIp, port);
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
FileInputStream fis = new FileInputStream(file)) {
out.writeByte(CMD_FILE);
byte[] nameBytes = file.getName().getBytes(StandardCharsets.UTF_8);
out.writeShort(nameBytes.length);
out.write(nameBytes);
out.writeLong(file.length());
byte[] buffer = new byte[8192];
int read;
while ((read = fis.read(buffer)) != -1) {
out.write(buffer, 0, read);
}
out.flush();
// 讀取回覆
DataInputStream in = new DataInputStream(socket.getInputStream());
byte resp = in.readByte();
if (resp == RESP_OK) System.out.println("上傳成功");
}
}
DataInputStream/DataOutputStream 處理二進制資料,避免編碼問題。