JAVA使用UDP收发文件
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();
}
}
}
}