如果发送了很多消息,如何写入 MemoryStream

How to write to MemoryStream if many messages are sent

下面是我现在如何从流中读取数据:

public List<ServerClient> clients = new List<ServerClient>();

while (true)
{
    Update();
}

    private void Update()
    {
        //Console.WriteLine("Call");
        if (!serverStarted)
        {
            return;
        }

        foreach (ServerClient c in clients.ToList())
        {
            // Is the client still connected?
            if (!IsConnected(c.tcp))
            {
                c.tcp.Close();
                disconnectList.Add(c);
                Console.WriteLine(c.connectionId + " has disconnected.");
                CharacterLogout(c.connectionId);
                continue;
                //Console.WriteLine("Check for connection?\n");
            }
            else
            {



                // Check for message from Client.
                NetworkStream s = c.tcp.GetStream();
                if (s.DataAvailable)
                {
                    string data = c.streamReader.ReadLine();

                    if (data != null)
                    {
                        OnIncomingData(c, data);
                    }

                }
                //continue;
            }
        }

        for (int i = 0; i < disconnectList.Count - 1; i++)
        {
            clients.Remove(disconnectList[i]);
            disconnectList.RemoveAt(i);
        }


    }

当读取数据时,它被发送到正在处理数据的OnIncomingData函数。我在那里没有问题。

以下是我向流发送数据的方式:

public void Send(字符串头,字典数据) {

if (stream.CanRead)
{
    socketReady = true;
}

if (!socketReady)
{
    return;
}
JsonData SendData = new JsonData();
SendData.header = "1x" + header;
foreach (var item in data)
{
    SendData.data.Add(item.Key.ToString(), item.Value.ToString());
}
SendData.connectionId = connectionId;

string json = JsonConvert.SerializeObject(SendData);
var howManyBytes = json.Length * sizeof(Char);
writer.WriteLine(json);
writer.Flush();

Debug.Log("Client World:" + json);

}

这是我的:

public class ServerClient
{
    public TcpClient tcp;
    public int accountId;
    public StreamReader streamReader;
    public int connectionId;
    public ServerClient(TcpClient clientSocket)
    {
        tcp = clientSocket;
    }
}

这是我的 OnConnection 函数:

    private void OnConnection(IAsyncResult ar)
    {
        connectionIncrementor++;
        TcpListener listener = (TcpListener)ar.AsyncState;
        NetworkStream s = clients[clients.Count - 1].tcp.GetStream();
        clients.Add(new ServerClient(listener.EndAcceptTcpClient(ar)));
        clients[clients.Count - 1].connectionId = connectionIncrementor;
        clients[clients.Count - 1].streamReader = new StreamReader(s, true);
        StartListening();


        //Send a message to everyone, say someone has connected!
        Dictionary<string, string> SendDataBroadcast = new Dictionary<string, string>();
        SendDataBroadcast.Add("connectionId", clients[clients.Count - 1].connectionId.ToString());

        Broadcast("001", SendDataBroadcast, clients, clients[clients.Count - 1].connectionId);
        Console.WriteLine(clients[clients.Count - 1].connectionId + " has connected.");
    }

通常一切正常。但是,如果我尝试每 1 秒发送更多请求,就会出现问题。收到的消息不完整。它只接收发送的消息的一部分。

Debug.Log("Client World:" + json); 我可以看到消息是完整的,但是在服务器上我看到它不是。

如果我发送较少的请求,就不会发生这种情况。

因此,出于这个原因,我认为我应该创建一个 MemoryStream 并在其中放置一条消息,然后再阅读。但是我真的不确定我该怎么做。你能帮忙吗?

在我看来,客户端比服务器更可疑。

StreamWriter is not thread-safe. Are you calling it in a thread-safe manner when using ClientWorldServer.Send? Lock up or queue your calls to ClientWorldServer.Send using a lock or BlockingCollection or some other synchronisation primitive. There is also a thread-safe wrapper of streamwriter你或许可以使用。

整个代码不是很好,但我会专注于您的具体问题。这很可能与 StreamReader 的数据缓冲有关。 StreamReader 的缓冲区大小(您可以将其传递给构造函数)默认为 1024 字节。当您调用 ReadLine 时 - 流 reader 完全有可能从基础流中读取 更多 一行。在你的情况下 - 你有 while 循环,你在其中枚举连接的客户端,并且在循环的每次迭代中你创建新的 StreamReader 并从中读取一行。当消息率低时 - 一切看起来都很好,因为在你的循环迭代之间只有一行到达。现在假设客户端快速发送了 2 json 条消息,每条消息都是 800 字节,并且它们都到达了您的套接字。现在你打电话给StreamReader.ReadLine。因为缓冲区大小是 1024 - 它将从套接字 (NetworkStream) 读取 1024 个字节,并且 return 前 800 个给你(作为一行)。您处理该行并丢弃 StreamReader 进入 while 循环的下一次迭代。通过这样做,您还丢弃了部分消息(下一条消息的 224 字节),因为它们已经从套接字读取到 StreamReader 缓冲区中。我认为应该清楚如何解决这个问题——不要每次都创建新的 StreamReader,而是为每个客户创建一个(例如存储为 ServerClient 的成员)并使用它。