【问题标题】:Which actions need to be performed on both ends for a TCP connectionTCP连接两端需要执行哪些动作
【发布时间】:2016-12-28 01:26:15
【问题描述】:

我不太明白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 类在通信过程中究竟是如何工作的,从而消除我的困惑——到目前为止,我还没有找到解释究竟发生了什么的文档。

【问题讨论】:

  • 不一样的NetworkStream。每个流都绑定到其TcpClient 的底层Socket。 -- Send/ReceiveBufferSize 属性只是表示您希望 发送或接收的方式。更改它们没有多大用处,客户端/服务器上的不同也不会真正影响任何事情。
  • @VisualVincent 发送/接收属性是否在“server.AcceptTcpClient()”中发送?我不太明白你说的用处不大是什么意思...如果我打算交换大文件,那么我会增加它们吗?
  • 没有发送任何内容。唯一同步的属性是Connected 属性。 ***BufferSize 属性只是表示您每次调用 NetworkStream.Read/Write 时希望发送或接收的数量。引用the documentation“SendBufferSize 属性获取或设置您希望在每次调用 NetworkStream.Write 方法时发送的字节数。”
  • 不应在单个 Write() 调用中发送整个文件,而应将其拆分为数据包。 BufferSize 属性仅控制网络缓冲区。假设您有一个 8192 的缓冲区,并且您发送了 9192 字节的数据。这将需要NetworkStream 发送前 8192 个字节,然后发送额外的 1000 个字节。一般来说,不需要更改这些属性。
  • 我可以确认更改Send/ReceiveBufferSize 并没有太大区别。经过测试,发送/接收速度似乎没有显着差异 - 我和提问者之间的聊天信息

标签: vb.net tcp tcpclient tcplistener


【解决方案1】:

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

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

每一方都有自己的孤立对象。双方都使用自己的TcpClient 对象,其作用类似于 TCP 连接的句柄。

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

这不是正确的关机顺序。第一行对第二行是多余的并且不完整。永远不应该调用 Close。最好的方法是将客户端包装在using 中。第二种最好的方法是在客户端上调用Dispose。 BCL 中的Close 方法是历史性的意外,应该被忽略。在我看过的所有案例中,它们都执行与 Dispose 相同的操作。

不要触摸缓冲区大小。它们控制内核在连接结束时使用多少内存来缓冲数据。内核能够自行管理。

也不要查看代码中的缓冲区大小。它们毫无意义。也不要使用DataAvailable 属性,因为如果它返回false/0,这并不意味着无法读取任何数据。

Connected 属性不一定在双方同步。如果网络出现故障,则无法同步。永远不要看Connected 属性。如果它在下一纳秒显示true,它可能是false。因此,不可能根据该属性做出决定。你不需要测试任何东西。只需读/写并通过中止处理异常。

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

【讨论】:

  • 当您说最好使用using 时,如果所有内容都不包含在一个子中,这是不可能的……那我该怎么办?只需拨打Dispose?
  • 是的,请致电 Dispose。或者,重新排列代码,使其全部为一个子。你也可以这样做:void HandleConn(TcpClient client) { using (client) ... }using 不需要new
  • 是的 - 问题是我已经为它制作了一个包装类,具有单独的发送/接收功能
  • 您可以使包装器 IDisposable 并用于包装器。
  • 我不确定...每次客户端断开连接然后重新连接时,我都会在包装器中初始化TcpClient 的新实例。你能解释一下DataAvailable 属性不可靠是什么意思吗?什么时候发生?
猜你喜欢
  • 1970-01-01
  • 2014-07-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多