您的位置:首页 > 编程语言 > Java开发

基于rsync同步算法的文件同步系统JAVA实现(一)——项目介绍

2014-09-15 16:52 1411 查看


项目主要功能:

用java实现的类似rsync项目的文件同步:A拥有不完整文件file_half,B拥有完整文件file_total,A向B发送不完整文件的校验码信息,B利用完整文件进行分析后返回差异数据块,A收到差异数据块后与不完整文件file_half进行重组形成完整文件file_total_copy。


优点:

同步时传送的文件内容只是差异文件,则可以减少传输的数据,减少同步时间(主要减少了网络传输时间),当差异块相对文件大小很小时,优势尤为突出。还有附加的优点就是支持断点传输,查看差异部分(这有点像svn)。


主要原理:

1.在α端将不完整文件A分割成相同大小的数据块。

2.对每个数据块进行两种校验(滚动校验和md4)

3.将校验结果发送给拥有完整文件B的β端

4.β通过搜索文件B的所有大小为S的数据块,来寻找与文件A的某一块有着相同的弱校验码和强校验码的数据块。这项工作可以借助滚动校验的特性很快完成。

5.β生成差异文件块和相关信息并发送给α,α利用差异块和相关信息重新生成完整文件B’。


项目碰到的难点:

1.数据量大,测试调试困难。

2.需要对字节级别的数据进行操作。

3.分析差异数据块的算法设计与优化。

4.设计哪些数据报,怎么设计。

5.错误处理。

6.如何利用数据报控制客户端和服务端的程序运行和交流。

7.网络环境复杂。


项目进度与需要完善的问题:

1.核心同步在单机上(利用127.0.0.1环回测试)已经实现。

2.暂时只支持一次操作,用户体验较差。

3.程序运行时客户端和服务器交互能力较差。


项目主要技术:

java语言,javafx界面,rsync算法参考


项目测试界面:




项目核心时序图:






作用:

分析差异数据块过程中需要不完整文件各个数据块的两种校验:滚动校验和md4校验,先对完整文件的各个分块依次进行滚动校验,若相同再进行md4校验,若再次相同说明数据块匹配,否则不匹配,在文件中向后移动一个字节形成的新分块进行校验(利用滚动校验的特性可以很快完成)。


核心算法1-滚动校验(参考rsync源码,并作了少量类型修改(unsigned转long)):

弱校验,优点是速度快(但不能保证唯一性),两个校验函数,一种是根据一整个数据块生成校验码,另一种是根据前一个数据块已知的校验码和新的字节信息产生校验码(快)。


源码:

[java] view
plaincopyprint?

/**

* 非递推滚动校验 a simple 32 bit checksum that can be upadted from either end

* (inspired by Mark Adler's Adler-32 checksum)

*

* @param bs

* @param len

* @return

*/

public static long checkSum_Adler32(byte[] buf, int len) {

int i;

long s1, s2;

// for (i = 0; i < len ; i++) {

// if (buf[i] < 0) {

// buf[i] = (byte) -buf[i];

// }

// }

s1 = s2 = 0;

for (i = 0; i < (len - 4); i += 4) {

s2 += 4 * (s1 + buf[i]) + 3 * buf[i + 1] + 2 * buf[i + 2]

+ buf[i + 3];

s1 += (buf[i + 0] + buf[i + 1] + buf[i + 2] + buf[i + 3]);

}

for (; i < len; i++) {

s1 += (buf[i]);

s2 += s1;

}

return (s1 & 0xffff) + ((s2 & 0xffff) << 16);

}

/**

* 递推滚动校验 adler32_checksum(X0, ..., Xn), X0, Xn+1 ----> adler32_checksum(X1,

* ..., Xn+1) where csum is adler32_checksum(X0, ..., Xn), c1 is X0, c2 is

* Xn+1

*/

public static long adler32_rolling_checksum(long csum, int len, byte c1,

byte c2) {

// if (c1 < 0) {

// c1 = (byte) -c1;

// }

// if (c2 < 0) {

// c2 = (byte) -c2;

// }

long s1, s2;

s1 = (csum & 0xffff);

s2 = (csum >> 16);

s1 -= (c1 - c2);

s2 -= (len * c1 - s1);

return (s1 & 0xffff) + ((s2 & 0xffff) << 16);

}


核心算法2-md4(最好是md5)校验:

强校验,可以保证唯一性,但是速度慢些。


源码略


注意细节:

检验码最终需要转换成字节流,需要给出起始和终止信号。


部分整合源码:

[java] view
plaincopyprint?

public void writeCheckSumFile(InputStream in,

OutputStream outStreamCheckSumFile) throws IOException {

BufferedInputStream inStreamHalfFile = new BufferedInputStream(in);

byte[] buffer = new byte[BLOCKSIZE];

int amount = 0;

while ((amount = inStreamHalfFile.read(buffer)) != -1) {

sendCheckSumToFile(buffer, outStreamCheckSumFile, amount);

}

byte end[] = new byte[24];

Arrays.fill(end, (byte) -1);

outStreamCheckSumFile.write(end);

}

public void sendCheckSumToFile(byte[] buffer, OutputStream outputStream,

int amount) throws IOException {

long sum1 = SumChecking.checkSum_Adler32(buffer, amount);

byte sum2[] = Md4Checking.mdfour(buffer);

outputStream.write(DataConvertUtils.long2bytes(sum1));

outputStream.write(sum2);

}

public void readCheckSumFile(String filein) throws IOException {

BufferedInputStream fileInputStream = new BufferedInputStream(

new FileInputStream(filein));

byte[] buffer1 = new byte[8];

byte[] buffer2 = new byte[16];

while ((fileInputStream.read(buffer1)) != -1) {

fileInputStream.read(buffer2);

System.out.print(DataConvertUtils.bytes2long(buffer1) + ","); //$NON-NLS-1$

System.out.print(Md4Checking.toHexString(buffer2) + ";"); //$NON-NLS-1$

System.out.println();

}

fileInputStream.close();

}

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