【问题标题】:Java Character with value greater than 127 sending via tcp值大于 127 的 Java 字符通过 tcp 发送
【发布时间】:2013-01-30 12:58:19
【问题描述】:

早安,

我遇到了一些麻烦。我正在尝试通过网络将字符数组发送到服务器。

这是我的代码:

char[] arr= {3,4};    
public void sendMessage(String message){
    if (out != null && !out.checkError()) {
        out.print(arr);
        out.flush();
    }
}

当我运行它时,lanshark 检测到它收到了一个包含 2 个字节数据的数据包。好的,一切都很好。

现在当我运行这个时:

 char[] arr= {3,160};      // notice 160 *****
public void sendMessage(String message){
    if (out != null && !out.checkError()) {
        out.print(arr);
        out.flush();
    }
}

lanshark 说这个包有 3 个字节的数据?确切的数据是:

03 c2 a0

现在为什么要在其中添加 c2?我知道这与我的 char 大于 127 的事实有关。但我需要发送这个 160 的值。

请你帮帮我。我需要使用其他类型的数据,还是以不同的方式发送?我知道你可以在 C 中做到这一点。我如何在 java 中做到这一点?

这是我的输出对象的代码:

PrintWriter out;
out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);

谢谢

【问题讨论】:

  • 当你使用 byte[] 而不是 char[] 会发生什么?

标签: java arrays char


【解决方案1】:

事实上,程序正在按照您的要求执行。它正在发送两个字符;即 unicode 代码点 3 (\u0003) 和 160 (\u00a0)。这些字符正在使用您平台的默认字符编码进行编码......这似乎是 UTF-8。字节 c2 a0\u00a0 字符的 UTF-8 编码。

但你实际上想要做的是发送 2 个字节。

在 Java 中,char 是 16 位类型,而不是 8 位类型。如果要发送 8 位值,则需要使用 byte 类型。

您犯的另一个错误是您尝试使用Writer 发送(本质上)二进制数据。 Writer 接口用于(16 位)面向字符的数据。你应该使用OutputStream API ...

无论如何...这里有一个代码 sn-p 来说明您应该如何发送字节数组;

byte[] arr = new byte[]{3, (byte) 160);
OutputStream out = socket.getOutputStream();
out.write(arr);

我现在刚刚将其更改为“out.print(new String(arr).getBytes(Charset.forName("UTF-8")));”这是我在wireshark上获得的数据:11字节: 5b42403431653230396538 它应该还是 2 个字节?

你让事情变得更糟了!

让我们分开:

  • new String(arr) 为您提供 2 个字符的字符串。
  • .getBytes(...) 将把它变成一个包含 03 c2 a0 字节的 3 字节数组。
  • out.print(...) 将尝试在 PrintWriter API 上调用 print 方法。

但是哪一个?好吧,您提供了一个声明类型为byte[] 的参数。这将导致您致电print(Object)

但是等一下……PrintWriter.print(Object) 是做什么的?嗯,第一件事就是在参数上调用toString()

那有什么作用?好吧,既然对象是byte[],这将调用java.lang.Object 提供的默认toString() 方法。这会给你一个看起来像B[@xxxxxxxx 的字符串,其中[B 是字节数组的“类名”,xs 的序列是数组对象标识哈希码的十六进制表示!

然后你输出那个那个字符串。

你的 2 个字节(实际上是字符)变成了 11 个字节。

【讨论】:

  • 谢谢:byte[] arr = new byte[]{3, (byte) 160);输出流输出 = socket.getOutputStream(); out.write(arr);
  • 好的,现在我的发送工作正常,我只是想在开始接收之前检查我是否在正确的轨道上。目前,我的输入包括一个“BufferedReader in;”和一个 'in = new BufferedReader(new InputStreamReader(socket.getInputStream())); '我需要对此进行哪些更改?我需要改用 inStream 吗?
  • 只需将套接字输入流包装在 BufferedInputStream 中,并使用read 方法之一。
  • 像这样:in = new BufferedReader(new InputStreamReader(new BufferedInputStream(socket.getInputStream()))); ?
  • 没有。喜欢这个InputStream in = BufferedInputStream(socket.getInputStream())。这真的很简单。如果您正在发送/接收字节,请不要将它们变成字符。如果您正在发送/接收字符,请不要将它们表示为字节数组。
【解决方案2】:

你没有告诉我们任何关于out 的事情——甚至没有告诉我们类型——但我强烈怀疑它使用 UTF-8 来编码你的字符数据。 U+00A0(即字符 160)在 UTF-8 中编码为 0xc2 0xa0。

几乎可以肯定,如果您同时控制读写代码,则使用 UTF-8 是最好的:这意味着您可以使用整个 Unicode。如果您使用 ISO-8859-1(这是我怀疑您希望使用的 - 对于所有字符,每个字符一个字节),您将自己限制在范围 [U+0000, U+00FF]。

【讨论】:

    【解决方案3】:

    您可以按照以下方式将数据发送为“UTF-8”:

    out.print(new String(arr).getBytes(Charset.forName("UTF-8"));
    

    您还必须使用 UTF-8 编码创建输出流,如下所示:

    out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), "UTF-8")), true);
    

    现在您将发送使用 UTF-8 编码的 char 数组,因此每个字符最多 8 个字节(最大值为 256)。查看@JonSkeet 的回答,了解为什么需要“UTF-8”编码。

    【讨论】:

    • 我现在只是将其更改为“out.print(new String(arr).getBytes(Charset.forName("UTF-8")));”这是我得到的数据在wireshark上:11个字节:5b42403431653230396538它应该还是2个字节?
    【解决方案4】:

    确保输入和输出使用相同的编码,然后您将得到您想要的。例如,

    外出发送时

     mPrintWriterClient = new PrintWriter(new BufferedWriter(new    OutputStreamWriter(mSocket.getOutputStream(), "UTF-8")), true);     
    

    接收时

     mBufferedReaderClient = new BufferedReader(new InputStreamReader(mSocket.getInputStream(), "UTF-8"));
    

    【讨论】:

      猜你喜欢
      • 2014-01-01
      • 1970-01-01
      • 2013-06-28
      • 1970-01-01
      • 2020-02-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-27
      相关资源
      最近更新 更多