java - 校验和计算正确一次,然后在 Java 中使用 CRC32 后就不正确

标签 java sockets networking checksum crc32

我在使用 Java 中的 CRC32 库计算的校验和时遇到问题。

所以客户端像这样计算校验和......

/**
 * Increments current packet message number, selects a
 * random destination, and sends the packet.
 * @param connection
 * @throws InterruptedException
 * @throws IOException
 */
private void generateAndSendPackets(Socket connection) throws InterruptedException, IOException
{
    byte packet[] = new byte[5];
    for (byte messageNumber = 0; messageNumber <= 20; messageNumber++)
    {
        packet[0] = CLIENT_ID; //SOURCE
        packet[1] = randomDestination(); //DESTINATION
        packet[3] = messageNumber; //DATA
        packet[4] = messageNumber;
        //Need more data?
        packet[2] = computeCheckSum(packet); //COMPUTE CHECKSUM
        send(packet); //SEND PACKET
        Thread.sleep(4000); //WAIT TO SEND NEXT PACKET
    }
    closeConnection(connection); //Closes the connection
}

/**
 * Given a packet, it computes the checksum for
 * the packet with internal Checksum library
 * @param packet
 * @return
 */
private byte computeCheckSum(byte[] packet)
{
    Checksum checkSum = new CRC32();
    checkSum.update(packet, 0, packet.length);
    return (byte)checkSum.getValue();
}

然后发送数据包。包括校验和。

然后路由器像这样计算校验和......

    /**
     * Given a packet, it computes the checksum for
     * the packet with internal Checksum library
     * @param p
     * @return
     */
    private boolean checkCheckSum(byte[] p)
    {
        byte[] packet = p;
        byte[] tempPacket = new byte[5];
        tempPacket[0] = packet[0];
        tempPacket[1] = packet[1];
        tempPacket[3] = packet[3];
        tempPacket[4] = packet[4];
        Checksum checkSum = new CRC32();
        checkSum.update(tempPacket, 0, tempPacket.length);
        byte cc = (byte)checkSum.getValue();
        System.out.println(packet[0] + " " + packet[1] + " " + packet[2] + " " + packet[3] + " " + packet[4]);
        tempPacket[2] = (byte)checkSum.getValue();
        System.out.println(tempPacket[0] + " " + tempPacket[1] + " " + tempPacket[2] + " " + tempPacket[3] + " " + tempPacket[4]);
        if((byte)checkSum.getValue() == packet[2]){
            System.out.println(packet[2] + "," + cc);
            return true;
        }else{
            System.out.println(packet[2] + "," + cc);
            return false;
        }
    }

所以当它计算和输出时,它第一次就正确了......但之后它就失败了......

Waiting for connection....
Connection recieved from /127.0.0.1 on port 9000
Waiting for packet...
Packet recieved: 11 44 -118 00
11 44 -118 0 0
11 44 -118 0 0
-118,-118
<Error here because we weren't done another part yet>
Waiting for packet...
Packet recieved: 11 33 -42 11
11 33 -42 1 1
11 33 -128 1 1
-42,-128
Checksum invalid!!!!
Waiting for packet...

那么之后的每一个都是无效的......

所以它一次正确地获取了校验和,然后在再次获取校验和时搞砸了。我认为这是我对 Java 中的 CRC32 库做错的事情。这些也是他们自己的线程,但我认为这不会成为问题。

下面是我们的代码,我试图突出显示上面的问题部分,因为有些部分已经完成了一半......

客户端.java

package runner;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.*;
import java.util.zip.CRC32;
import java.util.zip.Checksum;

/**
 * Client side for our client
 * server project. Sends a request
 * with a string to reverse.
 * @author xxxxx
 *
 */
public class Client
{
    private static final int PORT = 9000;

    private static final String HOST = "localhost";

    private static final byte CLIENT_ID = (byte)11;

    private Random rand;

    //For reciving packets
    private ServerSocket clientRecieverSocket = null;

    //Output to server
    private PrintWriter out;

    //Input from server
    private Scanner conIn;

    //Input from user
    private Scanner in;

    //Data Output Stream
    private DataOutputStream dos;

    /**
     * Creates a new instance of the client
     * @param args
     * @throws UnknownHostException
     * @throws IOException
     * @throws InterruptedException
     */
    public static void main(String[] args) throws IOException, InterruptedException
    {
        Client c = new Client();
        c.run();
    }

    /**
     * Runs the client
     *
     * @throws UnknownHostException
     * @throws IOException
     * @throws InterruptedException
     */
    private void run() throws IOException, InterruptedException
    {
        String msg; //Recieve messages from server

        //Opens connection
        Socket connection = openConnection();

        //Gets I/O streams from server
        System.out.println("Getting output stream...");
        out = new PrintWriter(connection.getOutputStream());
        System.out.println("Getting input stream...");
        conIn = new Scanner(connection.getInputStream());
        System.out.println();
        dos = new DataOutputStream(connection.getOutputStream());
        msg = conIn.nextLine();
        System.out.println(msg);
        in = new Scanner(System.in);

        generateAndSendPackets(connection);
    }

