#java #замена #tcp
В общем, есть два устройства.
Одно отсылает пакеты, а другое, соответственно, их принимает, изменяет и дальше отправляет
в сеть.
И тут еще суть в том, что нужно оставить заголовки пакета, окончание, а содержимое
заменить на другое.
То есть что получается: мне нужно поднять сервер, получить пакет, убрать из него
содержимое и вставить своё. Отправить пакет дальше. Даже схемка есть:
Вот - N - это количество "D".
Не понимаю, с чего начинать, т.к. с этим сталкиваюсь в первый раз. И хотелось бы
понять, что нарисовано на картинке.
Ответы
Ответ 1
Тут вроде ничего сложного. На картинке показана структура 2-х пакетов:
Сообщение, которое к вам приходит.
Сообщение, которое вы должны отослать.
По каждому сообщению подробно расписана структура следования байтов (Б1, Б2 и т.д.),
также показано, какую часть и куда нужно переносить. Тело исходного сообщения состоит
из массива данных структуры "D", каждый элемент по 6 байт.
Но я сейчас какие-то прописные истины перечислил)), которые вы и сами, наверное, поняли)
Но вот что мне не понятно по этому рисунку:
Во-первых, "Измерительное сообщение 98 байт максимум" - следовательно, пакет нефиксированной
длины, а как мы узнаем об окончании пакета? + не хватает 10 байт в описании, максимум
98, а на картинке расписано только 88 байт. Может, еще есть какая-нибудь информация?
Во-вторых, тело исходного сообщения на картинке 84 байта, а уместить его нужно в
103 байта, с ним производятся какие-то манипуляции? Или нужно добивать нулями до определенной
длинны?
===============================================
Все еще остаются вопросы) вот смотрите примерный алгоритм
На вашем сервере(на рис - прибор 2), считываем поток байт, для начала берем первый
байт и сверяем заголовок, судя по рисунку заголовок всегда 23 если да то продолжаем
читать, если нет то нужно больше информации о других пакетах и дальнейших действиях
Теперь когда мы поняли что за пакет, нам нужно узнать остальные данные, для этого
нужно понять длинну пакета, и тут опять непонятно как ее вычислить она всегда фиксирована
и равна = 113 байт ( тогда вам нужно считать еще 110 байт + crc(2 байта) ), или "N"
- это количество D, как говорил @avp, тогда вам нужно считать еще один байт, будем
считать что это count, тогда формула будет такая count * 6 + crc( 2 байта )
Когда вы получили тело сообщения, нужно сверить crc ( последние 2 байта), но тут
не написано для какой части сообщения его сверять?
Если crc совпал то теперь можно формировать новый пакет, но как его формировать тоже
не совсем понятно
Ответ 2
Короче, вот что я сумел настрогать:
Вот прибор 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. Что делать?
Вообще правильно?