【问题标题】:DataOutputStream and DataInputStream miscommunicationDataOutputStream 和 DataInputStream 通信错误
【发布时间】:2016-02-12 19:21:53
【问题描述】:

所以我有一个客户端/服务器游戏,每次客户端移动游戏输出到 DataOutputStream 并由 DataInputStream 接收时,第一条消息是一个连接消息,它告诉服务器用户名(此消息是正确接收),但所有后续消息都会出现偏差。

所以我在连接到服务器/客户端后像这样初始化流

private DataInputstream out = new DataOutputStream(socket.getOutputStream());

private DataInputStream in = new DataInputStream(socket.getInputStream());

向服务器发送消息的方法:

/**
 * Tells server someone has joined
 */
public void join(ViewProxy proxy, String session) throws IOException {
    out.writeByte('J');
    out.writeUTF(session);
    out.flush();
}

/**
 * tells server that a player took these numbers from a heap
 *
 * @param x the heap
 * @param y the number of items removed
 * @throws IOException
 */

@Override
public void placed(int id, int x, int y) throws IOException {
    out.writeByte('P');
    out.writeInt(id);
    out.writeInt(x);
    out.writeInt(y);
    out.flush();
}

/**
 * Tells server to start a new game
 *
 * @throws IOException
 */
@Override
public void newgame() throws IOException {
    out.writeByte('N');
    out.flush();
}

/**
 * Tells server to quit the game
 *
 * @throws IOException
 */
@Override
public void quit() throws IOException {
    out.writeByte('Q');
    out.flush();
}

最后服务器如何读取消息:

private class ReaderThread extends Thread {
    public void run() {
        try {
            for (;;) {
                String session;
                byte b = in.readByte();

                switch (b)
                {
                    case 'J':
                        session = in.readUTF();
                        System.out.println("Received J");
                        viewListener.join (ViewProxy.this, session);
                        break;
                    case 'P':
                        System.out.println("Received P");
                        int id = in.readInt();
                        int r = in.readInt();
                        int c = in.readInt();
                        viewListener.placed (id, r, c);
                        break;
                    case 'N':
                        System.out.println("Received N");
                        viewListener.newgame();
                        break;
                    case 'Q':
                        System.out.println("Received Q");
                        viewListener.quit();
                        break;
                    default:
                        System.err.println ("Bad message");
                        break;
                }
            }
        } catch (IOException exc) {
        } finally {
            try {
                socket.close();
            } catch (IOException exc) {
            }
        }
    }
}

当我运行服务器后跟客户端时,服务器接收到初始的“J”(来自 join 方法)并且一切运行顺利,但是每个后续消息我都会收到“错误消息”作为输出,这意味着服务器从未收到应该通过流发送的任何其他消息。

例如,当使用一些琐碎的参数调用放置的函数时,我会在控制台上打印 13 个“错误消息”副本。

所以我的问题是我错过了什么? DataOutputStream 是否发送了我想要的内容,我只是解释不正确,还是发生了更复杂的事情。

在弄乱程序后,我删除了刷新语句。我还打印了客户端发送的内容和服务器看到的内容。客户端正在发送正确的东西,但服务器似乎无法接收到它们。相反,它看到 7 个零(空)。 1 表示字母“P”,6 表示更多,我认为这三个整数。

我还包括一个指向我的 github 的链接,用于访问完整代码(位于 src 文件夹中): https://github.com/michaelrinos/Connect-Fout-Client-Server/tree/TCP

modelproxy 类的输出(客户端):

Writting J and "john1" <Byte> <UTF>
Sending: 0<Byte>  0<Byte> 5<Byte>

第二个modelproxy类的输出(客户端):

Writting J and "john2" <Byte> <UTF>

viewproxy 类的输出(服务器端):

Received J and john1
Received J and john2
0
Bad message
0
Bad message
0
Bad message
5
Bad message

您可以看到虽然数字是正确的,但我丢失了前导字符。

【问题讨论】:

  • 我建议你打印你得到的字节。它可以为您提供有关问题所在的线索。
  • 嗯,我尝试的一件事是移除开关盒并打印出所有读入的字节,即使这样我也会得到不同的输出,根据客户端应该发送的是:(74( 'J'), ASCII 二进制文件中的玩家名, 80 ('P'), 0, 0, 10) 另一方面服务器接收 (74 ('J'), client1, 74 ('J'), client2, 0 , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2)
  • 如果客户端收到client1client2 你一定是发送了这些,因为没有一个简单的错误会想出这样的真实数据。
  • Java char 是 16 位(不是 8 位)。
  • @ElliottFrisch 是的,我明白你的意思,但 DataOutputStream 的重点是它支持通过首先对它们进行二进制编码、发送它们,然后通过 DataInputStream 解码它们的过程来发送 java 原语。同样在我使用 UDP 和 DataOutputStream 编写的代码的类似版本中,客户端发送相同的消息 out.writeByte('P') 并且服务器能够成功接收消息

标签: sockets java-8 datainputstream dataoutputstream


【解决方案1】:

这不可能是真正的代码。否则,您将收到“J”、0x00、0x07、“player1”等,其中 0x0007 是由writeUTF(). 放置在那里的长度前缀确保您使用readUTF() 阅读的所有内容都是用writeUTF(). 编写的 您也可能是向此处未显示的流写入其他内容。

需要单独捕捉EOFException,捕捉时跳出读循环;你也不要忽视IOExceptions.

DataOutputStream.flush() 什么都不做,除非下面有一个缓冲流,在这种情况下没有。

【讨论】:

    猜你喜欢
    • 2013-03-12
    • 2013-09-03
    • 2012-03-23
    • 1970-01-01
    • 2012-02-13
    • 2018-03-09
    • 1970-01-01
    • 2014-06-04
    • 2017-12-31
    相关资源
    最近更新 更多