前端时间,项目需要文件断点续传,需要抛弃原来的UDT文件传输。改用UDP传输。
因为UDP传送数据较TCP快速,系统开销也少,所以选择UDP,但UDP不对收到的数据进行排序,在UDP报文的首部中并没有关于数据顺序的信息(如TCP所采用的序号),而且报文不一定按顺序到达的,所以接收端无从排起。UDP对接收到的数据报也不发送确认信号,发送端不知道数据是否被正确接收,也不会重发数据,所以我们要自己在制定一套协议。废话不多说上代码。
/**
* 断点发送文件
* @param filepath 文件路径
* @param startindex 文件已经发送大小
* @param videoArrayList 需要发送的文件列表
* @throws JSONException json异常
* @throws IOException io异常
*/
public void sendFile(String filepath, long startindex,
ArrayList videoArrayList) throws JSONException,
IOException {
long fileAccess = 0;
if (client != null && !client.isClosed()) {
client.close();
client = null;
}
client = new DatagramSocket();
client.setSoTimeout(3 * 1000);
try {
String sendStr = "C";
byte[] sendBuf;
sendBuf = sendStr.getBytes();
InetAddress addr = InetAddress.getByName(Custom.getMainLoginIp().getIP());
DatagramPacket sendPacket = new DatagramPacket(sendBuf,sendBuf.length, addr, Util.UDP_PORT);
client.send(sendPacket);
Log.e("UDP", "UDP Control--> sendFile 发送C");
byte[] recvBuf = new byte[1];
DatagramPacket recvPacket = new DatagramPacket(recvBuf,recvBuf.length);
client.receive(recvPacket);
String recvStr = new String(recvPacket.getData(), 0,recvPacket.getLength());
Log.e("UDP", "UDP Control--> sendFile 接受响应" + recvStr);
while (!"S".equals(recvStr)) {
client.receive(recvPacket);
recvStr = new String(recvPacket.getData(), 0,recvPacket.getLength());
}
VideoFilePath zipFilePath = new VideoFilePath();
zipFilePath.setVideoPath(filepath);
zipFilePath.setVideoAccess(startindex);
File zipFile = new File(filepath);
if (!zipFile.exists()) {
throw new FileNotFoundException();
}
zipFilePath.setVideoLength(zipFile.length());
videoArrayList.add(zipFilePath);
for (int v = 0; v < videoArrayList.size(); v++) {
VideoFilePath videoFilePath = videoArrayList.get(v);
File file = new File(videoFilePath.getVideoPath());
if (!file.exists()) {
throw new FileNotFoundException();
}
RandomAccessFile access = new RandomAccessFile(file, "r");
sendBuf = new byte[1024 * 5];
long tatol = videoFilePath.getVideoLength() - videoFilePath.getVideoAccess();
access.skipBytes((int) videoFilePath.getVideoAccess());
Log.e("UDP", "UDP Control--> 开始发送文件");
int len = (int) (videoFilePath.getVideoLength() - videoFilePath.getVideoAccess());
if (len > sendBuf.length) {
len = sendBuf.length;
}
fileAccess += videoFilePath.getVideoAccess();
while (tatol > 0 && isSendFile) {
int sendAccess = 0;
for (int i = 0; i < 20; i++) {
if (tatol < len) {
sendBuf = new byte[(int) tatol];
len = (int) tatol;
}
int rlength = access.read(sendBuf, 0, len);
tatol -= rlength;
sendAccess += rlength;
if (rlength > 0) {
byte[] sendIndexBuf = new byte[rlength + 4];
System.arraycopy(sendBuf, 0, sendIndexBuf, 4,rlength);
Util.int2Byte(i, sendIndexBuf, 0);
sendPacket = new DatagramPacket(sendIndexBuf,sendIndexBuf.length, addr, Util.UDP_PORT);
client.send(sendPacket);
}
if (tatol <= 0) {
break;
}
}
recvBuf = new byte[1];
recvPacket = new DatagramPacket(recvBuf, recvBuf.length);
client.receive(recvPacket);
soTimeIndex = 0;
fileAccess += sendAccess;
Message startMsg = new Message();
startMsg.arg1 = Const.UP_PROGRESS;
startMsg.obj = fileAccess;
if (tatol <= 0 && v == videoArrayList.size() - 1) {
startMsg.arg1 = Const.UP_UDP_SUCCESS;
}
handler.sendMessage(startMsg);
}
access.close();
}
client.close();
} catch (SocketTimeoutException e) {
if (isSendFile) {
Message msg = handler.obtainMessage();
soTimeIndex++;
if (soTimeIndex >= 5) {
soTimeIndex = 0;
msg.arg1 = Const.UP_SCREEN_CLOSE;
} else {
msg.arg1 = Const.UP_UDP_CLOSE;
}
handler.sendMessage(msg);
client.close();
}
}
}
/**
* int转byte数组
*
* @param a
* @param b
* @param offset
* @return
*/
public static void int2Byte(int a, byte[] b, int offset) {
b[offset++] = (byte) (a >> 24);
b[offset++] = (byte) (a >> 16);
b[offset++] = (byte) (a >> 8);
b[offset++] = (byte) (a);
}
/**
* 断点接受文件
* @param filepath 文件路径
* @param startindex 文件已接受大小
* @param totallen 文件总长度
* @param videoArrayList 还需接受文件列表
* @return 是否接受成功
* @throws Exception
*/
@SuppressWarnings("resource")
private boolean recevfileContinue(String filepath, long startindex,long totallen, ArrayList videoArrayList)throws Exception {
ArrayList fileList = new ArrayList();
fileList.addAll(videoArrayList);
ArrayList<byte[]> recevList = new ArrayList<byte[]>();
boolean isSucc = true;
Log.e("UDP", "recevFile---->startindex:" + startindex);
Log.e("UDP", "recevFile---->totallen:" + totallen);
if (datagramServer != null && !datagramServer.isClosed()) {
datagramServer.close();
datagramServer = null;
}
Log.e("UDP", "接受文件 datagramServer.close");
byte[] sendbufs = new byte[1];
datagramServer = new DatagramSocket(null);
datagramServer.setReuseAddress(true);
datagramServer.bind(new InetSocketAddress(Util.UDP_PORT));
datagramServer.setSoTimeout(2500);
Log.e("UDP", "接受文件 setSoTimeout");
byte[] recvBuf = new byte[1];
Log.e("UDP", "接受文件 recvBuf");
DatagramPacket recvPacket = new DatagramPacket(recvBuf, recvBuf.length);
Log.e("UDP", "接受文件 recvPacket");
datagramServer.receive(recvPacket);
Log.e("UDP", "接受文件 receive");
String recvStr = new String(recvPacket.getData(), 0,
recvPacket.getLength());
Log.e("UDP", "接受文件 recvStr" + recvStr);
while (!"C".equals(recvStr)) {
datagramServer.receive(recvPacket);
recvStr = new String(recvPacket.getData(), 0,
recvPacket.getLength());
}
int port = recvPacket.getPort();
InetAddress addr = recvPacket.getAddress();
Log.e("UDP", "接受文件 port" + port + " addr" + addr.toString());
String sendStr = "S";
byte[] sendBuf;
sendBuf = sendStr.getBytes();
DatagramPacket sendPacket = new DatagramPacket(sendBuf, sendBuf.length,
addr, port);
datagramServer.send(sendPacket);
VideoFilePath videoFilePath = new VideoFilePath();
videoFilePath.setVideoPath(filepath);
videoFilePath.setVideoAccess(startindex);
videoFilePath.setVideoLength(totallen);
fileList.add(videoFilePath);
for (int v = 0; v < fileList.size(); v++) {
VideoFilePath videoFile = fileList.get(v);
String[] str = videoFile.getVideoPath().split("/");
String videoPath = FileHelper.TEMP_DIR + "//" + str[str.length - 1];
File file = new File(videoPath);
long tatol = -1;
RandomAccessFile access = null;
access = new RandomAccessFile(file, "rw");
access.skipBytes((int) videoFile.getVideoAccess());
tatol = videoFile.getVideoLength() - videoFile.getVideoAccess();
Log.e("UDP", "接受文件 while");
while (tatol > 0) {
for (int arraySize = 0; arraySize < 20; arraySize++) {
recevList.add(arraySize, new byte[0]);
}
for (int i = 0; i < 20; i++) {
if (tatol <= 0) {
break;
}
recvBuf = new byte[(1024 * 5) + 4];
recvPacket = new DatagramPacket(recvBuf, recvBuf.length);
try {
datagramServer.receive(recvPacket);
} catch (SocketTimeoutException e) {
Log.e("UDP", "接受文件时链接超时 e" + e.getLocalizedMessage());
if (datagramServer != null&& !datagramServer.isClosed()) {
datagramServer.close();
datagramServer = null;
}
return false;
}
Log.e("UDP", "接受文件 arraycopy file");
int reallen = recvPacket.getLength() - 4;
Log.d("UDP", "接受文件 reallen == " + reallen);
if (reallen <= 0) {
return false;
}
tatol -= reallen;
byte[] recvBuffs = new byte[reallen];
Log.e("UDP", "接受文件 recvPacket.getData().length"
+ recvPacket.getData().length);
System.arraycopy(recvPacket.getData(), 4, recvBuffs, 0,
reallen);
int index = Util.getInt(recvPacket.getData(), 0);
recevList.add(index, recvBuffs);
Log.e("UDP", "index ; " + index);
}
sendbufs[0] = (byte) 0x06;
sendPacket = new DatagramPacket(sendbufs, sendbufs.length,addr, port);
Log.e("UDP", "接受文件 send data");
datagramServer.send(sendPacket);
for (int re = 0; re < recevList.size(); re++) {
byte[] buffs = recevList.get(re);
Log.e("UDP", "接受文件 write file");
access.write(buffs, 0, buffs.length);
}
recevList.clear();
Log.d("recevfileContinue", "tatol == " + tatol);
}
access.close();
}
datagramServer.close();
Log.d("recevfileContinue", "isSucc == " + isSucc);
return isSucc;
}
/**
* 判断是否为断点续传
*
* @param fileName
* 文件名字
* @param md5
* 文件md5
* @return 文件已经存在长度
*/
private long sendFileContinue(String fileName, String md5,
ArrayList videoArray) {
String filepath = FileHelper.TEMP_DIR + "//" + fileName;
String textFilePath = FileHelper.TEMP_DIR + "//fileText.xml";
File textFile = new File(textFilePath);
File file = new File(filepath);
try {
for (int v = 0; v < videoArray.size(); v++) {
VideoFilePath videoFilePath = videoArray.get(v);
String[] str = videoFilePath.getVideoPath().split("/");
String videoPath = FileHelper.TEMP_DIR + "//"
+ str[str.length - 1];
File videoFile = new File(videoPath);
if (videoFile.exists()) {
videoFilePath.setVideoAccess(videoFile.length());
} else {
videoFilePath.setVideoAccess(0);
}
}
if (!textFile.exists()) {
textFile.createNewFile();
}
String textStr = FileHelper.readFile(textFilePath);
ArrayList sendFileTextArrayList = Json
.analysisFileText(textStr);
if (file.exists()) {
for (int i = 0; i < sendFileTextArrayList.size(); i++) {
SendFileText sendFileText = sendFileTextArrayList.get(i);
if (fileName.equals(sendFileText.getFileName())) {
if (md5.equals(sendFileText.getFileMD5())) {
return FileHelper.fileSize(filepath);
} else {
sendFileTextArrayList.remove(sendFileText);
break;
}
}
}
FileHelper.deleteFile(filepath);
SendFileText addSendFileText = new SendFileText();
addSendFileText.setFileMD5(md5);
addSendFileText.setFileName(fileName);
sendFileTextArrayList.add(addSendFileText);
FileHelper.writeFile(textFilePath,
Json.structureFileText(sendFileTextArrayList));
return 0;
} else {
for (int i = 0; i < sendFileTextArrayList.size(); i++) {
SendFileText sendFileText = sendFileTextArrayList.get(i);
if (fileName.equals(sendFileText.getFileName())
|| md5.equals(sendFileText.getFileMD5())) {
sendFileTextArrayList.remove(sendFileText);
break;
}
}
SendFileText addSendFileText = new SendFileText();
addSendFileText.setFileMD5(md5);
addSendFileText.setFileName(fileName);
sendFileTextArrayList.add(addSendFileText);
FileHelper.writeFile(textFilePath,
Json.structureFileText(sendFileTextArrayList));
return 0;
}
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}