Замена данных в TCP пакете

Рейтинг: 3Ответов: 2Опубликовано: 29.09.2014

В общем, есть два устройства.
Одно отсылает пакеты, а другое, соответственно, их принимает, изменяет и дальше отправляет в сеть.

И тут еще суть в том, что нужно оставить заголовки пакета, окончание, а содержимое заменить на другое.

То есть что получается: мне нужно поднять сервер, получить пакет, убрать из него содержимое и вставить своё. Отправить пакет дальше. Даже схемка есть:

Вот - N - это количество "D".

alt text

Не понимаю, с чего начинать, т.к. с этим сталкиваюсь в первый раз. И хотелось бы понять, что нарисовано на картинке.

Ответы

▲ 3Принят

Тут вроде ничего сложного. На картинке показана структура 2-х пакетов:

  1. Сообщение, которое к вам приходит.
  2. Сообщение, которое вы должны отослать.

По каждому сообщению подробно расписана структура следования байтов (Б1, Б2 и т.д.), также показано, какую часть и куда нужно переносить. Тело исходного сообщения состоит из массива данных структуры "D", каждый элемент по 6 байт.

Но я сейчас какие-то прописные истины перечислил)), которые вы и сами, наверное, поняли)

Но вот что мне не понятно по этому рисунку:

Во-первых, "Измерительное сообщение 98 байт максимум" - следовательно, пакет нефиксированной длины, а как мы узнаем об окончании пакета? + не хватает 10 байт в описании, максимум 98, а на картинке расписано только 88 байт. Может, еще есть какая-нибудь информация?

Во-вторых, тело исходного сообщения на картинке 84 байта, а уместить его нужно в 103 байта, с ним производятся какие-то манипуляции? Или нужно добивать нулями до определенной длинны?

===============================================

Все еще остаются вопросы) вот смотрите примерный алгоритм

  1. На вашем сервере(на рис - прибор 2), считываем поток байт, для начала берем первый байт и сверяем заголовок, судя по рисунку заголовок всегда 23 если да то продолжаем читать, если нет то нужно больше информации о других пакетах и дальнейших действиях

  2. Теперь когда мы поняли что за пакет, нам нужно узнать остальные данные, для этого нужно понять длинну пакета, и тут опять непонятно как ее вычислить она всегда фиксирована и равна = 113 байт ( тогда вам нужно считать еще 110 байт + crc(2 байта) ), или "N" - это количество D, как говорил @avp, тогда вам нужно считать еще один байт, будем считать что это count, тогда формула будет такая count * 6 + crc( 2 байта )

  3. Когда вы получили тело сообщения, нужно сверить crc ( последние 2 байта), но тут не написано для какой части сообщения его сверять?

  4. Если crc совпал то теперь можно формировать новый пакет, но как его формировать тоже не совсем понятно

▲ 1

Короче, вот что я сумел настрогать:

Вот прибор 1:

import java.io.*;
import java.net.*;
import java.util.*;
import java.nio.ByteBuffer;
import java.math.BigInteger;

class TCPClient
{
    public static void main(String argv[]) throws Exception
    {

        Random rand = new Random();
        int[] keys = {20, 1480, 70, 1520, 1470, 60, 0, -16, -15, -14};
        float[] values = {0.000f, 0.000f, 0.000f, 0.000f, 0.006f, 0.000f, 0f, 22.150f, 744.301f,  41.136f};

        byte[] bots = new byte[88];
        byte[] one_byte = new byte[4];

        //one_byte = intToByteArray(023, 1);
        bots[0] = intToByteArray(23, 1)[0];
        bots[1] = intToByteArray(14, 1)[0];

        for(int i=2, key_store = 0; i < 81; i++, key_store++) {
            one_byte = intToByteArray(keys[key_store], 2); // код ЗХВ
            bots[i++] = one_byte[0];
            bots[i++] = one_byte[1];

            one_byte = FloatToByteArray(values[key_store]); // отчет float
            bots[i++] = one_byte[0];
            bots[i++] = one_byte[1];
            bots[i++] = one_byte[2];
            bots[i++] = one_byte[3];
        }

        one_byte = intToByteArray(rand.nextInt(), 2); // код CRC 16

        bots[86] = one_byte[0];
        bots[87] = one_byte[1];

        for(int i=0; i < 88; i++) {
            System.out.print(bots[i] + " ");
        }

        Socket socket = new Socket("localhost", 6789);

        DataOutputStream outToServer = new DataOutputStream(socket.getOutputStream());
        BufferedReader inFromServer = new BufferedReader(new InputStreamReader(socket.getInputStream()));

        outToServer.write(bots);

        int bytesWritten = outToServer.size();
        System.out.println("Total " + bytesWritten + " bytes are written to stream.");

        String modifiedSentence = inFromServer.readLine();
        System.out.println("FROM SERVER: " + modifiedSentence);
        socket.close();  
    }

    public static byte[] FloatToByteArray(float value) {
        int bits = Float.floatToIntBits(value);
        byte[] bytes = new byte[4];
        bytes[0] = (byte)(bits & 0xff);
        bytes[1] = (byte)((bits >> 8) & 0xff);
        bytes[2] = (byte)((bits >> 16) & 0xff);
        bytes[3] = (byte)((bits >> 24) & 0xff);

        return bytes;
    }

    public static byte[] intToByteArray(int value, int length) {
        if(length == 2) {
            byte[] data = new byte[2];
            data[0] = (byte) (value & 0xFF);
            data[1] = (byte) ((value >> 8) & 0xFF);
            return data;
        }
        else {
            BigInteger bigInt = BigInteger.valueOf(value);      
            return bigInt.toByteArray();
        }
    }

    static int crc16(final byte[] buffer) {
        int crc = 0xFFFF;

        for (int j = 0; j < buffer.length ; j++) {
            crc = ((crc  >>> 8) | (crc  << 8) )& 0xffff;
            crc ^= (buffer[j] & 0xff);//byte to int, trunc sign
            crc ^= ((crc & 0xff) >> 4);
            crc ^= (crc << 12) & 0xffff;
            crc ^= ((crc & 0xFF) << 5) & 0xffff;
        }
        crc &= 0xffff;
        return crc;
    }
}

Как я думаю, как оно работает: первые 2 байта - кодирую int в byte и записываю. Дальше идут структуры "D", содержащие по 6 байт, где первые 2 байта ключ, а остальные 4 - значение.

Ну и в конце код CRC.

Но что получается, на устройстве 2 я принимаю запрос так:

Socket connectionSocket = welcomeSocket.accept();
BufferedReader inFromClient = new BufferedReader(new InputStreamReader(connectionSocket.getInputStream()));
DataOutputStream outToClient = new DataOutputStream(connectionSocket.getOutputStream());

while ((i = inFromClient.read()) != -1) {

}

и получаю int значение, когда должно приходить byte, отправлял же в byte. Что делать? Вообще правильно?