【问题标题】:read bits and not int from a socket从套接字读取位而不是 int
【发布时间】:2009-06-25 15:19:05
【问题描述】:

第三方程序允许我从他的 ip:port 询问数据。我通过这个经典代码询问这些东西。这是我的连接类的构造函数:

public TcpConnection(String adress, Integer port) {
    this.adress = adress;
    this.port = port;
    try {
        socket = new Socket(adress, port);
    System.out.println("Opening connection");
        out = new PrintWriter(socket.getOutputStream(), true);
        InputStream r = new DataInputStream(socket.getInputStream());
        in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    } catch (UnknownHostException e) {
        // TODO: handle exception
    } catch (IOException e) {
        e.printStackTrace();
    }
}

然后我在 while 循环中使用 in.read() 读取我的套接字。

它允许我通过 int 读取套接字 int,但我需要更精细的粒度。 (答案中的一些信息以 2 个字节编码,一些以位编码,一些以 64 个字节编码......)。所以我需要读 2 个字节,然后读一点。然后是另一个位,然后是 1 个字节并检查该字节的每一位。

首先我在想:“好吧,我将得到的 int 转换为字符串二进制表示”, (通过Integer.toBinaryString(whatIget)) 但它只是愚蠢且容易出错。

我确定我缺少一些东西来解决这个偶然的问题。 有什么想法吗?

Edit2:我删除了“当我读取 int 时,我读取 32 位(4 个字节)”,因为这是错误的,而不是问题的重点。因此,Reader.read() 读取的是一个 int,如果这个方法只读取一个字节,她正在读取一个 1/4 int ??!?

【问题讨论】:

  • 编辑:我想读一点。 0 或 1。不是 byte 或 int 或其他花哨的类型。我需要它,因为我读取的流中的某些位是标志(例如:第一个字节的第三位表示投影仪是否打开。第二个如果投影仪正在运行,第一个如果 ...)

标签: java sockets


【解决方案1】:

没有。 read() 一次读取 8 位 / 1 个字节。

如果您进一步使用 DataInputStream 类型的引用,您可以从 DataInputStream 获取字节、字、int、long、utf-8 字符串等。有

DataInputStream r = new DataInputStream(socket.getInputStream());
r.readLong();
r.readShort();

而不是

InputStream r = new DataInputStream(socket.getInputStream());

但是,对于单词而言,int 和 long 数据的“字节序”很重要。 DataInputStream 以大端格式组合字节,而您的数据可能采用小端格式。从 DIS 读取后,您可能需要交换 short/int/long 中的字节。这就是Integer.reverseBytes() 和它的朋友们派上用场的地方。

如果您需要位大小的数据检索(例如读取 6 位、4 位、12 位等),您可能需要查看this recent question 的答案。

编辑:删除了 8 位,因为它在这种情况下具有误导性。

编辑 2:改写我的第三句话。

【讨论】:

  • DataInputStream 是唯一干净的解决方案,恕我直言。
  • 感谢您提供指向最近问题的链接。这完全是我想要的,读取数字,有时它们在 1 个字节上。有时是 1 个字节,有时是 8 个字节(不要问为什么......遗留系统,不能修改任何东西)
  • 困难是:我读到“3”,二进制是 11,但我应该添加 6 个零(00000011)或更多(例如 0000000000000011)。现在我不能一点一点地阅读,这很容易。
  • 最后一个问题,我去睡觉了,如何检测比特流的“字节序”?
  • 我认为你需要观察比特流和你提取的值。例如,位流包含 011,它可能表示 3(msb-lsb 方向)或表示 6(lsb-msb 方向)。
【解决方案2】:

你不能只读一点:socket/TCP/IP 以字节为最小单位。
您必须读取包含该位的字节并使用一些位移/掩码来获取一位的值:

int byte = r.read();
boolean bit1 = (byte && 0x01) != 0;  // first bit (least significatn)
boolean bit2 = (byte && 0x02) != 0;  // second bit
boolean bit3 = (byte && 0x04) != 0;  // thrid bit
...

【讨论】:

    【解决方案3】:

    您可以通过 int 读取 int 并通过以下方式提取信息 位运算符

    【讨论】:

    • Riiight。我完全忘记了。我会读一个字节。然后用掩码将其炸成 8 位。有更好的方法吗?
    【解决方案4】:

    您应该使用BufferedInputStream 进行阅读。 BufferedReader 用于文本数据。

    read() 一次读取一个字节。

    您不必担心。

    read() 的每次调用都将返回一个字节。

    对于InputStream,请参阅Javadocsread() 方法。

    从输入流中读取下一个字节的数据。

    【讨论】:

      【解决方案5】:

      您不应该对此类数据使用 Reader(您有 BufferedReader)。从 DataInputStream(您已经使用)中,您可以获得 Bytes、Ints 或许多其他类型(使用名为 readByte 等的方法)。您无法获得单个位,流中的数据始终至少是一个字节。这对 Java 没有特别的限制,在其他语言中,您也被限制从 Sockets 文件中读取至少字节。如果您需要其中的单个位,则需要进行逻辑操作以从已读取的字节中提取它们。

      【讨论】:

      • 谢谢,您的回复非常完美。我选择 kd304 而不是你,因为他提供了另一个线程的甜蜜链接。
      【解决方案6】:

      您无法从InputStream 中读取单个位。这是不可能的,您可以在API definition of InputStream.read() 中看到。

      因此,将答案封装在DataInputStream 中,您将从中读出每一条信息,就像 kd304 提供的那样。

      【讨论】:

      • 也许他想在数据检索期间解码字符串。
      猜你喜欢
      • 2021-12-14
      • 2023-03-15
      • 1970-01-01
      • 2011-10-29
      • 1970-01-01
      • 1970-01-01
      • 2019-04-02
      • 2013-10-12
      相关资源
      最近更新 更多