Проблема передачи изображения Java - PullRequest
1 голос
/ 18 января 2011

У меня есть школьное задание, чтобы отправить изображение jpg, разбить его на группы по 100 байт, испортить его, использовать проверку CRC, чтобы найти ошибки и повторно передать, пока в конечном итоге оно не будет возвращено в исходную форму. 1001 *

Он практически готов, однако, когда я проверяю новые изображения, они появляются с ошибками.

Буду очень признателен, если кто-нибудь посмотрит на мой код ниже и, возможно, обнаружит эту логическую ошибку, поскольку я не могу понять, в чем проблема, потому что все выглядит хорошо: 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 Ответ

1 голос
/ 18 января 2011

Обучение отладке, вероятно, является одним из наиболее важных уроков для разработки, поэтому, как я в итоге выполню эти шаги, я опишу, как вы можете подойти к нему.

  1. Проведите модульный тест для вашей программы.
  2. Вы жестко запрограммированы на 100 байт. ломти. Сделайте эту переменную, чтобы ваш модульный тест может изменить значение, чтобы сначала 5 или 10.
  3. Ваш первый тест - пройти известный 5 байт чанк.
  4. Он будет поврежден, убедитесь, что коррупция - это то, что ожидалось. Если нет, исправьте это.
  5. Затем проверьте передачу, убедитесь, что что было передано то, что было получил.
  6. Затем проверьте исправление.
  7. Тогда сделай это с большим размером, возможно 20, затем сделать 100, затем изображение.

Наличие жестко запрограммированного размера - плохая практика. Писать код без модульных тестов плохо, так как вы можете (будете) писать код, который не тестируется, поэтому его сложнее отлаживать.

Это позволит вам определить, какие функции не работают в соответствии с вашими ожиданиями, и вы можете определить, что происходит, вам может потребоваться реорганизовать код и разбить функции на более мелкие блоки.

...