在无符号字节变量中表示有符号字节

时间:2014-10-11 20:26:19

标签: java c# sockets byte

如果这个问题的标题不清楚,我道歉,但我无法找出用这么少的话来描述我的困境的最好方法。

我正在使用套接字和逐字节传输信息在java和C#之间编写一个通信框架。

我遇到了一个让我困惑好几个小时的问题。正如你所希望的那样。 java的字节基类型是有符号的,这意味着如果你以整数形式表示它,它可以存储-128到+127。但是,C#使用无符号字节,这意味着它以整数形式存储0-255。

这是我遇到问题的地方。如果需要从我的c#客户端向我的java服务器发送一些字节的信息,我使用以下代码:

C#:

MemoryStream stream;

public void write(byte[] b, int off, int len) {
    stream.Write(b, off, len);
}

爪哇:

DataInputStream in;

public int read(byte[] b, int off, int len) throws IOException{
    in.read(b, off, len));
}

正如您所看到的,这些代码非常相似,在其自己的语言中使用时会产生可预测的结果。但是,由于签名的不同,这些将产生无法使用的数据。

即如果我从我的c#客户端发送255到java服务器,我将在java服务器上收到值-1。这是因为这两个值都由这8位表示:11111111

最好为了解决这个问题,我需要使用以下代码,使用sbyte,c#的有符号字节。

C#:

MemoryStream stream;

public void write(sbyte[] b, int off, int len) {

    //Code to change sbyte into a byte but keeping it in the form in which java will understand

    stream.Write(b, off, len);
}

我基本上需要在无符号C#字节内存储java的有符号字节表示,以便将该字节发送到服务器。我还需要反向执行此操作以从我的java服务器接收到的字节中获取sbyte。

我尝试了很多方法,但没有成功。如果有人知道我怎么能这样做,我将非常感激。

1 个答案:

答案 0 :(得分:5)

除了停止将字节视为数字之外,您基本上不需要做任何事情。将它们视为8位,Java和C#是相同的。很少有人真的想把一个字节视为一个数字 - 它通常只是二进制数据,如图像,或者可能是编码文本。

如果要将字节10100011从Java发送到C#,反之亦然,只需以最自然的方式进行。这些位是正确的,即使将它们视为数字时字节值也会不同。

您实际尝试传播的数据并不完全清楚,但在99.9%的情况下,您可以将byte[]视为不透明的二进制数据,并传输它而不必担心。

如果你需要将字节视为大小,你需要计算出你想要的范围。处理Java范围更容易,因为C#可以使用sbyte[]支持它...但是如果你想要范围0-255,你只需要转换byte到Java端的int并用底部的8位掩盖它:

byte b = ...;
int unsigned = b & 0xff;

如果你真的需要在C#上将byte[]视为sbyte[],反之亦然,你可以使用一点秘密:即使C#不允许你在两者之间进行转换,CLR也可以。您需要做的就是通过将引用转换为object来欺骗C#编译器,使其认为可能有效 - 否则它认为它最清楚。所以这没有例外地执行:

byte[] x = new byte[] { 255 };
sbyte[] y = (sbyte[]) (object) x;
Console.WriteLine(y[0]); // -1

您可以以完全相同的方式转换到另一个方向。