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

标签 c# tcp memorystream

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

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 并将一条消息放在那里,然后再阅读它。但是我真的不确定我该怎么做。你能帮忙吗?

最佳答案

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

关于c# - 如果发送了很多消息,如何写入 MemoryStream,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47386798/

相关文章:

c# - 正在注册的类(class)上获取类(class)未注册 80041054

c# - Azure函数: StatusCode cannot be set because the response has already started

tcp - 服务器比使用 TCP 的客户端花费更多时间

c# - 使用 memorystream 创建文件并保存到它

c# - 将 Azure blob 的内容下载为文本字符串需要很长时间

c# - C# 中自定义 SQL SELECT 查询的安全检查

c# - 从ViewModel中选择 ListView 中的所有项目

c++ - 使用 tun/tap 接口(interface)的错误序列号

http - 多个客户端如何同时连接到服务器上的一个端口,比如 80?

delphi - 印地和 TStreams