【问题标题】:why is BinaryReader inside Thread, reading wrong packet data from netty?为什么 BinaryReader 在 Thread 中,从 netty 读取错误的数据包数据?
【发布时间】:2014-11-20 05:23:25
【问题描述】:

我正在将数据从 netty 发送到统一 3d 游戏引擎中的 c# 应用程序,它读取数据包 ID 并根据数据包 ID(在线程内)执行不同的方法,BinaryReader 读取的数据包 ID 是错误的,我无法理解为什么

这里是 custombuffer、datainputstream、dataoutputstream 类:https://docs.google.com/document/d/1LmW8fzGFFnkgqV_kS-TnBi7XvVYTC4Q4kHWJT60UF00/edit?usp=sharing

您不必仔细阅读它们,我发布它们以便您了解它们是什么

这是登录方式

public void SendLogin(string username,string password)
{
    Debug.Log ("Sending username and password");
    CustomBuffer buffer = new CustomBuffer (ClientOutput);
    buffer.WriteUTF (username);
    buffer.WriteUTF (password);
    buffer.SendBuffer ();
}

这里是 sendLogin 的服务器处理程序

    public PacketEncoder sendLogin(boolean value, Account account,byte opcode) {

    ChannelBuffer buffer = new DynamicChannelBuffer(2);
    ChannelBufferOutputStream out = new ChannelBufferOutputStream(buffer);
    try {
        out.writeInt(0);
        out.writeBoolean(value);
        System.out.println("sendig login back packet 0");
        if(value) {
            System.out.println("value true sending username");
            out.writeUTF(account.getUsername());
        }

        else if(!value) {
            System.out.println("value false sending opcode : "+ String.valueOf( (int)opcode));
            out.writeByte(opcode);
        }

        Send(out.buffer());
        out.close();

    } catch(IOException e) {

        e.printStackTrace();
    }


    return this;
}

这里它工作正常!下面是问题

这是在角色创建请求后返回信息的netty方法

public PacketEncoder SendCharacterCreationResult(boolean exists,boolean success) {
        ChannelBuffer buffer = new DynamicChannelBuffer(2);
        ChannelBufferOutputStream out = new ChannelBufferOutputStream(buffer);
        try {
            out.writeInt(2);
            out.writeBoolean(exists);
            out.writeBoolean(success);

            //debug console 
            System.out.println(" ");
            System.out.println("Sending Character Creation Result packet : 2");
            System.out.println("exists : " + String.valueOf(exists));
            System.out.println("success : " + String.valueOf(success));

            Send(out.buffer());
            out.close();
        } catch(IOException e)
        {
            e.printStackTrace();
        }

        return this;
    }

这是来自 c# 的数据包处理程序

    void InputLoop()
    {
        while(Client.Connected)
        {
            int packetID = ClientInput.ReadInt();
            Debug.Log("packedID : " + packetID);
            switch(packetID)
            {
            case 0: //Login
                PacketsIn.Login();
                break;
            case 1://Character Request Response
                PacketsIn.CharacterRequest();
                break;
            case 2: //Character Creation Response
                PacketsIn.CharacterCreate();
                break;
            }
        }
    }

在登录后,其处理完美的服务器发送带有数据包 id 2 的字符创建结果,当它首先到达客户端时,它运行 packetsIn.Login()(它是 0 的数据包 ID)和 SendCharacterCreationResult 中的 writeInt(2) 从下面的方法中读取其中 byte opcode = ClientInput.ReadByte (); 等于(2)我像这样尝试过 int opcode = clientInput.ReadInt();它给出了相同的结果。如果我感到困惑,你告诉我在文本中添加完整文件

这是输入循环中case 0的函数(在线程中运行)

public void Login()
{
    bool success = ClientInput.ReadBoolean ();
    if(success)
    {
        string username = ClientInput.ReadUTF();
        Debug.Log("Successfuly Logged In. " + username);
        MasterClient.singleton.ChangeScene(4);
    }
    byte opcode = ClientInput.ReadByte ();
    //GameObject.Find ("MessageLogsText").GetComponent<UILabel> ().text
        Debug.Log( GetLoginMessage (opcode) );
}

