一个TCP连接需要在两端进行哪些动作

Which actions need to be performed on both ends for a TCP connection

我不太明白 TcpListenerTcpClient 交流时一些功能是如何共享的。

假设下面的代码是运行(现在忽略同步):

服务器:

Dim server As New TcpListener(localAddr, port)
server.Start()

Dim client As TcpClient = server.AcceptTcpClient()

客户:

Dim client As New TcpClient
client.Connect(hostAddr, port)

连接成功。现在有两个 TcpClient 个实例——一个在服务器端,一个在客户端。但是,他们通过 TcpClient.GetStream().

共享相同的网络流

我有点困惑 — 当调用 server.AcceptTcpClient() 时,客户端是否将自身及其所有属性传递给服务器?

在此之后对 TcpClient 个实例中的任何一个有什么变化?当连接关闭时,我在两侧调用它:

client.GetStream.Close()
client.Close()

但是我在客户端上遇到 TcpClient.GetStream.Close() 的异常,它最近执行了这段代码,因为它告诉我客户端已经关闭(当上面的代码在双方没有完全同步时会发生这种情况).

.SendBufferSize.ReceiveBufferSize 属性呢?我需要在连接的两端都设置吗?

希望有人可以通过解释 TcpClient/Listener 类 在通信过程中究竟如何工作来消除我的困惑 — 到目前为止,我还没有找到解释到底发生了什么的文档。

TCP 协议不知道TcpClient 是什么。这是一个.NET 概念。 TCP 根本不引用 .NET 概念。因此,不会通过网络发送任何对象。

唯一发送的是您明确写入的字节。

每一方都有自己的独立对象。双方都使用自己的 TcpClient 对象,该对象充当 TCP 连接的句柄。

client.GetStream.Close()
client.Close()

这不是正确的关机顺序。第一行相对于第二行是多余的,而且不完整。永远不要调用 Close。最好的方法是将客户端包装在 using 中。第二种最佳方法是在客户端调用 Dispose。 BCL 中的 Close 方法是历史事件,应该忽略。在我看过的所有情况下,他们做的事情和 Dispose 做的一样。

不要触及缓冲区大小。它们控制内核使用多少内存来缓冲连接端的数据。内核能够自行管理它。

也不要查看代码中的缓冲区大小。它们毫无意义。也不要使用 DataAvailable 属性 因为如果它 returns false/0 这并不意味着没有数据可以读取。

Connected属性不一定两边同步。如果网络出现故障,则无法进行同步。永远不要看Connected属性。如果它说 true 下一个纳秒,它可能是 false。因此不可能根据 属性 做出决定。你不需要测试任何东西。只需 Read/Write 并通过中止处理异常。

关于数据包,当你Write时你没有发送数据包。 TCP 有一个无边界的字节流。内核在内部打包您的数据。您不需要将数据拆分为特定大小。只需使用相当大的缓冲区大小,例如 8K(或在快速网络上更大)。写入大小只是通过减少聊天来节省 CPU 时间(假设启用了唠叨)。