Проблема с преобразованием байтово закодированных данных обратно в int32 после передачи UDP - PullRequest
0 голосов
/ 25 мая 2019

Я собираю дейтаграммы для связи UDP с подзаголовком, который я использую, чтобы указать тип отправляемых данных. Клиент работает на C #, сервер работает на Java, а подзаголовок представляет собой один Int32, то есть 4 байта данных.

Данные успешно поступают на сервер, и данные подзаголовка + интерпретируются правильно, но когда я отправляю ответ обратно клиенту, использование BitConverter.ToInt32 (подзаголовок, 0) приводит к 8-значному числу, которое не отображается к любому из моих ожидаемых целых чисел. Однако отправленные данные корректно отображаются при пропуске подзаголовка, что заставляет меня думать, что проблема связана только с процессом кодирования / декодирования подзаголовка.

У меня есть методы на обоих концах, которые могут вычистить подзаголовок из байтового массива, и которые пытаются сопоставить вычищенный подзаголовок с MsgType. Как я уже упоминал, на сервере все работает, как и ожидалось, поэтому я подозреваю, что проблема заключается в кодировании на сервере или в декодировании обратно на клиенте.

Я также пытался использовать MemoryStream и BinaryReader для преобразования в Int32, но с теми же результатами.

C # Клиент:

        const SUBHEADER_SIZE = 4; // 4 bytes to an Int32

        private void ReceiveUdp(IAsyncResult packet)
        {
            IPEndPoint remote = (IPEndPoint)Udp.Client.RemoteEndPoint;
            byte[] received = Udp.EndReceive(packet, ref remote);
            MsgType type = GetMsgType(received);
            string msg;

            switch (type)
            {
                case MsgType.POS:
                case MsgType.STATE:
                case MsgType.STATUS:
                    msg = Encoding.ASCII.GetString(ScrubSubheader(received));
                    if (msg.Equals("0"))
                        Disconnect();
                    break;
                case MsgType.MSG:   // Default to MSG
                default:
                    msg = Encoding.ASCII.GetString(ScrubSubheader(received));
                    LocalConsole.Instance.Log("Received [" + type + "] " + msg + " from " + remote.Address + " on port " + remote.Port);
                    break;
            }
        }

        public static byte[] ScrubSubheader(byte[] arr)
        {
            byte[] scrubbed = new byte[arr.Length - SUBHEADER_SIZE];
            for (int i = 0; i < scrubbed.Length; i++)
                scrubbed[i] = arr[i + SUBHEADER_SIZE];
            return scrubbed;
        }

        public static MsgType GetMsgType(byte[] arr)
        {
            byte[] subheader = new byte[SUBHEADER_SIZE];

            for (int i = 0; i < SUBHEADER_SIZE; i++)
                subheader[i] = arr[i];

            int iType = BitConverter.ToInt32(subheader, 0);
            MsgType mtType;

            // Also tried: "MemoryStream stream = new MemoryStream(subheader); 
            // int iType = new BinaryReader(stream).ReadInt32();"

            LocalConsole.Instance.Log("iType is " + iType, true);

            switch(iType)
            {
                case (int)MsgType.POS:
                    mtType = MsgType.POS;
                    break;
                case (int)MsgType.STATE:
                    mtType = MsgType.STATE;
                    break;
                case (int)MsgType.STATUS:
                    mtType = MsgType.STATUS;
                    break;
                case (int)MsgType.MSG:  // Default to MSG
                default:
                    mtType = MsgType.MSG;
                    break;
            }

            return mtType;
        }

Java-сервер:

    public void run() {
        try (DatagramSocket udpServSock = new DatagramSocket(_port)) {

            DatagramPacket packet = null;
            byte[] byteArr = new byte[HubrisServer.MAX_PACKET_SIZE];

            while (true) {

                packet = new DatagramPacket(byteArr, byteArr.length);
                udpServSock.receive(packet);

                InetAddress clientAdd = packet.getAddress();
                int clientPort = packet.getPort();

                MsgType type = getMsgType(packet.getData());
                String msg = DataToString(scrubSubheader(packet.getData()), true);

                MsgType sendType = HubrisServer.MsgType.STATUS;

                msg = "0";
                byte[] sendArr = assemblePacket(msg.getBytes(), sendType);

                DatagramPacket sendPack = new DatagramPacket(sendArr, sendArr.length, clientAdd, clientPort);

                Thread.sleep(1000);

                udpServSock.send(sendPack);
            }
        } catch ... {
            ...
        }
    }

    /**
     * Assemble a packet with subheader and data
     * @param arr
     * @param type
     * @return packet
     */
    public static byte[] assemblePacket(byte[] arr, MsgType type) {
        ByteBuffer buff = ByteBuffer.allocate(4);
        buff.putInt(type.getValue());
        byte[] subheader = buff.array();
        byte[] packet = new byte[arr.length + subheader.length];

        for(int i = 0; i < packet.length; i++) {
            if(i >= subheader.length)
                packet[i] = arr[i - subheader.length];
            else
                packet[i] = subheader[i];
        }

        return packet;
    }

    /**
     * Scrub the subheader from a byte array and return the scrubbed array
     * @param arr
     * @return
     */
    public static byte[] scrubSubheader(byte[] arr)
    {
        ... similar to C# implementation
    }

    public static MsgType getMsgType(byte[] arr)
    {
        byte[] subArr = new byte[SUBHEADER_SIZE];

        for (int i = 0; i < SUBHEADER_SIZE; i++)
            subArr[i] = arr[i];

        ByteBuffer buff = ByteBuffer.wrap(subArr);
        int iType = buff.getInt();
        MsgType mtType;

        if(iType == MsgType.POS.getValue())
            mtType = MsgType.POS;
        else if (iType == MsgType.STATE.getValue())
            mtType = MsgType.STATE;
        else if (iType == MsgType.STATUS.getValue())
            mtType = MsgType.STATUS;
        else // Default to MSG
            mtType = MsgType.MSG;

        return mtType;
    }

1 Ответ

0 голосов
/ 25 мая 2019

Благодаря Avo Nappo и VGR было решено, что это проблема с порядком байтов.(Если кто-то из вас отправит ваш комментарий в качестве ответа, я приму его в качестве ответа)

Кажется, что в Java по умолчанию ByteBuffers имеет значение с прямым порядком байтов, поэтому переключите их с помощью ".order (ByteOrder.LITTLE_ENDIAN)"решил проблему.

...