private string GetLoginMessage(byte opcode)
{
    switch(opcode)
    {
    case 0:
        return "Invalid Usarename Or Password";
    case 1:
        return "Account Is Already Logged In";
    case 2:
        return "test";
    default:
        return "Invalid opcode Sent From Server";
    }
}

然后数据包 id 变成 513,我不明白为什么

【问题讨论】:

  • 在没有看到接收数据的实际代码的情况下,甚至无法开始评论可能出现的问题。但是您的第一步是更多地调试问题;您需要做更多的研究,包括在从传输到最终收据的每一步检查数据,以便您首先确切地知道在哪里数据被误解了。我敢打赌你在某个地方遇到了字节排序问题,但这只是一个疯狂的猜测。见stackoverflow.com/help/mcvestackoverflow.com/help/how-to-ask
  • 嘿,彼得,我的英语不是很好,我尽力了...我会尝试编辑它并添加更多内容
  • 另外,我想评论一下 Peter Duniho 也是正确的,但这并不是目前影响应用程序的原因。 (我会知道,因为我编写了原始教程。)但是,您使用的 DataInputStream 版本已弃用,应该被替换。 (教程系列第 11 部分的下载链接)

标签: java c# sockets unity3d netty


【解决方案1】:

PacketEncoder#SendCharacterCreationResult 中,您通过网络发送三个变量

out.writeInt(2);
out.writeBoolean(exists);
out.writeBoolean(success);

确保无论您在何处读取数据,您都在读取所有三个变量,您似乎仍在使用我已弃用的​​数据包系统,该系统确实需要更换(您将在本系列的后面部分介绍, 来第 11 部分)

您未能提供客户端收到数据包 ID 为 2 时处理的代码,但您看到的结果是由于 TCP 流中存在剩余数据。

在不推荐使用的系统中,您通过客户端发送的第一件事是整数(32 位),客户端将其解释为数据包标识号(或操作码)。在您当前位置的某个视频中,我们将数据包标头从 Byte(8bit) 读取到 Int(32bit) 的方式更改了,确保无论您正在读取数据包 id(opcode)客户端您正在读取一个整数而不是一个字节。

EDIT: I see that you already did this, didn't notice the posted code

完成此操作后,当您收到操作码 2 时,进入您正在调用的任何方法,然后确保您从 PacketsIn#CharacterCreate 正确读取所有数据,您需要发出两个DataInputStream#ReadBoolean() 来电。 (注意: DataInputStream 实例在您的应用程序中称为 ClientInput

在您从PacketsIn#CharacterCreate() 发布代码之前,我无能为力。

【讨论】:

  • 我没有提供 CharacterCreate(),因为 InputLoop 不运行调用 CharacterCreate() 的案例 2,而是运行案例 0,即包含 int opcode = 的 Login() ClientInput.ReadInt () ,并且操作码变为 2 所以线程有问题,这个 2 应该由 InputLoop 的 int packetID = ClientInput.ReadInt(); 读取.如果您注意到我在 clientINput.ReadInt(); 之后有 Debug.Log(packetID);它在操作码的 Debug.Log 之后执行,并打印数字 513 ,我不知道它们是如何乱序执行的,甚至不可能,
【解决方案2】:

我终于明白了!问题出在PacketDecoder#Login() 方法中,当登录成功时,它正在读取服务器未发送的 int,所以我做了什么,我将这两行代码置于“else”状态 这段代码在Login()里面

byte opcode = ClientInput.ReadByte (); Debug.Log( GetLoginMessage (opcode) ); }

这是有效的,因为如果值为 false,服务器会发送 opcode

一切正常!也许您应该为此通知其他人,因为我检查了视频并且您像我一样在其他条件之外得到它

【讨论】:

  • 在您的代码中甚至没有注意到这一点,但是是的,这会使所有内容都陷入循环。
猜你喜欢
  • 2019-03-06
  • 1970-01-01
  • 2021-11-26
  • 1970-01-01
  • 2018-08-04
  • 2021-01-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多