我希望有人可以解释这种行为,或者它是否可能是 .NET 中的错误。
由于夏令时而及时向后移动意味着 NetworkStream 不注意其属性 ReadTimeout,并且在此代码的情况下会导致循环旋转。 (这只是一个证明它正在发生的例子)。
要重现我看到的问题,您需要设置一个使用夏令时的时区,例如英国。
- 将您的时区设置为 UTC London,并确保选中夏令时。
- 将日期改回 2017 年 10 月 29 日
- 将时间设置为凌晨 01:58:50
- 运行下面的代码,观察它在凌晨 2 点应用夏令时时旋转,如果应用正确,时间应该回到凌晨 1 点。
- 请务必等待,它最多可能需要 30 秒才能开始旋转。
编辑:经过深入调查,1 小时后,它停止旋转,行为恢复正常并遵守 ReadTimeout。
如有任何想法,我们将不胜感激!
客户端代码:
class Program
{
static bool running = false;
static void Main(string[] args)
{
running = true;
Task.Factory.StartNew(() => Run());
Console.ReadKey();
running = false;
}
static void Run()
{
TcpClient connection = new TcpClient("127.0.0.1", 1234);
while (running)
{
if (connection != null && connection.Connected)
{
try
{
NetworkStream stream = connection.GetStream();
stream.ReadTimeout = 1000;
byte[] buffer = new byte[1024];
int readCount = stream.Read(buffer, 0, 1024); // Should block here for the ReadTimeout duration if nothing received
// However when daylight savings is applied and time moves backwards an hour, the stream.ReadTimeout = 1000;
// is not honoured and it falls through and spins
if (readCount > 0)
{
Console.WriteLine("Received some data");
//process read here
}
else
{
Console.WriteLine("ReadTimeout was not honoured");
}
}
catch (IOException)
{
Console.WriteLine("Read timed out");
}
}
}
}
}
服务器代码:
class Program
{
static bool running = false;
public static void Main()
{
TcpListener server = null;
try
{
// Set the TcpListener on port 13000.
Int32 port = 5000;
IPAddress localAddr = IPAddress.Parse("192.168.1.69");
// TcpListener server = new TcpListener(port);
server = new TcpListener(localAddr, port);
// Start listening for client requests.
server.Start();
// Enter the listening loop.
while (true)
{
Console.Write("Waiting for a connection... ");
// Perform a blocking call to accept requests.
// You could also user server.AcceptSocket() here.
TcpClient client = server.AcceptTcpClient();
Console.WriteLine("Connected!");
// Get a stream object for reading and writing
NetworkStream stream = client.GetStream();
running = true;
Task.Factory.StartNew(() => Run(stream));
Console.ReadKey();
// Shutdown and end connection
client.Close();
}
}
catch (SocketException e)
{
Console.WriteLine("SocketException: {0}", e);
}
finally
{
// Stop listening for new clients.
server.Stop();
}
Console.WriteLine("\nHit enter to continue...");
Console.Read();
}
static async Task Run(NetworkStream stream)
{
byte[] stuffToSend = Encoding.ASCII.GetBytes("Stuff to send");
while (running)
{
stream.Write(stuffToSend, 0, stuffToSend.Length);
await Task.Delay(1000);
}
}
}
最佳答案
the OS documentation中有一些非常重要的注意事项.NET ReadTimeout
属性中未提及的内容:
SO_RCVTIMEO
andSO_SNDTIMEO
When using the
recv
function, if no data arrives during the period specified inSO_RCVTIMEO
, therecv
function completes. In Windows versions prior to Windows 2000, any data received subsequently fails withWSAETIMEDOUT
. In Windows 2000 and later, if no data arrives within the period specified inSO_RCVTIMEO
, therecv
function returnsWSAETIMEDOUT
, and if data is received,recv
returns SUCCESS.If a send or receive operation times out on a socket, the socket state is indeterminate, and should not be used; TCP sockets in this state have a potential for data loss, since the operation could be canceled at the same moment the operation was to be completed.
目前,在每次超时后,您都在循环并尝试在同一个套接字上进行另一个接收操作。但是这个注释非常清楚地表明您需要创建一个新连接。
关于c# - NetworkStream.ReadTimeout 在应用夏令时和时钟向后移动时无法阻止 NetworkStream.Read(...),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48710174/