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

时间:2017-11-20 07:19:47

标签: 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并在那里发送消息并在之后阅读。但是,我真的不确定我该怎么做。你能帮忙吗?

2 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:0)

客户端看起来比服务器更可疑。

StreamWriter不是线程安全的。使用ClientWorldServer.Send时是否以线程安全的方式调用它?使用lockBlockingCollection或其他同步原语将您的来电锁定或排入ClientWorldServer.Send。您也可以使用a thread-safe wrapper of streamwriter