【问题标题】:Inputstream readUTF can't read UTF输入流 readUTF 无法读取 UTF
【发布时间】:2015-03-22 09:01:27
【问题描述】:

我是 Java 的菜鸟,如果这是一个菜鸟的错误,我深表歉意。 我正在尝试 Java NIO,但我还没有到使用非阻塞特性的阶段。我只是无法让服务器读取字符串,我知道从一侧发送 Bytebuffer 并试图在另一侧将其解释为 String 并不容易,但我仍然不知道我要去哪里错误的。这是代码

**********************************服务器端**************** ************************

class MyBlockingServer extends Thread
{
    private int M_PortNumber;
    private ServerSocket M_ServerSocket;

    MyBlockingServer(int PortNumber)
    {
        M_PortNumber = PortNumber;
        try {
            M_ServerSocket = new ServerSocket(M_PortNumber);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public void run()
    {
        int my_number = 0;
        while(true)
        {
            try {
                Socket Server = M_ServerSocket.accept();


                DataInputStream inputStream = new DataInputStream(Server.getInputStream());
                System.out.println("[SERVER]" +inputStream.readUTF());


                DataOutputStream outputStream = new DataOutputStream(Server.getOutputStream());
                outputStream.writeUTF("Thanks for connection, you suck tata" + " "+ my_number);

                my_number++;
                Server.close();

            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

    void socket_close()
    {
        try {
            M_ServerSocket.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}

public class JavaBlocking
{

    public static void main(String []args)
    {
        MyBlockingServer Server = new MyBlockingServer(8000);
        try {
            Server.start();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }
}

************************************客户端****************** *******************

public class JavaChannels 
{

    public static void main(String []args)
    {
        SocketChannel client_channel = null;

        try {
            client_channel = SocketChannel.open();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        System.out.println("[Client] Socket channel open");

        try {
            client_channel.connect(new InetSocketAddress("127.0.0.1",8000));
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        System.out.println("[Client] Socket channel connected");

        ByteBuffer my_buffer = ByteBuffer.allocate(48);
        my_buffer.clear();

        try {
            my_buffer.put("WHY_YOU_NO_WORK".getBytes("UTF-8"));
        } catch (UnsupportedEncodingException e2) {
            // TODO Auto-generated catch block
            e2.printStackTrace();
        }

        my_buffer.flip();

        try {
            int bytes_written = client_channel.write(my_buffer);

            while(my_buffer.hasRemaining())
            {
                bytes_written = client_channel.write(my_buffer);
            }

            System.out.println("[Client] Wrote "+ bytes_written +" bytes");
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        System.out.println("[Client] Socket channel write finished");

        my_buffer.clear();
        my_buffer.flip();


        try {
            client_channel.read(my_buffer);
        } catch (IOException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }

        System.out.println("[Client] server says" + new String(my_buffer.array()));

        try {
            client_channel.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }


}

我不断收到的错误是

java.io.EOFException 在 java.io.DataInputStream.readFully(DataInputStream.java:197) 在 java.io.DataInputStream.readUTF(DataInputStream.java:609) 在 java.io.DataInputStream.readUTF(DataInputStream.java:564) 在 netty_tutorial.blocking.MyBlockingServer.run(JavaBlocking.java:39)

这以某种方式向我表明 readUTF 不是在读取 UTF 格式,而是在读取其他格式。

总之我在做的是

服务器 --> 读取UTF

Client --> String --> UTF-8 字节数组 --> ByteBuffer -->Write

因为我将字节数组显式编码为 UTF-8。为什么readUTF读不出来?

【问题讨论】:

  • 如果使用readUTF,对方必须使用writeUTF。除非您研究这种特殊的格式并遵循小字:两个字节长度,然后是字符等,但没有真正转换为 UTF-8(尽管如果您的 unicode 字符不是很古怪,这可能不会导致任何问题。 )
  • ByteBuffer 实际上没有 writeUTF 方法,有什么解决方法吗?
  • DataOutputStream 有。
  • 我会试试的。我仍然不清楚为什么它会失败,如果将字符串转换为编码为 UTF-8 的字节缓冲区,readUTF 不应该工作吗?
  • 长度,前面短。

标签: java sockets nio eofexception


【解决方案1】:

DataInput.readUTF 方法 读取 UTF-8 编码的字符串,它以 DataOutput.writeUTF 创建的特定格式读取数据,这与真正的 UTF 相似但不同-8:

  • 它以一个 16 位无符号整数开头,给出构成字符串的后续字节数
  • 以下这些字节是UTF-8的修改形式,其中U+0000用两个字节而不是1表示(所以字符串的二进制表示不能包含任何0字节),U+FFFF以上的补充字符表示作为代理对,高代理和低代理分别以 3 个字节编码为 UTF-8(真正的 UTF-8 将使用总共 4 个字节一次性编码整个补充代码点)。

如果你写的是真正的 UTF-8,那么你需要阅读真正的 UTF-8,如果你想readUTF,那么你必须writeUTF

如果您想将writeUTF 转换为ByteBuffer,那么在缓冲区周围实现OutputStream 包装器非常简单,您可以反过来将其包装在DataOutputStream 中:

class ByteBufferBackedOutputStream extends OutputStream{
  ByteBuffer buf;
  ByteBufferBackedOutputStream( ByteBuffer buf){
    this.buf = buf;
  }
  public synchronized void write(int b) throws IOException {
    buf.put((byte) b);
  }

  public synchronized void write(byte[] bytes, int off, int len) throws IOException {
    buf.put(bytes, off, len);
  }

}

(source)

【讨论】:

  • 谢谢,您的解释对我来说是最有意义的。不知何故,函数的名称并没有表明这一点:)。
  • 这不是你必须使用DataOutputStream.writeUTF的情况,有很多你可以解决这个问题,我在我的答案中包含了最简单的。
  • @PeterLawrey 只要您不使用任何补充字符,就可以。
  • @IanRoberts,将 readUTF 更改为读取。将生成的字节数组转换为字符串,现在可以工作了。谢谢
  • 如果您使用 UTF-8 编码编写补充字符,readUTF 将正确解码它们。如果您使用 DataOutputStream.writeUTF 编写补充字符,它们将不是有效的 UTF-8。
【解决方案2】:

您需要编写 DataInputStream 期望的格式。

例如

public static void writeUTF(ByteBuffer bb, String text) {
    byte[] bytes = text.getBytes("UTF-8");
    if (bytes.length > 1 << 16)
        throw new IllegalArgumentException();
    bb.putShort((short) bytes.length);
    bb.write(bytes);
}

注意:虽然 writeUTF 会将 \0 写入两个字节而不是一个字节,但 readUTF 将接受它作为 1 或 2 个字节。

【讨论】:

    猜你喜欢
    • 2022-01-11
    • 1970-01-01
    • 1970-01-01
    • 2023-04-04
    • 2015-12-23
    • 2014-12-13
    • 1970-01-01
    • 2012-03-12
    相关资源
    最近更新 更多