【发布时间】:2018-07-20 11:31:35
【问题描述】:
我希望有人能解释这种行为,或者这可能是 .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);
}
}
}
【问题讨论】:
-
只是为了确定,您是说失败是重复返回负值,无一例外?
-
失败是返回值== 0,因为它根本没有等待,根本没有读取任何数据。
-
返回值
0通常意味着连接已经干净地关闭。确认实际情况并非如此(可能是由于对时间变化做出反应的结果)。从理论上讲,这可能是一个 .NET 错误,但极不太可能,因为设置ReadTimeout所做的只是使用SO_RCVTIMEO选项调用本机setsockopt。完全不清楚为什么内核甚至应该关心与网络超时相关的相对系统时间。 -
我绝对可以保证连接没有断开,我编辑了帖子,所以它也在这里。您仍然可以向 tcpclient 发送数据,并且当它处于此状态时它仍然会读取它。 1小时后,即凌晨2点,它恢复正常。老实说,它开始感觉像是 .NET 中的一个错误
-
如果您还没有这样做,也可以在另一台机器上复制它,最好是只安装 Windows 的干净 VM,以尽量减少网络堆栈的任何可能的恶作剧。此外,看看您是否可以发布您在端口
1234上监听的任何代码,以便我们进行完整的复制。如果你做不到,试着让它变得无伤大雅和琐碎,比如netcat(或你自己的简单TcpListener循环)。如果您可以仅使用localhost和琐碎的网络代码重现此问题,那么这应该是Windows 本身的一个错误,而不仅仅是.NET。这就是为什么它如此不可能(但并非不可能)。
标签: c# sockets datetime tcpclient networkstream