    /**
     * Increments current packet message number, selects a
     * random destination, and sends the packet.
     * @param connection
     * @throws InterruptedException
     * @throws IOException
     */
    private void generateAndSendPackets(Socket connection) throws InterruptedException, IOException
    {
        byte packet[] = new byte[5];
        for (byte messageNumber = 0; messageNumber <= 20; messageNumber++)
        {
            packet[0] = CLIENT_ID; //SOURCE
            packet[1] = randomDestination(); //DESTINATION
            packet[3] = messageNumber; //DATA
            packet[4] = messageNumber;
            //Need more data?
            packet[2] = computeCheckSum(packet); //COMPUTE CHECKSUM
            send(packet); //SEND PACKET
            Thread.sleep(4000); //WAIT TO SEND NEXT PACKET
        }
        closeConnection(connection); //Closes the connection
    }


    /**
     * Given a packet, it computes the checksum for
     * the packet with internal Checksum library
     * @param packet
     * @return
     */
    private byte computeCheckSum(byte[] packet)
    {
        Checksum checkSum = new CRC32();
        checkSum.update(packet, 0, packet.length);
        return (byte)checkSum.getValue();
    }

    /**
     * Select random destination
     * to send to.
     */
    private byte randomDestination()
    {
        List<Byte> destinations = Arrays.asList((byte)22,(byte)33,(byte)44);
        //destinations.remove(CLIENT_ID); //Do not send it to itself...
        rand = new Random();
        return destinations.get(rand.nextInt(destinations.size())); //converts string to byte
    }

    /**
     * Open the connection
     * @return
     * @throws UnknownHostException
     * @throws IOException
     */
    private Socket openConnection() throws IOException
    {
        System.out.println("Connecting to server...");
        Socket connection = new Socket(HOST, PORT); //Connects to server
        System.out.println("Connection made!");
        return connection;
    }

    /**
     * Closes the connection
     * @param connection
     * @throws IOException
     */
    private void closeConnection(Socket connection) throws IOException
    {
        System.out.println("Closing connection...");
        connection.close();
    }

    /**
     * Sends a message to the server
     * with the string to reverse.
     * @param packet
     */
    private void send(byte[] packet) throws IOException
    {
        System.out.println("You sent " + packet + ", sending message...");
        System.out.println(packet[0] + " " + packet[1] + " " + packet[2] + " " + packet[3] + " " + packet[4]);
        dos.write(packet, 0, packet.length);
        dos.flush();
    }
}

路由器.java

import javax.xml.crypto.Data;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Hashtable;
import java.util.Scanner;
import java.util.zip.CRC32;
import java.util.zip.Checksum;

/**
 * Router class routes messages
 * around to different routers/clients
 *
 * @Author Abe and Carson
 */
public class Router{
    //Stores routing table
    private Hashtable<Byte, String> routingTable;

    //Stores socket
    private static ServerSocket SERVER;

    private static Socket CLIENT;

    //Stores router ID (CHANGE THIS IS HARDCODED!!!!!!)
    private static final int ROUTER_ID = 1;

    public static void main(String args[]) throws IOException
    {
        Router r = new Router();
        System.out.println("Waiting for connection....");
        while(true)
        {
            Socket incomingConnection = SERVER.accept();
            System.out.println("Connection recieved from "
                    + incomingConnection.getInetAddress()
                    + " on port "
                    + incomingConnection.getLocalPort());
            RouterHandlerThread rht = new RouterHandlerThread(incomingConnection, r);
            rht.start();
        }
    }

