#c# #c #sockets
Вопрос:
Я написал клиент сокета C#, который отправляет и получает данные из сокета сервера, написанного на C (для которого у меня нет исходного кода, только двоичное приложение).
Но у меня возникают проблемы при получении данных, потому что я получаю следующее исключение SocketException:
A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond
Это раздел кода, который получает данные клиента C# :
byte[] response = new byte[2048];
int bytesRead = 0;
while ((bytesRead = netStream.Read(response, 0, response.Length) > 0)
{
// Copy the data to a memory stream until the total of bytes have been received.
}
Если, например, длина сообщения, отправленного сервером, составляет 1024:
- На первой итерации NetStream.Read считывает эти 1024 байта и возвращает 1024 в bytesRead.
- На второй итерации NetStream.Read выдает предыдущее исключение SocketException, показанное вместо возврата 0 в bytesRead.
То же самое происходит с любой длиной сообщения, полученного из сокета сервера. Сетевой поток.Чтение всегда вызывает одно и то же исключение SocketException, когда для чтения больше нет байтов.
Мой вопрос в следующем: есть ли какая-либо ошибка в моем коде или плохо реализован подключенный сервер?
Комментарии:
1. Единственный способ, которым вы могли бы получить эту конкретную ошибку (которая есть
WSAETIMEDOUT
), — это установить значение aReadTimeout
для потока сокетов. В противном случаеRead()
просто заблокировал бы вызывающего абонента до тех пор, пока не поступят новые данные.Read()
вернет 0 только тогда, когда одноранговый узел (т. е. сервер) закроет свой конец соединения. Реальный вопрос в том, почему вы пытаетесь прочитать больше байтов, чем отправляет сервер? Вы должны знать, как сервер формирует свои сообщения, вы не можете просто читать вслепую.2. @RemyLebeau, которым я пользовался
ReceiveTimeout
TcpClient
, потомуRead()
что зависает навсегда в ожидании дополнительных данных, как только он прочитает общее количество отправленных сокетом сервера. Отвечая на ваш вопрос : Существует формат для кадра, что-то вроде: <заголовок><заголовок><размер><размер><полезная нагрузка>, однако проблема в том, что такой сервер может отправлять более одного кадра при чтении, но нет способа узнать, сколько кадров будет отправлено.3. » Я использовал
ReceiveTimeout
TcpClient
, потомуRead()
что зависает навсегда, ожидая дополнительных данных, как только он прочитает общее количество, отправленное сокетом сервера » — Так и должно быть. По умолчанию. сокеты работают в режиме блокировки, если вы не переведете их в неблокирующий режим или не укажете время ожидания. В этом случае вы получаете ошибку, потому что вы читаете больше байтов, чем должны . Просто перестань это делать. » Есть формат для кадра » — Хорошо, ТЕПЕРЬ мы к чему-то пришли. Фрейминг точно сообщает вам, сколько байтов следует ожидать, поэтому прочитайте ТОЛЬКО это количество байтов, НЕ БОЛЬШЕ И НЕ МЕНЬШЕ.4. » сервер может отправлять более одного кадра при чтении, но нет способа узнать, сколько кадров будет отправлено » — это совершенно нормально. Тебе не нужно этого знать. TCP-это поток байтов, он не имеет понятия о сообщениях, поэтому используется фрейминг. Считывайте ТОЛЬКО байты
<header>
, затем считывайте ТОЛЬКО байты<size>
, затем считывайте ТОЛЬКО байты<payload>
, затем ОСТАНАВЛИВАЙТЕ и обрабатывайте кадр по мере необходимости. Затем позже считывайте ТОЛЬКО байты для следующего<header>
,<size>
а<payload>
затем ОСТАНОВИТЕСЬ. Повторяйте по мере необходимости.5. @RemyLebeau Спасибо за разъяснение. Я подумал, что правильный способ-прочитать все байты, отправленные сокетом, а затем декодировать эти байты в соответствии с форматом кадрирования. Я думал, что чтение содержимого, отправленного сокетом так, как вы предположили, было плохой практикой, потому что оно было тесно связано с форматом кадрирования. Даже я думал, что серверный сокет был плохо реализован.