Проблема связи с сокетом Java - PullRequest
0 голосов
/ 24 марта 2011

Я использую Java для сокетной связи.Сервер читает байты с клиента следующим образом:

InputStream inputStream;
final int BUFFER_SIZE = 65536;
byte[] buffer = new byte[BUFFER_SIZE];
String msg="";

while (msg.indexOf(0)==-1 && (read = inputStream.read(buffer)) != -1)
{
    msg += new String(buffer, 0, read);
}
handleMessage(msg)

Существует проблема, когда клиент отправляет несколько сообщений одновременно, сервер смешивает сообщения, например,

MSG1: <MyMessage><Hello/>nul
MSG2: </MyMessage><MyMessage><Hello again /></MyMessage>nul

Так чтохвост сообщения 1 является частью сообщения 2. Ноль представляет символ java nul.

Почему входной поток смешивает сообщения?

Заранее спасибо!

Ответы [ 4 ]

1 голос
/ 24 марта 2011

Вы делаете неправильное сравнение. Вы проверяете, есть ли \ 0 где-нибудь в строке, и затем считаете, что это одно сообщение. Неправильно. На самом деле, во втором примере \ 0 встречается дважды.

Вы должны сделать это по-другому. Чтение из потока в char на char (с использованием обертки BufferedInputStream, иначе производительность будет ужасной) и пропуск при достижении \ 0 Теперь сообщение завершено, и вы можете его обработать.

InputStream bin = new BufferedInputStream(inputStream);
InputStreamReader reader = new InputStreamReader(bin);
StringBuilder msgBuilder = new StringBuilder();
char c;
while ( (c=reader.read()) != -1 ) 
{
    msgBuilder .append(c);
}
handleMessage(msgBuilder.toString())

Еще лучше было бы использовать символ новой строки для разделения строк. В этом случае вы можете просто использовать функцию readline () BufferedReader.

0 голосов
/ 24 марта 2011

Данные, которые вы прочитали с InputStream, поступят, поскольку они доступны из ОС, и нет никакой гарантии, как они будут разделены. Если вы хотите разделить на новые строки, вы можете рассмотреть что-то вроде этого:

BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));

А затем используйте reader.readLine(), чтобы получить каждую строку как String, это ваше сообщение.

0 голосов
/ 24 марта 2011

Я думаю, что ваша проблема в вашем подходе:

Существует проблема, когда клиент отправляет несколько сообщений одновременно

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

Сокеты будут контролировать, является ли ваше сообщение целостным с физической точки зрения, но что именно в сообщении, является вашей заботой.

0 голосов
/ 24 марта 2011

Сокеты и InputStream являются только потоком байтов, а не сообщений. Если вы хотите разбить поток на основе символа типа \0, вам нужно сделать это самостоятельно.

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

Кстати: использование String + = очень неэффективно.

...