Почему разъединение конечной точки TCP выбрасывает кучу 0 байт на другую конечную точку?

#c# #sockets #tcp

Вопрос:

Я играл с сокетами и TCP в C#, и это произошло. Когда одна конечная точка подключения отключается, другая при использовании метода получения получает набор нулевых байтов. Почему это происходит?

Это код (выполняемый с помощью скрипта dotnet), который может воспроизвести то, о чем я упоминал:

 using System;
using System.Net;
using System.Net.Sockets;
                    
Socket s = new Socket(SocketType.Stream, ProtocolType.Tcp);
s.Bind(new IPEndPoint(IPAddress.Any, 1000));
s.Listen(1);
Console.WriteLine("Opened.");

Socket c = new Socket(SocketType.Stream, ProtocolType.Tcp);
c.Connect(new IPEndPoint(IPAddress.Loopback, 1000));

Socket i = s.Accept();
Console.WriteLine("Accepted.");

byte[] buffer = Array.Empty<byte>();

i.Shutdown(SocketShutdown.Both);

while (true)
{
    buffer = new byte[4];
    c.Receive(buffer, 4, SocketFlags.None);
    Console.WriteLine(BitConverter.ToString(buffer).Replace("-"," "));
}
 

Когда произойдет проблема, консоль напечатает много 00 00 00 00 последовательностей. Это тоже происходит с i и c обменивается.

Ответ №1:

… другой при использовании метода приема получает кучу нулевых байтов

Это неверная интерпретация из-за неправильного кода. Распечатывается содержимое исходного буфера с нулевой инициализацией. Буфер внутри не изменился c.Receive , так как вызов ничего не получил.

Что нужно было сделать, так это проверить возвращаемое значение Receive , которое представляет собой количество фактически прочитанных байтов. Это показало бы, что код ничего не вернул. Вместо этого было просто, но ошибочно предположено, что было прочитано 4 байта, потому что было запрошено 4 байта.

В общем Receive случае всегда можно вернуть меньше байтов, чем требуется, не только при закрытии соединения. Таким образом, только столько байтов из узла buffer должно считаться считанным с однорангового узла, как явно возвращенное, так и полученное байтами Receive .

Комментарии:

1. Означает ли это, что эта перегрузка приема не блокируется до тех пор, пока не будет получено заданное количество байтов? Получает ли он столько, сколько может, только один раз, а затем возвращается?

2. @TrietVoNguyenMinh: Receive будет блокироваться до тех пор, пока не будет получен хотя бы один байт или пока не станет ясно, что никакие байты вообще не могут быть получены (т. Е. соединение закрыто или ошибка). Чтобы процитировать документацию, на которую я ссылался: «Если вы используете сокет, ориентированный на подключение, метод приема будет считывать столько данных, сколько доступно, вплоть до количества байтов, указанного параметром size . Если удаленный хост отключит соединение с сокетом с помощью метода завершения работы, и все доступные данные будут получены, метод приема завершится немедленно и вернет нулевые байты».