服务器关闭连接后 TcpClient 仍然连接。为什么?
TcpClient still connected after server closed connection. Why?
我有一个 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()
关闭连接流,以下对 ReadByte()
的调用失败并出现异常。到目前为止,一切都很好。这就是我所期望的。
第二种:当服务器读取到客户端发送的所有字节,然后关闭连接,下面调用ReadByte()
不会失败。它 returns 0
并且 - 更奇怪 - 它声明仍然连接并且客户端仍然可以毫无例外地在流上写入数据。
有人可以解释为什么第二种情况会这样吗?或者我该如何管理它,以在这种情况下获得例外?
read
returns 如果对等方通过在其末端执行 close
发送 FIN,则为零。
read
为来自对等方的 RST 引发异常 ( ECONNRESET )。
现在:
如果 recv Q 不为空并且尝试 close
,实体将发送 RST。连接永远消失了。
并且如果 recv Q 为空,则在 close
尝试时 FIN 熄灭。这并不意味着另一端不能写入套接字。它还没有调用 close
。连接是半开的。因此,您观察到客户端能够写入套接字。
我有一个 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()
关闭连接流,以下对 ReadByte()
的调用失败并出现异常。到目前为止,一切都很好。这就是我所期望的。
第二种:当服务器读取到客户端发送的所有字节,然后关闭连接,下面调用ReadByte()
不会失败。它 returns 0
并且 - 更奇怪 - 它声明仍然连接并且客户端仍然可以毫无例外地在流上写入数据。
有人可以解释为什么第二种情况会这样吗?或者我该如何管理它,以在这种情况下获得例外?
read
returns 如果对等方通过在其末端执行 close
发送 FIN,则为零。
read
为来自对等方的 RST 引发异常 ( ECONNRESET )。
现在:
如果 recv Q 不为空并且尝试 close
,实体将发送 RST。连接永远消失了。
并且如果 recv Q 为空,则在 close
尝试时 FIN 熄灭。这并不意味着另一端不能写入套接字。它还没有调用 close
。连接是半开的。因此,您观察到客户端能够写入套接字。