Java图像传输问题

时间:2011-01-17 21:41:44

标签: java image networking crc32

我有一个学校作业,发送jpg图像,将其拆分为100个字节的组,破坏它,使用CRC校验来定位错误并重新传输,直到最终构建回原始形式。 / p>

它已经准备就绪,但是当我查看新图像时,它们会出现错误。

我真的很感激,如果有人可以查看我下面的代码并且可能找到这个逻辑错误,因为我无法理解问题是什么,因为一切看起来都不错:S

对于包含照片和错误模式所需的所有数据的文件,可以从以下链接下载:http://rapidshare.com/#!download | 932tl2 | 443122762 | Data.zip | 739

不要忘记更改图像和错误文件代码中的路径。

package networks;

import java.io.*;               // for file reader
import java.util.zip.CRC32;     // CRC32 IEEE (Ethernet)

public class Main {

/**
 * Reads a whole file into an array of bytes.
 * @param file The file in question.
 * @return Array of bytes containing file data.
 * @throws IOException Message contains why it failed.
 */
public static byte[] readFileArray(File file) throws IOException {
    InputStream is = new FileInputStream(file);
    byte[] data=new byte[(int)file.length()];
    is.read(data);
    is.close();
    return data;
}

/**
 * Writes (or overwrites if exists) a file with data from an array of bytes.
 * @param file The file in question.
 * @param data Array of bytes containing the new file data.
 * @throws IOException Message contains why it failed.
 */
public static void writeFileArray(File file, byte[] data) throws IOException {
    OutputStream os = new FileOutputStream(file,false);
    os.write(data);
    os.close();
}

/**
 * Converts a long value to an array of bytes.
 * @param data The target variable.
 * @return Byte array conversion of data.
 * @see http://www.daniweb.com/code/snippet216874.html
 */
public static byte[] toByta(long data) {
    return new byte[] {
        (byte)((data >> 56) & 0xff),
        (byte)((data >> 48) & 0xff),
        (byte)((data >> 40) & 0xff),
        (byte)((data >> 32) & 0xff),
        (byte)((data >> 24) & 0xff),
        (byte)((data >> 16) & 0xff),
        (byte)((data >> 8) & 0xff),
        (byte)((data >> 0) & 0xff),
    };
}

/**
 * Converts a an array of bytes to long value.
 * @param data The target variable.
 * @return Long value conversion of data.
 * @see http://www.daniweb.com/code/snippet216874.html
 */
public static long toLong(byte[] data) {
    if (data == null || data.length != 8) return 0x0;
    return (long)(
        // (Below) convert to longs before shift because digits
        // are lost with ints beyond the 32-bit limit
        (long)(0xff & data[0]) << 56 |
        (long)(0xff & data[1]) << 48 |
        (long)(0xff & data[2]) << 40 |
        (long)(0xff & data[3]) << 32 |
        (long)(0xff & data[4]) << 24 |
        (long)(0xff & data[5]) << 16 |
        (long)(0xff & data[6]) << 8  |
        (long)(0xff & data[7]) << 0
    );
}

public static byte[] nextNoise(){
    byte[] result=new byte[100];
    // copy a frame's worth of data (or remaining data if it is less than frame length)
    int read=Math.min(err_data.length-err_pstn, 100);
    System.arraycopy(err_data, err_pstn, result, 0, read);
    // if read data is less than frame length, reset position and add remaining data
    if(read<100){
        err_pstn=100-read;
        System.arraycopy(err_data, 0, result, read, err_pstn);
    }else // otherwise, increase position
        err_pstn+=100;
    // return noise segment
    return result;
}

/**
 * Given some original data, it is purposefully corrupted according to a
 * second data array (which is read from a file). In pseudocode:
 * corrupt = original xor corruptor
 * @param data The original data.
 * @return The new (corrupted) data.
 */
public static byte[] corruptData(byte[] data){
    // get the next noise sequence
    byte[] noise = nextNoise();
    // finally, xor data with noise and return result
    for(int i=0; i<100; i++)data[i]^=noise[i];
    return data;
}

/**
 * Given an array of data, a packet is created. In pseudocode:
 * frame = corrupt(data) + crc(data)
 * @param data The original frame data.
 * @return The resulting frame data.
 */
public static byte[] buildFrame(byte[] data){
    // pack = [data]+crc32([data])
    byte[] hash = new byte[8];
    // calculate crc32 of data and copy it to byte array
    CRC32 crc = new CRC32();
    crc.update(data);
    hash=toByta(crc.getValue());
    // create a byte array holding the final packet
    byte[] pack = new byte[data.length+hash.length];
    // create the corrupted data
    byte[] crpt = new byte[data.length];
    crpt = corruptData(data);
    // copy corrupted data into pack
    System.arraycopy(crpt, 0, pack, 0, crpt.length);
    // copy hash into pack
    System.arraycopy(hash, 0, pack, data.length, hash.length);
    // return pack
    return pack;
}

/**
 * Verifies frame contents.
 * @param frame The frame data (data+crc32).
 * @return True if frame is valid, false otherwise.
 */
public static boolean verifyFrame(byte[] frame){
    // allocate hash and data variables
    byte[] hash=new byte[8];
    byte[] data=new byte[frame.length-hash.length];
    // read frame into hash and data variables
    System.arraycopy(frame, frame.length-hash.length, hash, 0, hash.length);
    System.arraycopy(frame, 0, data, 0, frame.length-hash.length);
    // get crc32 of data
    CRC32 crc = new CRC32();
    crc.update(data);
    // compare crc32 of data with crc32 of frame
    return crc.getValue()==toLong(hash);
}

/**
 * Transfers a file through a channel in frames and reconstructs it into a new file.
 * @param jpg_file File name of target file to transfer.
 * @param err_file The channel noise file used to simulate corruption.
 * @param out_file The name of the newly-created file.
 * @throws IOException
 */
public static void transferFile(String jpg_file, String err_file, String out_file) throws IOException {
    // read file data into global variables
    jpg_data = readFileArray(new File(jpg_file));
    err_data = readFileArray(new File(err_file));
    err_pstn = 0;
    // variable that will hold the final (transfered) data
    byte[] out_data = new byte[jpg_data.length];
    // holds the current frame data
    byte[] frame_orig = new byte[100];
    byte[] frame_sent = new byte[100];
    // send file in chunks (frames) of 100 bytes
    for(int i=0; i<Math.ceil(jpg_data.length/100); i++){
        // copy jpg data into frame and init first-time switch
        System.arraycopy(jpg_data, i*100, frame_orig, 0, 100);
        boolean not_first=false;
        System.out.print("Packet #"+i+": ");
        // repeat getting same frame until frame crc matches with frame content
        do {
            if(not_first)System.out.print("F");
            frame_sent=buildFrame(frame_orig);
            not_first=true;
        }while(!verifyFrame(frame_sent));   // usually, you'd constrain this by time to prevent infinite loops (in
                                            // case the channel is so wacked up it doesn't get a single packet right)
        // copy frame to image file
        System.out.println("S");
        System.arraycopy(frame_sent, 0, out_data, i*100, 100);
    }
    System.out.println("\nDone.");
    writeFileArray(new File(out_file),out_data);
}

// global variables for file data and pointer
public static byte[] jpg_data;
public static byte[] err_data;
public static int    err_pstn=0;

public static void main(String[] args) throws IOException {

    // list of jpg files
    String[] jpg_file={
        "C:\\Users\\Stefan\\Desktop\\Data\\Images\\photo1.jpg",
        "C:\\Users\\Stefan\\Desktop\\Data\\Images\\photo2.jpg",
        "C:\\Users\\Stefan\\Desktop\\Data\\Images\\photo3.jpg",
        "C:\\Users\\Stefan\\Desktop\\Data\\Images\\photo4.jpg"
    };

    // list of error patterns
    String[] err_file={
        "C:\\Users\\Stefan\\Desktop\\Data\\Error Pattern\\Error Pattern 1.DAT",
        "C:\\Users\\Stefan\\Desktop\\Data\\Error Pattern\\Error Pattern 2.DAT",
        "C:\\Users\\Stefan\\Desktop\\Data\\Error Pattern\\Error Pattern 3.DAT",
        "C:\\Users\\Stefan\\Desktop\\Data\\Error Pattern\\Error Pattern 4.DAT"
    };
    // loop through all jpg/channel combinations and run tests
    for(int x=0; x<jpg_file.length; x++){
        for(int y=0; y<err_file.length; y++){
            System.out.println("Transfering photo"+(x+1)+".jpg using Pattern "+(y+1)+"...");
            transferFile(jpg_file[x],err_file[y],jpg_file[x].replace("photo","CH#"+y+"_photo"));
        }
    }

}

}

1 个答案:

答案 0 :(得分:1)

学习如何调试可能是最重要的开发课程之一,因此,我最终会按照这些步骤来描述如何处理它。

  1. 为您的计划进行单元测试。
  2. 你有100字节的硬编码 块。做那个变量,所以你的 单元测试可以改变值 最初可能是5或10。
  3. 你的第一个考验是采取已知的5 字节块。
  4. 它会被破坏,验证 腐败是预期的。 如果没有,请修复它。
  5. 然后测试传输,验证 传播的是什么 接收。
  6. 然后测试固定。
  7. 然后用更大的尺寸做 大概20,然后做100,然后是 图像。
  8. 硬编码的大小是不好的做法。编写没有单元测试的代码是不好的,因为您可能会(然后)编写不可测试的代码,因此更难调试。

    这将使您能够根据自己的期望找到哪些功能不起作用,并且您可以确定发生了什么,您可能需要重构代码并将功能分解为更小的单元。