0

我制作了一个可以同时与多个客户端通信的 TCP 服务器,但我似乎无法使它们稳定。当其中一个客户端向服务器发送 100 个数据包时,服务器只接收到其中的几个。

这是 PasteBin 中的客户端代码。它显示了客户端如何连接到服务器,然后在 For 循环中向服务器发送 100 条消息。

以下是服务器处理连接的方式。我无法粘贴完整的源代码,因为它有数百行,所以如果它缺少任何强制性部分,请告诉我,我也会上传它们。

4

1 回答 1

1

我也在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# 中,因为这是我最满意的,对此我深表歉意。;)

客户代码

服务器代码

我希望这有帮助!

于 2011-10-16T15:46:16.807 回答