我制作了一个可以同时与多个客户端通信的 TCP 服务器,但我似乎无法使它们稳定。当其中一个客户端向服务器发送 100 个数据包时,服务器只接收到其中的几个。
这是 PasteBin 中的客户端代码。它显示了客户端如何连接到服务器,然后在 For 循环中向服务器发送 100 条消息。
以下是服务器处理连接的方式。我无法粘贴完整的源代码,因为它有数百行,所以如果它缺少任何强制性部分,请告诉我,我也会上传它们。
我制作了一个可以同时与多个客户端通信的 TCP 服务器,但我似乎无法使它们稳定。当其中一个客户端向服务器发送 100 个数据包时,服务器只接收到其中的几个。
这是 PasteBin 中的客户端代码。它显示了客户端如何连接到服务器,然后在 For 循环中向服务器发送 100 条消息。
以下是服务器处理连接的方式。我无法粘贴完整的源代码,因为它有数百行,所以如果它缺少任何强制性部分,请告诉我,我也会上传它们。
我也在reddit上回答了你的问题,但我想我会在这里回复,以防其他人正在搜索这种东西。
服务器处理读取的方式有两个问题。首先,您的客户端对象的构造函数:
Public Sub New(ByVal client As TcpClient)
'New client connects
Me.client = client
client.GetStream().BeginRead(New Byte() {0}, 0, 0, AddressOf Read, Nothing)
End Sub
BeginRead 希望您以可以传递给回调方法的方式收集数据;在这种情况下“阅读”。通常,这是通过创建一个新对象来保存此异步操作的“状态”并将其作为最后一个参数传递给 BeginRead 来完成的。您在此处的方法调用正在创建一个新的字节数组,但没有持有对它的引用以作为该方法的最后一个参数传入。这意味着通过此调用读取的数据将在读取后消失,因为它永远不会传递给存储它的方法。
其次,您的读取操作:
Public Sub Read(ByVal ar As IAsyncResult)
Dim reader As New StreamReader(client.GetStream())
clientPacket &= reader.ReadLine()
client.GetStream().BeginRead(New Byte() {0}, 0, 0, AddressOf Read, Nothing)
End Sub
由于您没有传递在异步调用中读取的数据,因此您将在此处创建一个新的 StreamReader 以从客户端提取更多数据。这不是异步方法调用。您的 reader.ReadLine() 调用将阻塞,直到遇到换行符,此时数据将附加到 clientPacket。然后您再次调用 BeginRead,出现与上述相同的问题,这意味着您将丢失更多数据。
此外,您永远不会通过在流上调用 EndRead() 来清除 AsyncResult 对象,当 CLR 用完异步操作的工作线程时,这最终会导致资源匮乏。
这是我实现此类任务的方式的示例。它在 C# 中,因为这是我最满意的,对此我深表歉意。;)
我希望这有帮助!