我有一台运行TCP客户端的TCP服务器 - 疯了,我知道。现在我的行为对我来说并不清楚,也许有人可以帮助我理解它。
[Test]
[TestCase(2, 1)] // first scenario: Okay!
[TestCase(1, 1)] // second scenario: Huh?
public void NotifyClientAboutError(int clientSendBytes, int serverReadBytes)
{
var server = new TcpListener(IPAddress.Any, 12345);
server.Start();
Task.Factory.StartNew(() =>
{
using (var serverClient = server.AcceptTcpClient())
{
using (var serverClientStream = serverClient.GetStream())
{
for (var i = 0; i < serverReadBytes; i++)
{
serverClientStream.ReadByte();
}
serverClientStream.Close();
}
serverClient.Close();
}
});
using (var client = new TcpClient())
{
client.Connect(IPAddress.Loopback, 12345);
using (var clientStream = client.GetStream())
{
for (var i = 0; i < clientSendBytes; i++)
{
clientStream.Write(new byte[] { 42 }, 0, 1);
}
// returns 0 - would have expected an Exception here
clientStream.ReadByte();
// says: true
Console.WriteLine(client.Connected);
// no exception
clientStream.Write(new byte[] { 42 }, 0, 1);
clientStream.Flush();
// says: true
Console.WriteLine(client.Connected);
}
}
server.Stop();
}
请参阅NUnit测试用例中包含的两个场景:
首先:当服务器读取的字节数少于客户端发送的时,通过调用流上的Close()
来关闭连接,以下调用{ {1}}失败并出现异常。到现在为止还挺好。这就是我的期望。
第二:当服务器读取客户端发送的所有字节时,然后关闭连接,以下对ReadByte()
的调用不会失败。它返回ReadByte()
并且 - 更奇怪 - 它表示仍然连接,客户端仍然可以毫无例外地在流上写入数据。
有人可以解释为什么第二种情况会像这样发生吗?或者如何管理它,在这种情况下获得例外?
答案 0 :(得分:1)
read
发送了FIN,则 close
返回零。
read
从对等方为RST引发异常(ECONNRESET)。
现在:
如果recv Q不为空,实体将发送RST并尝试close
。连接已经消失了。
如果recv Q为空,则在尝试close
时FIN退出。而这并不意味着另一端无法写入套接字。它还没有调用close
。连接是半开放的。因此,您观察到客户端能够写入套接字。