套接字 WriteLine/ReadLine 不匹配

Socket WriteLine/ReadLine getting mismatched

平时遇到问题自己能解决,但又不得不求助。如果有什么不连贯的地方,我提前道歉,因为我好像有点发烧。

我目前正在使用 XNA 制作非常简单的游戏。这是一款 2D 高空射击游戏。唯一的动作是玩家射击子弹。问题是,我想让它成为多人游戏(同一网络中的玩家)。

我考虑过以下方法:

  1. 其中一位玩家托管服务器

    • 服务器保存每个玩家和子弹的位置信息
    • 服务器创建新世界(由玩家和子弹组成)并像这样在新线程中更新它:

      while (true)
          {
              lock (world) world.update();
              Thread.Sleep(worldUpdatePeriod);
          }
      
    • 服务器为每个必须处理的玩家创建新线程

  2. 玩家连接服务器

    • 他们应该定期从服务器接收信息他们应该画什么:

      class Asset
      {
         string type;
         Vector2 position;
      }
      
    • 他们应该能够从键盘和鼠标发送输入来移动和射击。

现在,进入正题。播放器可以向服务器发送三种类型的消息:

服务器,在每个客户端的单独线程中等待消息

streamReader = new StreamReader(networkStream);
streamWriter = new StreamWriter(networkStream);
streamWriter.AutoFlush = true;

while (true)
{
    if (networkStream.DataAvailable)
    {
        string header;
        lock (streamReader)
        {
            header = Convert.ToString(streamReader.ReadLine());
            Console.WriteLine($"Header received: {header}");
            handleHeader(header);
        }
    }
}

现在如果 header 是,例如 "CAN READ"

  1. 服务器

    case "CAN READ":
        if (streamWriter.BaseStream.CanRead)
        {
            lock (streamWriter)
            {
                streamWriter.WriteLine(server.world.assets.Count);
    
                foreach (var asset in server.world.assets)
                {
                    streamWriter.WriteLine(asset.type);
                    streamWriter.WriteLine(asset.position.X);
                    streamWriter.WriteLine(asset.position.Y);
                }
            }
        }
        break;
    
  2. 客户

    int assetCount = Convert.ToInt32(streamReader.ReadLine());
    List<Asset> receivedAssets = new List<Asset>();
    
    lock (streamReader)
    {
    
        for (int i = 0; i < assetCount; i++)
        {
            string type = Convert.ToString(streamReader.ReadLine());
            int x = Convert.ToInt32(streamReader.ReadLine());
            int y = Convert.ToInt32(streamReader.ReadLine());
    
            receivedAssets.Add(new Asset(type, new Vector2(x, y)));
        }
        return receivedAssets;
    }
    

当然,Client class 和 handleClient class 有独立的 streamReaders 和 streamWriters。

你懂的。我正在尝试将来自服务器的每个 WriteLine() 与来自客户端的 ReadLine() 进行匹配,依此类推。而且效果很好!直到我将用户输入添加到混合物中。

一旦我发送键盘输入(如上所示匹配),它似乎可以工作,偶尔 System.FormatException,这意味着某些 ReadLine() 读错了 WriteLine()。我能够抓住它并重试。

一旦我也发送鼠标输入,一切都会变得糟糕。不匹配的异常更常见到 'game' 无法播放的地步。所以我想知道我的方法是否有问题。对于问题的长度,我深表歉意,我尽量简洁,但也觉得有必要提供上下文。谢谢,如果你能坚持到最后,我很乐意回答任何进一步的问题,因为我在过去几天一直在努力解决它。

我已经阅读了 Andrew 提供给我的 link,我已经能够让它发挥作用。如何?同时使用 TCP 客户端(建立连接,从客户端读取输入)和 UDP 客户端(向每个客户端广播资产)。只是发布以防将来有人遇到此类问题,我对此表示高度怀疑。

干杯!