Отправка 4-байтового заголовка сообщения от клиента C # на сервер Java - PullRequest
7 голосов
/ 18 сентября 2008

Я пытаюсь написать клиент C # на сервер, который написан на Java. Сервер ожидает 4-байтовый заголовок сообщения (DataInputStread readInt () в Java), за которым следует фактическое сообщение.

Я абсолютно новичок в C #, как я могу отправить этот заголовок сообщения на Java Server? Я пробовал это несколькими способами (в основном методом проб и ошибок, не слишком углубляясь в язык C #), и ничего не получалось. Сторона Java оказалась с неправильной (очень большой) длиной сообщения.

Ответы [ 6 ]

11 голосов
/ 18 сентября 2008

Это, как указывали другие авторы, вплоть до порядка байтов.

Java DataInputStream ожидает, что данные будут big-endian (сетевой порядок байтов). Судя по документации Mono (для эквивалентов, таких как BinaryWriter ), C # стремится к младшему порядку (по умолчанию для Win32 / x86).

Итак, когда вы используете стандартную библиотеку классов для преобразования 32-битного целого числа '1' в байты, они дают разные результаты:

//byte hex values
Java: 00 00 00 01
  C#: 01 00 00 00

Вы можете изменить способ написания целых в C #:

private static void WriteInt(Stream stream, int n) {
    for(int i=3; i>=0; i--)
    {
        int shift = i * 8; //bits to shift
        byte b = (byte) (n >> shift);
        stream.WriteByte(b);
    }
}

EDIT:

Более безопасный способ сделать это будет:

private static void WriteToNetwork(System.IO.BinaryWriter stream, int n) {
    n = System.Net.IPAddress.HostToNetworkOrder(n);
    stream.Write(n);
}
2 голосов
/ 18 сентября 2008

Как все здесь уже отметили, проблема, скорее всего, вызвана тем, что приложение C # отправляет целые числа в порядке с прямым порядком байтов, тогда как приложение Java ожидает их в сетевом порядке (с прямым порядком байтов). Однако вместо явной перестановки байтов в приложении C # правильным способом является использование встроенных функций для преобразования из хоста в сетевой порядок (htons и т.п.) - таким образом, ваш код будет продолжать нормально работать даже при запуске на машине с прямым порядком байтов.

В общем, при устранении таких проблем я считаю полезным записывать правильный трафик (например, с Java на Java в вашем случае), используя такие инструменты, как netcat или wireshark, а затем сравнивать его с неверным трафиком, чтобы увидеть, куда он идет. неправильно. В качестве дополнительного преимущества вы также можете использовать netcat, чтобы вводить захваченные / предварительно записанные запросы на сервер или вводить захваченные / предварительно записанные ответы в клиент. Не говоря уже о том, что вы также можете изменить запросы / ответы в файле и проверить результаты, прежде чем приступить к исправлению кода.

2 голосов
/ 18 сентября 2008

Это просто, но вы проверяли порядок байтов? Это может быть несоответствие между порядком байтов, в который вы отправили данные, и порядком байтов, в который вы получаете.

1 голос
/ 18 сентября 2008

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

using(Socket socket = ...){
  NetworkStream ns = new NetworkStream(socket);      
  ns.WriteByte((size>>24) & 0xFF);
  ns.WriteByte((size>>16) & 0xFF);
  ns.WriteByte((size>>8)  & 0xFF);
  ns.WriteByte( size      & 0xFF);
  // write the actual message
}
0 голосов
/ 18 сентября 2008

Класс Sysetm.Net.IPAddress имеет два статических вспомогательных метода: HostToNetworkOrder () и NetworkToHostOrder (), которые выполняют преобразование за вас. Вы можете использовать его с BinaryWriter над потоком, чтобы записать правильное значение:

using (Socket socket = new Socket())
using (NetworkStream stream = new NetworkStream(socket))
using (BinaryWriter writer = new BinaryWriter(stream))
{
    int myValue = 42;
    writer.Write(IPAddress.HostToNetworkOrder(myValue));
}
0 голосов
/ 18 сентября 2008

Я не знаю C #, но вам просто нужно сделать эквивалент этого:

out.write((len >>> 24) & 0xFF);
out.write((len >>> 16) & 0xFF);
out.write((len >>>  8) & 0xFF);
out.write((len >>>  0) & 0xFF);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...