Нужно ли закрывать сокет сервера при отправке всех данных?

#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 ), — это установить значение a ReadTimeout для потока сокетов. В противном случае Read() просто заблокировал бы вызывающего абонента до тех пор, пока не поступят новые данные. Read() вернет 0 только тогда, когда одноранговый узел (т. е. сервер) закроет свой конец соединения. Реальный вопрос в том, почему вы пытаетесь прочитать больше байтов, чем отправляет сервер? Вы должны знать, как сервер формирует свои сообщения, вы не можете просто читать вслепую.

2. @RemyLebeau, которым я пользовался ReceiveTimeout TcpClient , потому Read() что зависает навсегда в ожидании дополнительных данных, как только он прочитает общее количество отправленных сокетом сервера. Отвечая на ваш вопрос : Существует формат для кадра, что-то вроде: <заголовок><заголовок><размер><размер><полезная нагрузка>, однако проблема в том, что такой сервер может отправлять более одного кадра при чтении, но нет способа узнать, сколько кадров будет отправлено.

3. » Я использовал ReceiveTimeout TcpClient , потому Read() что зависает навсегда, ожидая дополнительных данных, как только он прочитает общее количество, отправленное сокетом сервера » — Так и должно быть. По умолчанию. сокеты работают в режиме блокировки, если вы не переведете их в неблокирующий режим или не укажете время ожидания. В этом случае вы получаете ошибку, потому что вы читаете больше байтов, чем должны . Просто перестань это делать. » Есть формат для кадра » — Хорошо, ТЕПЕРЬ мы к чему-то пришли. Фрейминг точно сообщает вам, сколько байтов следует ожидать, поэтому прочитайте ТОЛЬКО это количество байтов, НЕ БОЛЬШЕ И НЕ МЕНЬШЕ.

4. » сервер может отправлять более одного кадра при чтении, но нет способа узнать, сколько кадров будет отправлено » — это совершенно нормально. Тебе не нужно этого знать. TCP-это поток байтов, он не имеет понятия о сообщениях, поэтому используется фрейминг. Считывайте ТОЛЬКО байты <header> , затем считывайте ТОЛЬКО байты <size> , затем считывайте ТОЛЬКО байты <payload> , затем ОСТАНАВЛИВАЙТЕ и обрабатывайте кадр по мере необходимости. Затем позже считывайте ТОЛЬКО байты для следующего <header> , <size> а <payload> затем ОСТАНОВИТЕСЬ. Повторяйте по мере необходимости.

5. @RemyLebeau Спасибо за разъяснение. Я подумал, что правильный способ-прочитать все байты, отправленные сокетом, а затем декодировать эти байты в соответствии с форматом кадрирования. Я думал, что чтение содержимого, отправленного сокетом так, как вы предположили, было плохой практикой, потому что оно было тесно связано с форматом кадрирования. Даже я думал, что серверный сокет был плохо реализован.