Как вытащить данные из данных сетевого пакета в Java

Hanshenrik,
я также использовал CURLOPT_VERBOSE, как вы сказали. Вот 2 журнала локонов. Единственное отличие заключается в том, что строка < * остановила поток пауз!> В журнале скручивания Ubuntu.


В журнале CURL от ведьмы Ubuntu есть проблема:

*   Trying 192.168.1.205...
* TCP_NODELAY set
* Connected to 192.168.1.205 (192.168.1.205) port 8084 (#0)
> POST /datasnap/rest/TServerMethods/%22W_GetDashboard%22/ HTTP/1.1
Host: 192.168.1.205:8084
Accept-Encoding: gzip,deflate
Accept: application/json
Content-Type: text/xml; charset=utf-8
Pragma: dssession=146326.909376.656191
Content-Length: 15
* upload completely sent off: 15 out of 15 bytes

< HTTP/1.1 200 OK
< Connection: close
< Content-Encoding: deflate
< Content-Type: application/json
< Content-Length: 348
< Date: Thu, 17 Jan 2019 15:27:03 GMT
< Pragma: dssession=146326.909376.656191,dssessionexpires=3600000
< 
* stopped the pause stream!
* Closing connection 0

В журнале CURL от ведьмы Centos нет проблемы:

* About to connect() to 192.168.1.205 port 8084 (#1)
*   Trying 192.168.1.205...
* Connected to 192.168.1.205 (192.168.1.205) port 8084 (#1)
> POST /datasnap/rest/TServerMethods/%22W_GetDashboard%22/ HTTP/1.1
Host: 192.168.1.205:8084
Accept-Encoding: gzip,deflate
Accept: application/json
Content-Type: text/xml; charset=utf-8
Pragma: dssession=3812.553164.889594
Content-Length: 15

* upload completely sent off: 15 out of 15 bytes
< HTTP/1.1 200 OK
< Connection: close
< Content-Encoding: deflate
< Content-Type: application/json
< Content-Length: 348
< Date: Thu, 17 Jan 2019 15:43:39 GMT
< Pragma: dssession=3812.553164.889594,dssessionexpires=3600000
< 
* Closing connection 1
5
задан christopher 12 January 2009 в 21:01
поделиться

6 ответов

Я записал что-то для упрощения этого вида работы. Как большинство задач, было намного легче записать инструмент, чем попытаться сделать все вручную.

Это состояло из двух классов, Вот пример того, как это использовалось:

    // Resulting byte array is 9 bytes long.
    byte[] ba = new ByteArrayBuilder()

     .writeInt(0xaaaa5555) // 4 bytes
     .writeByte(0x55) //      1 byte
     .writeShort(0x5A5A) //   2 bytes
     .write( (new BitBuilder())  //     2 bytes---0xBA12                
            .write(3, 5) //     101      (3 bits value of 5)
            .write(2, 3) //        11    (2 bits value of 3)
            .write(3, 2) //          010 (...)
            .write(2, 0) //     00
            .write(2, 1) //       01
            .write(4, 2) //         0002
        ).getBytes();

Я записал ByteArrayBuilder для простого накопления битов. Я использовал метод, объединяющий шаблон в цепочку (Просто возвращающий "это" из всех методов), чтобы помочь записать набор операторов вместе.

Все методы в ByteArrayBuilder были тривиальны, точно так же, как 1 или 2 строки кода (я просто записал все в поток вывода данных),

Это должно создать пакет, но разрывание того не должно быть немного тяжелее.

Единственный интересный метод в BitBuilder - этот:

public BitBuilder write(int bitCount, int value) {
    int bitMask=0xffffffff;  
    bitMask <<= bitCount;   // If bitcount is 4, bitmask is now ffffff00
    bitMask = ~bitMask;     // and now it's 000000ff, a great mask

    bitRegister <<= bitCount; // make room
    bitRegister |= (value & bitMask); // or in the value (masked for safety)
    bitsWritten += bitCount;
    return this;
}

Снова, логика могла быть инвертирована очень легко для чтения пакета вместо сборки один.

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

1
ответ дан 14 December 2019 в 09:02
поделиться

Я не полагаю, что эта техника может быть сделана в Java, за исключением использования JNI и на самом деле записи обработчика протокола в C. Другой способ сделать техника, которую Вы описываете, является различными записями и объединениями, которые Java не имеет также.

Если Вы имели контроль над протоколом (это - Ваш сервер и клиент), Вы могли использовать сериализованные объекты (inc. xml), для получения автоволшебства (но не так эффективное время выполнения) парсинг данных, но это об этом.

Иначе Вы застреваете с парсингом Потоков или массивов байтов (который можно рассматривать как Потоки).

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

2
ответ дан 14 December 2019 в 09:02
поделиться

Считайте свой пакет в массив байтов и затем извлеките биты и байты, которые Вы хотите от этого.

Вот образец без обработки исключений:

DatagramSocket s = new DatagramSocket(port);
DatagramPacket p;
byte buffer[] = new byte[4096];

while (true) {
    p = new DatagramPacket(buffer, buffer.length);
    s.receive(p);

    // your packet is now in buffer[];
    int version = buffer[0] << 24 + buffer[1] << 16 + buffer[2] < 8 + buffer[3];
    byte[] serverId = new byte[20];
    System.arraycopy(buffer, 4, serverId, 0, 20);

     // and process the rest
}

В практике Вы, вероятно, закончите с функциями помощника для извлечения полей данных в сетевом порядке от массива байтов, или как Tom указывает в комментариях, можно использовать a ByteArrayInputStream(), из которого можно создать a DataInputStream() который имеет методы для чтения структурированных данных из потока:

...

while (true) {
    p = new DatagramPacket(buffer, buffer.length);
    s.receive(p);

    ByteArrayInputStream bais = new ByteArrayInputStream(buffer);
    DataInput di = new DataInputStream(bais);

    int version = di.readInt();
    byte[] serverId = new byte[20];
    di.readFully(serverId);
    ...
}
3
ответ дан 14 December 2019 в 09:02
поделиться

Посмотрите на библиотеку Javolution и ее классы структуры, они сделают именно то, что вы просите. Фактически, у автора есть именно этот пример, использующий классы Javolution Struct для манипулирования пакетами UDP.

1
ответ дан 14 December 2019 в 09:02
поделиться

Это - альтернативное предложение по ответу, который я оставил выше. Я предлагаю, чтобы Вы рассмотрели реализацию его, потому что это действовало бы в значительной степени то же как решение C, где Вы могли выбрать поля из пакета по имени.

Вы могли бы начать его с внешним текстом, регистрируют что-то вроде этого:

OneByte,       1
OneBit,       .1
TenBits,      .10
AlsoTenBits,  1.2
SignedInt,    +4  

Это могло указать всю структуру пакета, включая поля, которые могут повториться. Язык мог быть столь простым или сложным, как Вам нужно-

Вы создали бы объект как это:

new PacketReader packetReader("PacketStructure.txt", byte[] packet);

Ваш конструктор выполнил бы итерации по файлу PacketStructure.txt и сохранил бы каждую строку как ключ хеш-таблицы и точное местоположение, он - данные (и разрядное смещение и размер) как данные.

После того как Вы создали объект, передающий в bitStructure и пакете, Вы могли случайным образом получить доступ к данным с операторами, столь же простыми как:

int x=packetReader.getInt("AlsoTenBits");

Также отметьте, этот материал был бы намного менее эффективным, чем структура C, но не так, как Вы могли бы думать - это все еще, вероятно, много раз более эффективно, чем Вам будет нужно. При правильной организации файл спецификации был бы только проанализирован однажды, таким образом, Вы только получите незначительный удар единственного поиска хеша и нескольких бинарных операций для каждого значения, Вы читаете из пакета - не плохо вообще.

Исключение - то, если Вы анализируете пакеты от высокоскоростного непрерывного потока, и даже затем я сомневаюсь, что быстрая сеть могла лавинно разослать даже достаточно медленный ЦП.

0
ответ дан 14 December 2019 в 09:02
поделиться

Короткий ответ, нет Вы не можете сделать этого настолько легко.

Более длинный ответ, если можно использовать Serializable объекты, можно сцепить Ваш InputStream до ObjectInputStream и используйте это для десериализации объектов. Однако это требует, чтобы Вы имели некоторый контроль над протоколом. Это также работает легче при использовании TCP Socket. Если Вы используете UDP DatagramSocket, необходимо будет получить данные из пакета и затем подать это в a ByteArrayInputStream.

Если Вы не управляете протоколом, Вы можете все еще использовать вышеупомянутый метод десериализации, но Вы, вероятно, оказываетесь перед необходимостью реализовывать readObject() и writeObject() методы вместо того, чтобы использовать реализацию по умолчанию, данную Вам. Если необходимо использовать чужой протокол (скажите, потому что Вам нужно к interop с собственной программой), это вероятно самое легкое решение, которое Вы собираетесь найти.

Кроме того, помните, что Java использует UTF-16 внутренне для строк, но я не уверен, что он сериализирует их тот путь. Так или иначе необходимо быть очень осторожными при передаче строк назад и вперед программам не-Java.

0
ответ дан 14 December 2019 в 09:02
поделиться
Другие вопросы по тегам:

Похожие вопросы: