在TcpListener
和TcpClient
进行通信时,我并不完全清楚如何分享一些功能。
假设运行以下代码(暂时忽略同步):
服务器:
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
类在沟通过程中的工作原理来解决我的困惑 - 到目前为止,我还没有找到解释究竟发生了什么的文档。
答案 0 :(得分:2)
TCP协议不知道TcpClient
是什么。这是一个.NET概念。 TCP根本不引用.NET概念。因此,不会通过电线发送任何对象。
唯一发送的是你明确写的字节。
每一方都拥有自己的孤立物体。双方都使用自己的TcpClient
对象,它就像TCP连接的句柄一样。
client.GetStream.Close()
client.Close()
这不是正确的关机顺序。第一行是第二行,而第二行是不完整的。永远不应该打电话给关闭。最好的方法是将客户端包装在using
中。第二种最好的方法是在客户端上调用Dispose
。 BCL中的Close
方法是历史事故,应予以忽略。他们做的事与Dispose在我曾经看过的所有情况下做的一样。
请勿触摸缓冲区大小。它们控制内核用于缓冲连接末端数据的内存量。内核能够自行管理它。
另外,请不要查看代码中的缓冲区大小。它们毫无意义。也不要使用DataAvailable
属性,因为如果它返回false/0
,这并不意味着无法读取数据。
Connected
属性不一定在双方同步。如果网络出现故障,则无法进行同步。永远不要看Connected
财产。如果它显示true
下一个纳秒,它可能是false
。因此,根据该属性做出决定是不可能的。你不需要测试任何东西。只需读/写并通过中止处理异常。
关于数据包,您Write
时不发送数据包。 TCP具有无边界的字节流。内核在内部打包您的数据。您无需将数据拆分为特定大小。只需使用相当大的缓冲区大小,如8K(或更快的网络)。写入大小只是通过减少繁琐来节省CPU时间(假设启用了nagling)。