java使用UDP發送文件
環境
maven 3.6
jdk 1.8
udp-nio 分支支持批量發送
2021-05-10 udp-nio分支代碼已廢棄
請參考 udp-etty 分支代碼
服務端源碼(接收文件)
package com.banywl.file.transfer.udp;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
/**
* 文件接收服務器
*/
public class UDPFileServer {
/**
* socket 緩沖區
*/
private DatagramSocket socket;
/**
* 文件包數據大小
*/
private int packetSize;
/**
* 名稱長度值占用4字節
* 文件長度值占用8字節
*/
private byte[] fileInfo = new byte[12];
/**
* packet 緩沖區
*/
private byte[] packetBuf;
/**
* 文件名長度值用4字節緩沖區接收 int 值
*/
private DatagramPacket fileNameLenPacket;
/**
* 文件長度值使用8字節緩沖區接收 long 值
*/
private DatagramPacket fileLenPacket;
/**
* 文件數據封包使用512字節緩沖區分段接收
*/
private DatagramPacket filePacket;
/**
* 接收到的文件名
*/
private String fileName;
/**
* 接收到的文件內容
*/
private byte[] fileData;
/**
* 初始化文件接收UDP服務
*
* @param port 監聽端口
* @param packetSize 封包大小
* @throws SocketException
*/
public UDPFileServer(int port, int packetSize) throws SocketException {
this.socket = new DatagramSocket(port);
this.packetSize = packetSize;
this.packetBuf = new byte[packetSize];
fileNameLenPacket = new DatagramPacket(fileInfo, 4);
fileLenPacket = new DatagramPacket(fileInfo, 4,8);
filePacket = new DatagramPacket(packetBuf, this.packetSize);
}
/**
* 接收文件,
* udp 包順序: 1、文件名長度值 2、文件長度值 3、文件名 4、文件內容
*
* @return 文件內容字節數組
* @throws IOException
*/
public void receiveFile() throws IOException {
// 讀取文件名長度
this.socket.receive(fileNameLenPacket);
// 讀取文件長度
this.socket.receive(fileLenPacket);
// 取回文件名
byte[] fileNameBuf = new byte[Utils.bytesToInt(this.fileInfo)];
DatagramPacket fnPacket = new DatagramPacket(fileNameBuf, fileNameBuf.length);
this.socket.receive(fnPacket);
this.fileName = new String(fileNameBuf);
// 建立文件緩沖區,讀取文件內容到緩沖區
int fileLen = (int) Utils.bytesToLong(this.fileInfo,4);
this.fileData = new byte[fileLen];
int writePos = 0;
while (writePos != fileLen) {
// 取回文件內容
this.socket.receive(filePacket);
if (writePos + this.packetSize < fileLen) {
System.arraycopy(packetBuf, 0, this.fileData, writePos, this.packetSize);
writePos += this.packetSize;
} else {
int rsize = fileLen - writePos;
System.arraycopy(packetBuf, 0, this.fileData, writePos, rsize);
writePos += rsize;
}
System.out.println(String.format("已接收:%.4f",(double)writePos / (double) fileLen));
}
System.out.println("接收完成");
}
public void close() {
this.socket.close();
}
public String getFileName() {
return fileName;
}
public byte[] getFileData() {
return fileData;
}
}
UDP客戶端源碼(發送文件)
package com.banywl.file.transfer.udp;
import java.io.*;
import java.net.*;
import java.util.concurrent.TimeUnit;
/**
* 文件發送客戶端
*/
public class UDPFileClient {
private InetAddress address;
private int port;
/**
* 包大小
*/
private int packetSize;
/**
* 文件包
*/
private byte[] packetBuf;
/**
* 名稱長度值占用4字節
* 文件長度值占用8字節
*/
private byte[] fileInfoBuf = new byte[12];
/**
* 文件名 packet
*/
private DatagramPacket fileNameLenPacket;
/**
* 文件長度 packet
*/
private DatagramPacket fileLenPacket;
/**
* 文件數據 packet
*/
private DatagramPacket filePacket;
private DatagramSocket socket = new DatagramSocket();
/**
* 初始化文件發送
* @param hostname 目標主機名稱
* @param port 目標端口
* @param packetSize 封包大小
* @throws UnknownHostException
* @throws SocketException
*/
public UDPFileClient(String hostname, int port,int packetSize) throws UnknownHostException, SocketException {
this.address = InetAddress.getByName(hostname);
this.port = port;
this.packetSize = packetSize;
this.packetBuf = new byte[this.packetSize];
// 文件名長度值用4字節
this.fileNameLenPacket = new DatagramPacket(this.fileInfoBuf,4,this.address,port);
// 文件長度使用8字節
this.fileLenPacket = new DatagramPacket(this.fileInfoBuf,4,8,this.address,port);
// 文件使用512字節分段發送
this.filePacket = new DatagramPacket(packetBuf,this.packetSize,this.address,port);
}
/**
* udp 包順序: 1、文件名長度值 2、文件長度值 3、文件名 4、文件內容
* @param filePath 文件路徑
* @throws IOException
*/
public void sendFile(String filePath) throws IOException {
// 讀取系統文件
File file = new File(filePath);
byte[] fileBuf = new byte[(int)file.length()];
byte[] readBuf = new byte[2048];
int readLen,staPos = 0;
FileInputStream inputStream =new FileInputStream(file);
while ((readLen = inputStream.read(readBuf))!=-1){
System.arraycopy(readBuf,0,fileBuf,staPos,readLen);
staPos += readLen;
}
// 發送文件名長度值和文件長度值
System.arraycopy(Utils.intToBytes(file.getName().getBytes().length),0,this.fileInfoBuf,0,4);
System.arraycopy(Utils.longToBytes(file.length()),0,this.fileInfoBuf,4,8);
socket.send(fileNameLenPacket);
socket.send(fileLenPacket);
// 發送文件名
DatagramPacket fileNamPacket = new DatagramPacket(file.getName().getBytes(),file.getName().getBytes().length,address,port);
socket.send(fileNamPacket);
// 發送文件
int readIndex = 0;
while (readIndex != fileBuf.length){
if(readIndex + this.packetSize < fileBuf.length){
System.arraycopy(fileBuf,readIndex,packetBuf,0,this.packetSize);
readIndex += this.packetSize;
}else{
int rsize = fileBuf.length - readIndex;
System.arraycopy(fileBuf,readIndex,packetBuf,0,rsize);
readIndex += rsize;
}
socket.send(filePacket);
System.out.println(String.format("已發送:%.4f",(double)readIndex / (double) file.length()));
try {
TimeUnit.MILLISECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("發送完成");
}
public void close(){
this.socket.close();
}
}
例子(Application.java)
package com.banywl.file.transfer.udp;
import java.io.*;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Scanner;
public class Application {
/**
* -server 18888 10240
* -client 255.255.255.255 18888 10240 path/to/file
* @param args
*/
public static void main(String[] args) {
String baseDir = System.getProperty("user.dir") ;
System.out.println(baseDir);
if (args.length == 0) {
System.out.println("參數錯誤!");
System.exit(0);
}
if ("-server".equals(args[0])) {
System.out.println("啟動服務端");
int port = Integer.parseInt(args[1]);
int size = args.length == 2 ? 1024 : Integer.parseInt(args[2]);
try {
UDPFileServer server = new UDPFileServer(port,size);
while (true){
System.out.println("等待接收");
server.receiveFile();
System.out.println("收到文件:"+ server.getFileName());
File file = new File(baseDir + File.separator+ "receive" + File.separator+server.getFileName());
if (!file.getParentFile().exists()){
file.getParentFile().mkdir();
}
FileOutputStream fo = new FileOutputStream(file);
fo.write(server.getFileData());
fo.close();
System.out.println("是否退出(Y/N)?");
Scanner scanner = new Scanner(System.in);
if ("y".equalsIgnoreCase(scanner.next())){
break;
}
}
server.close();
System.out.println("服務器已關閉");
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}else if("-client".equals(args[0])){
System.out.println("啟動客戶端");
String ip = args[1];
int port = Integer.parseInt(args[2]);
int size = Integer.parseInt(args[3]);
String pathname = args[4];
try {
UDPFileClient client = new UDPFileClient(ip,port,size);
client.sendFile(pathname);
client.close();
System.out.println("發送完成");
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}