Чтение и запись данных между c # и java-сокетами - PullRequest
3 голосов
/ 19 января 2012

Я боролся с этим весь день. Мне нужно отправить строки (JSON) между сервером C # и клиентом Java. Я должен иметь первые 4 байта (всегда 4 байта) в качестве длины сообщения (заголовок, чтобы мы знали, какова длина остальной части сообщения), а затем тело сообщения. Потоки остаются открытыми в течение всего срока службы приложения. Лично я бы просто разделил каждое сообщение с помощью '\ n', а затем использовал бы readLine (), но клиент НУЖЕН это так.

Мне нужна сторона C # для отправки и получения этих сообщений, а также сторона Java. Не слишком уверен, как все кодировать и декодировать.

Некоторые биты, с которыми я играл:

C # отправить

byte[] body = Encoding.ASCII.GetBytes(message);
byte[] header = BitConverter.GetBytes((long) body.Length);

foreach (byte t in header)
{
    networkStream.WriteByte(t);
}


foreach (byte t in body)
{
    networkStream.WriteByte(t);
}

Я еще не дошел до C #. Отправка Java:

byte[] dataToSend = data.getBytes();
byte[] header = ByteBuffer.allocate(4).putInt(dataToSend.length).array();
ByteArrayOutputStream output = new ByteArrayOutputStream();
output.write(header);
output.write(dataToSend);
output.writeTo(outputStream);

Java получает:

byte[] header = new byte[4];
int bytesRead;
do {
    Debug.log("TCPClient- waiting for header...");
    bytesRead = reader.read(header);

    ByteBuffer bb = ByteBuffer.wrap(header);
    int messageLength = bb.getInt();

    Debug.log("TCPClient- header read. message length (" + messageLength + ")");

    byte[] body = new byte[messageLength];
    do {
       bytesRead = reader.read(body);
    }
    while (reader.available() > 0 && bytesRead != -1);
}
while (reader.available() > 0 && bytesRead != -1);

Я знаю, что код не является полным, но кто-нибудь может оказать какую-либо помощь?

1 Ответ

4 голосов
/ 19 января 2012

Разделение сообщений с помощью '\n' не очень хорошая идея, если только вы не уверены, что ваши сообщения будут состоять только из однострочного текста.Если '\n' встречается внутри одного из ваших сообщений, то это сообщение будет разделено.

Вы утверждаете, что длина сообщения должна быть ровно 4 байта;однако следующая строка генерирует 8-байтовый массив:

byte[] header = BitConverter.GetBytes((long) body.Length);

Причина в том, что в C # long является псевдонимом для структуры Int64, представляющей 64-разрядное целое число со знаком.Вам нужен int или uint, представляющий 32-разрядное целое число со знаком или без знака.Таким образом, просто измените приведенную выше строку на:

byte[] header = BitConverter.GetBytes(body.Length);

Еще одно важное соображение, которое вам необходимо сделать, - это порядковый номер ваших данных.Представьте, что вы пытаетесь создать 4-байтовый массив для значения, скажем, 7. На платформе с прямым порядком байтов это будет закодировано как 0,0,0,7;на платформе с прямым порядком байтов она будет закодирована как 7,0,0,0.Однако, если он будет декодирован на платформе с обратным порядком байтов, 7 будет интерпретироваться как самый старший байт, давая значение 117,440,512 (равно 7 × 256 3 ), а не 7.

Таким образом, порядковый номер должен быть одинаковым как для вашего Java, так и для ваших приложений на C #.Java ByteBuffer по умолчанию является байтовым;однако C # BitConverter зависит от архитектуры и может быть проверен с помощью статического свойства IsLittleEndian.Вы можете заставить C # всегда следовать правилам с прямым порядком байтов, обращая массив в обратном порядке:

byte[] header = BitConverter.GetBytes(body.Length);
if (BitConverter.IsLittleEndian)
    Array.Reverse(header);
...