Я запускаю NetCore в Windows 10, у меня есть две программы - сервер и клиент, которые я запускаю как локально.Объяснить странное поведение C# TcpClient/TcpListener на NetCore
Последовательность выполнения заключается в следующем:
- Run сервер - есть петля для обработки клиентов
- Запуск клиент - клиент делает свою работу и процесс завершается
- Run клиент во второй раз
Эта последовательность производит следующий вывод с сервера, используя этот код:
Waiting for client.
Reading message.
Incoming message: This message is longer than what
Sending message.
Closing connection.
Waiting for client.
Reading message.
Incoming message: This message is longer than what
Sending message.
Closing connection.
Waiting for client.
и после выхода из клиента:
Connecting to server.
Sending message.
Reading message.
Incoming message: Thank you!
Connecting to server.
Sending message.
Reading message.
Unhandled Exception: System.AggregateException: One or more errors occurred. (Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.) ---> System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host. ---> System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host
Другими словами - вторая попытка запуска клиента заканчивается исключением. Это странная часть.
Вот мой минимальный образец кода для воспроизведения проблемы.
Серверный код:
public static async Task StartServerAsync()
{
TcpListener listener = new TcpListener(IPAddress.Any, 1234);
listener.Server.NoDelay = true;
listener.Server.LingerState = new LingerOption(true, 0);
listener.Start();
while (true)
{
Console.WriteLine("Waiting for client.");
using (TcpClient client = await listener.AcceptTcpClientAsync())
{
client.NoDelay = true;
client.LingerState = new LingerOption(true, 0);
Console.WriteLine("Reading message.");
using (NetworkStream stream = client.GetStream())
{
byte[] buffer = new byte[32];
int len = await stream.ReadAsync(buffer, 0, buffer.Length);
string incomingMessage = Encoding.UTF8.GetString(buffer, 0, len);
Console.WriteLine("Incoming message: {0}", incomingMessage);
Console.WriteLine("Sending message.");
byte[] message = Encoding.UTF8.GetBytes("Thank you!");
await stream.WriteAsync(message, 0, message.Length);
Console.WriteLine("Closing connection.");
}
}
}
}
код клиента:
public static async Task StartClientAsync()
{
using (TcpClient client = new TcpClient())
{
client.NoDelay = true;
client.LingerState = new LingerOption(true, 0);
Console.WriteLine("Connecting to server.");
await client.ConnectAsync("127.0.0.1", 1234);
Console.WriteLine("Sending message.");
using (NetworkStream stream = client.GetStream())
{
byte[] buffer = Encoding.UTF8.GetBytes("This message is longer than what the server is willing to read.");
await stream.WriteAsync(buffer, 0, buffer.Length);
Console.WriteLine("Reading message.");
int len = await stream.ReadAsync(buffer, 0, buffer.Length);
string message = Encoding.UTF8.GetString(buffer, 0, len);
Console.WriteLine("Incoming message: {0}", message);
}
}
}
Как ни странно, если мы изменим сообщение клиента от
"This message is longer than what the server is willing to read."
в
"This message is short."
оба экземпляра клиента завершают без сбоев и выдают тот же результат.
Обратите внимание, что если я опустил все три строки, где установлен LingerState, это не имеет значения. И нет никакой разницы в поведении, если я изложу LingerState к
new LingerState(true, 5)
И нет никакой разницы, если я изложу NODELAY ложь. Другими словами, установка любых значений для LingerState и NoDelay с обеих сторон, похоже, не влияет на сбой. Единственный способ предотвратить крах - прочитать весь ввод от клиента на стороне сервера.
Это странно, и мне интересно, может ли кто-нибудь объяснить это. Я не уверен, что он относится и к .NET Framework, но тестируется только с NetCore 1.0.0 и Windows 10.
Извините, но уже написано в вопросе, что «Единственный способ предотвратить крах - прочитать весь ввод от клиента на стороне сервера». Сам вопрос заключается в том, почему он сбой, когда весь сообщение не читается. – Wapac