通过tcp发送值大于127的Java字符

通过tcp发送值大于127的Java字符,java,arrays,char,Java,Arrays,Char,你好 我有点麻烦。我正在尝试通过网络将字符数组发送到服务器 这是我的密码: char[] arr= {3,4}; public void sendMessage(String message){ if (out != null && !out.checkError()) { out.print(arr); out.flush(); } } 当我运行它时,lanshark检测到它接收到一个包含2字节数据的数据包。好的,一切都

你好

我有点麻烦。我正在尝试通过网络将字符数组发送到服务器

这是我的密码:

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);

谢谢

您没有告诉我们关于out的任何信息,甚至没有告诉我们类型,但我强烈怀疑它正在使用UTF-8对您的字符数据进行编码。U+00A0,即字符160在UTF-8中编码为0xc2 0xa0


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

您没有告诉我们关于out的任何信息,甚至没有告诉我们类型-但我强烈怀疑它使用UTF-8对您的字符数据进行编码。U+00A0,即字符160在UTF-8中编码为0xc2 0xa0


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

您可以按如下方式将数据作为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编码的字符数组,因此每个字符最多可发送8个字节,最大值为256。请参阅@JonSkeet的答案,了解您为什么需要UTF-8编码。

您可以按如下方式将数据作为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编码的字符数组,因此每个字符最多可发送8个字节,最大值为256。请参阅@JonSkeet的答案,以了解为什么需要UTF-8编码。

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

但实际上您要做的是发送2个字节

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

您正在犯的另一个错误是,您试图使用Writer发送基本上是二进制的数据。Writer接口用于16位面向字符的数据。您应该使用OutputStream API

无论如何。。。下面是一段代码片段,说明如何发送字节数组

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

我现在刚把它改成out.printnew-Stringarr.getBytesCharset.forNameUTF-8;这是我在wireshark上得到的数据:11字节:5b42403431653230396538应该还是2字节

你让事情变得更糟了

让我们把它拆开:

new Stringarr为您提供一个2个字符的字符串。 .getBytes。。。将其转换为包含字节03 c2 a0的3字节数组。 打印出来。。。将尝试调用PrintWriter API上的打印方法。 但是哪一个呢?您提供了一个声明类型为byte[]的参数。这将导致调用printObject

但是等一下。。。PrintWriter.printObject做什么?首先,它要做的是调用toString来处理这个参数

那又有什么用呢?由于对象是字节[],因此调用java.lang.object提供的默认toString方法。这会产生一个类似于B[@xxxxxxxx的字符串,其中[B是字节数组的类名,xs序列是数组对象标识哈希码的十六进制表示形式

然后输出该字符串


瞧,你的2个字节实际上已经变成了11个字节。

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

但实际上您要做的是发送2个字节

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

您正在犯的另一个错误是,您试图使用Writer发送基本上是二进制的数据。Writer接口用于16位面向字符的数据。您应该使用OutputStream API

无论如何。。。下面是一段代码片段,说明如何发送字节数组

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

我现在刚把它改成out.printnew-Stringarr.getBytesCharset.forNameUTF-8;这是我在wireshark上得到的数据:11字节:5b42403431653230396538应该还是2字节

你让事情变得更糟了

让我们把它拆开:

new Stringarr为您提供一个2个字符的字符串。 .getBytes。。。将其转换为包含字节03 c2 a0的3字节数组。 打印出来。。。将尝试调用PrintWriter API上的打印方法。 但是哪一个呢?您提供了一个声明类型为byte[]的参数。这将导致调用printObject

但是等一下。。。PrintWriter.printObject做什么?首先,它要做的是调用toString来处理这个参数

那又有什么用呢?由于对象是字节[],因此调用java.lang.object提供的默认toString方法。这会产生一个类似于B[@xxxxxxxx的字符串,其中[B是字节数组的类名,xs序列是数组对象标识哈希码的十六进制表示形式

然后输出该字符串


看看你的2个字节实际上已经变成了11个字节。

确保输入和输出采用相同的编码,那么你就会得到你想要的。例如

发出时:

接收时:


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

发出时:

接收时:


当您使用byte[]而不是char[]时会发生什么?当您使用byte[]而不是char[]时会发生什么我刚把它改成现在,out.printnew Stringarr.getBytesCharset.forNameUTF-8;这是我在wireshark上得到的数据:11字节:5b42403431653230396538应该还是2字节?我刚把它改成现在,out.printnew Stringarr.getBytesCharset.forNameUTF-8;这是我在wireshark上得到的数据:11字节:5b42403431653230396538应该还是2个字节?谢谢:byte[]arr=new byte[]{3,字节160;OutputStream out=socket.getOutputStream;out.writearr;好的,现在我已经让发送正常工作了,我只想在开始接收之前检查一下我是否在正确的轨道上。目前,我的输入包括一个'BufferedReader in;'和一个'in=new BufferedReadernew InputStreamReadersocket.getInputStream;'我该怎么办需要对此进行更改吗?是否需要改用inStream?只需将套接字输入流包装在BufferedInputStream中,并使用其中一种读取方法。例如:in=new BufferedReadernew InputStreamReadernew BufferedInputStreamsocket.getInputStream;?否。例如InputStream in=BufferedInputStreamsocket.getInputStream。它是非常简单。如果发送/接收字节,请不要将它们转换为字符。如果发送/接收字符,请不要将它们表示为字节数组。谢谢:byte[]arr=new byte[]{3,字节160;OutputStream out=socket.getOutputStream;out.writearr;好的,现在我已经让发送正常工作了,我只想在开始接收之前检查一下我是否在正确的轨道上。目前,我的输入包括一个'BufferedReader in;'和一个'in=new BufferedReadernew InputStreamReadersocket.getInputStream;'我该怎么办需要对此进行更改吗?是否需要改用inStream?只需将套接字输入流包装在BufferedInputStream中,并使用其中一种读取方法。例如:in=new BufferedReadernew InputStreamReadernew BufferedInputStreamsocket.getInputStream;?否。例如InputStream in=BufferedInputStreamsocket.getInputStream。它是非常简单。如果发送/接收字节,不要将它们转换为字符。如果发送/接收字符,不要将它们表示为字节数组。