    /**
     * Creates a router object
     * with a server socket that opens to listen for packets
     * and a routing table
     */
    public Router()
    {
        //Creates routing tables HashTable<Byte, String> for router to use based on its ID
        RoutingTableFactory rtf = new RoutingTableFactory();
        try{
            routingTable = rtf.getRoutingTable(ROUTER_ID);
        } catch(RoutingTableFactory.InvalidRouterIDException e){
            e.printStackTrace();
        }
        try {
            SERVER = new ServerSocket(9000);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * Getter for the routers
     * Routing Table
     * @return
     */
    public Hashtable<Byte, String> getRoutingTable()
    {
        return this.routingTable;
    }

    /**
     * Thread for handling router processes for
     * forwarding a packet to a different link.
     */
    private static class RouterHandlerThread extends Thread
    {
        private Socket connection;
        private Router router;
        private Scanner in;
        private PrintWriter out;
        //Used for sending the packet byte[], can't use Scanner for byte[] :(
        private DataInputStream dis;
        RouterHandlerThread(Socket c, Router r) throws IOException
        {
            this.router = r;
            this.connection = c;
            in = new Scanner(c.getInputStream());
            out = new PrintWriter(c.getOutputStream());
            dis = new DataInputStream(c.getInputStream());
        }

        /**
         * Given a packet, it computes the checksum for
         * the packet with internal Checksum library
         * @param p
         * @return
         */
        private boolean checkCheckSum(byte[] p)
        {
            byte[] packet = p;
            byte[] tempPacket = new byte[5];
            tempPacket[0] = packet[0];
            tempPacket[1] = packet[1];
            tempPacket[3] = packet[3];
            tempPacket[4] = packet[4];
            Checksum checkSum = new CRC32();
            checkSum.update(tempPacket, 0, tempPacket.length);
            byte cc = (byte)checkSum.getValue();
            System.out.println(packet[0] + " " + packet[1] + " " + packet[2] + " " + packet[3] + " " + packet[4]);
            tempPacket[2] = (byte)checkSum.getValue();
            System.out.println(tempPacket[0] + " " + tempPacket[1] + " " + tempPacket[2] + " " + tempPacket[3] + " " + tempPacket[4]);
            if((byte)checkSum.getValue() == packet[2]){
                System.out.println(packet[2] + "," + cc);
                return true;
            }else{
                System.out.println(packet[2] + "," + cc);
                return false;
            }
        }

        public void run()
        {
            out.println("R: Connected to router " + ROUTER_ID + " at " + SERVER.getLocalPort());
            out.flush();
            while(connection.isConnected())
            {
                byte[] packet = new byte[5];
                System.out.println("Waiting for packet...");
                //Reads packet byte[] from the client, stores in packet.
                try{
                    dis.readFully(packet);
                }catch(Exception e){
                    e.printStackTrace();
                }
                //Print out each byte of packet.
                System.out.println("Packet recieved: " + packet[0] + " " + packet[1] + " " + packet[2] + " " + packet[3] + packet[4]);
                //Get routing table, look up what link to send packet to.
                Hashtable<Byte, String> routingTable = router.getRoutingTable();
                if(checkCheckSum(packet)){
                    String destination = routingTable.get(packet[1]);

                    try {
                        Socket targetRouter = new Socket(destination, 9000);
                        DataOutputStream dos = new DataOutputStream(targetRouter.getOutputStream());
                        dos.write(packet);
                        dos.flush();
                        System.out.println("Forwarding to " + destination);
                        targetRouter.close();
                        dos.close();
                    } catch (UnknownHostException e) {
                        e.printStackTrace();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }else{
                    System.out.println("Checksum invalid!!!!");
                }
            }
        }
    }
}

/**********
 * CODE FIDDLING WITH STRINGS -> BYTES AND VICE VERSA
 public static void main(String[] args)
 {
 byte packet[] = new byte[4];
 packet[0] = 'D';
 packet[1] = 'B';
 packet[3] = 29;

 Checksum checkSum = new CRC32();
 checkSum.update(packet, 0, packet.length);
 packet[2] = (byte)checkSum.getValue();

 System.out.println(packet[0] + " " + packet[1] + " " + packet[2] + " " + packet[3]);
 String str = new String(packet);
 System.out.println(str);
 }
 */

最佳答案

计算校验和时,packet[2] 必须设置为零。在代码的某些部分,即在函数 generateAndSendPackets 中,您重复使用相同的 byte[] 来发送多个数据包,但您将前一个校验和字节保留在 packet[2],导致新的校验和值不正确。

    byte packet[] = new byte[5];
    for (byte messageNumber = 0; messageNumber <= 20; messageNumber++)
    {
        packet[0] = CLIENT_ID; //SOURCE
        packet[1] = randomDestination(); //DESTINATION
        packet[3] = messageNumber; //DATA
        packet[4] = messageNumber;
        //Need more data?

        // ********************
        packet[2] = (byte) 0; // <<<<<< You have to set it to zero
        // ********************

        packet[2] = computeCheckSum(packet); //COMPUTE CHECKSUM
        send(packet); //SEND PACKET
        Thread.sleep(4000); //WAIT TO SEND NEXT PACKET
    }

关于java - 校验和计算正确一次,然后在 Java 中使用 CRC32 后就不正确,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43216683/

相关文章:

java - 如何列出不被继承的方法?

java - 哪个系统组件负责在 Java 应用程序中绑定(bind) Unicode 连字?

java - 如何解析Netty(java)中的各种对象?

java - Java接收UDP数据

iphone - 从 iOS 代码 Ping IP 地址

java - 使用antlr4的二义性语法

java - 在 GWT 文本框中捕获粘贴的文本

java - Java中如何查找IP地址建立的TCP连接数?

c - 如何比较C中的套接字地址?

Android:寻找一种方法来加速通过 wifi 从 Android 到 PC 的图像传输