Каков наилучший способ отслеживать сокет для новых данных и затем обрабатывать эти данные? - PullRequest
2 голосов
/ 17 января 2009

Прошу прощения за мой статус новичка в C # .Net. Если это очевидно, и я пропустил это из документации, будет полезна ссылка на соответствующую страницу или образец кода.

Я работаю над приложением, которое будет принимать соединение через сокет TCP из приложения Java. (Да, для этой части требуется Java. Это устройство Sun SPOT, и Java - единственный вариант.) Приложение Java будет периодически записывать новые данные в сокет, и работа моего приложения заключается в получении байта [], преобразовании переведите его в строку, обработайте данные (обновите пользовательский интерфейс и т. д.) и, возможно, перенаправьте данные на другой компьютер, на котором выполняется аналогичное приложение C # .NET.

Вот что я сделал до сих пор: сейчас при запуске приложение раскручивает поток, который открывает сокет. Приложение Java может успешно подключиться к сокету, чтобы он работал. Я искал метод beginRead NetworkStream и свойства dataAvailable, length и CanRead, но я не совсем уверен, как определить, когда я прочитал один пакет данных, обычно около 512 байт, но может варьироваться.

Если приложение Java записывает данные в поток или существует резерв данных (приложение Java будет передавать данные довольно быстро.) Как я могу убедиться, что я читаю только один пакет данных за раз? Если приложение Java обнуляет данные, когда оно записывает, это поможет? Этого достаточно?

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

Спасибо за чтение и за любую помощь, которую вы можете предложить.

Ответы [ 3 ]

5 голосов
/ 17 января 2009

"Если приложение Java записывает данные в поток или существует резерв данных (приложение Java будет передавать данные довольно быстро.), Как я могу убедиться, что я читаю только один пакет данных за раз? «

Будьте осторожны, чтобы не предполагать, что у вас есть какой-либо контроль над тем, какие данные попадают в какой пакет. Если вы попытаетесь отправить байтовые данные { 'H', 'e', 'l', 'l', 'o' }, нет гарантии, что все эти данные будут отправлены в одном пакете. Хотя это крайне маловероятно, все же возможно, что каждый пакет может содержать только один байт, поэтому вы получите все пять байтов в 5 различных событиях. Дело в том, что не полагайтесь на пакеты таким образом. Вместо этого определите свои собственные терминаторы End Of Message и просто сбросьте все входящие данные в некоторый байтовый буфер, и у вас есть другая функция, обнаруживающая, присутствует ли какой-либо из этих терминаторов. Если так, то читайте до этого терминатора. Например, вы дважды вызываете соответствующий метод send из вашего Java-приложения, содержащий следующие данные:

{ 'H', 'e', 'l', 'l', 'o', '\0' }
{ 'W', 'o', 'r', 'l', 'd', '\0' }

То, как ваша заявка должна быть подготовлена ​​для получения данных, должно выглядеть примерно так:

Server receives { 'H', 'e', 'l' }
Data stored in byte buffer { 'H', 'e', 'l' }
Check byte buffer for message terminator '\0'. None found. Buffer unchanged, no message processed.
Server receives { 'l', 'o', '\0', 'W' }
Data stored in byte buffer { 'H', 'e', 'l', 'l', 'o', '\0', 'W' }
Check byte buffer for message terminator '\0'. 1 found, extracted message { 'H', 'e', 'l', 'l', 'o' } and buffer updated { 'W' }

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

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

1 голос
/ 17 января 2009

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

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

0 голосов
/ 16 февраля 2009

Способ, которым мы решили это, состоит в том, чтобы получить комбинацию часовых символов и полей фиксированной ширины. Первые два байта являются заголовком длины для всего пакета. Затем я считываю пакет в буфер byte [] и затем полагаюсь на нашу собственную структуру пакета, чтобы знать, что, например, первые два байта должны интерпретироваться как отдельные поля, а затем строковые поля заканчиваются символом \ n (0x0A, если вы забиваете дома). Затем длинные поля данных обрабатываются чтением в 8 последовательных байтах и ​​т. Д. Это, кажется, работает довольно хорошо для нас, но это, очевидно, решение для ситуации, когда один контролирует оба конца сокета, а не только один в состоянии контролировать один конец. Надеюсь, это поможет кому-то еще.

...