繁体   English   中英

JAVA - 使用自定义套接字协议

[英]JAVA - Working with a custom socket protocol

我正在尝试通过套接字连接一个C应用程序,它需要一个特定的头和数据体,但是,当我尝试遵循这种格式时,我遇到了一堆问题,它应该是这样的:

标题:
- 数据包启动的2个字节。
- 4个字节,表示数据包大小加头。
- 数据包类型为1个字节。

身体:
- 4个字节,表示参数的数量。

每个参数的以下一个块:
- 参数经度为4个字节。
- 消息内容的X字节。
- 转义字符为1个字节。

以下是服务器期望的示例:

[%%] [13 00 00 00] [0] [12 00 00 00] [0 00 00 00 00] [OPERATIONPERFORMED \\ 0]

我遇到的问题是,当尝试通过PrintWriter发送信息时,另一端将十六进制值作为ASCII字符而不是实际值。 我已经尝试过使用ByteBuffer,DataOutputStream和几个选项,但他们仍然以这种格式出现甚至更奇怪。

从我正在研究的东西来看,似乎是endian被反转,所以它们得到正确的字节,但顺序错误。

我现在正在尝试的实现如下:

  DataOutputStream stream = new DataOutputStream(socket.getOutputStream());
    PrintWriter writer = new PrintWriter(socket.getOutputStream()); 

    BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));

    // Header
    stream.writeChar(37);
    stream.writeChar(37); 
    stream.writeInt(26);
    stream.writeChar('\\0');

    stream.writeInt(1);
    stream.writeInt(11);

    stream.writeUTF("SET_PROBLE\\0");


    stream.flush();

    StringBuilder sb = new StringBuilder();

    boolean state = true;

    while (state) {
        if (in.ready()) {
            sb.append((char) in.read());
        }
        else {
            if (sb.length() > 0) {
                state = false;
            }
        }
    }

    System.out.println(sb.toString().trim());

}

你能帮我吗?

非常感谢提前!

当然,Tomasz直接使用OutputStream并发送字节是正确的。 我想扩展这一点,并说明为什么这是真的。

我们来看看服务器所期望的字节数。 首先,您需要两个字节,每个值37(ascii %%)。 DataOutputStream.writeChar不会给你那个。 正如文档明确指出的那样,它将Writes a char to the underlying output stream as a 2-byte value, high byte first.

stream.writeChar(37);
stream.writeChar(37);

将产生4个字节:0 37 0 37(或00 25 00 25 hex)。 类似地,您需要几个4字节整数。 请注意,根据您的服务器示例,这些整数以小端模式(低字节优先)序列化。 所以DataOutputStream.writeInt不会有帮助,因为它将Writes an int to the underlying output stream as four bytes, high byte first

stream.writeInt(26)

在需要时(1A 00 00 00)将产生4个字节 - 0 0 0 26(或00 00 00 1A hex)。 你明白了。 这不会起作用。

下面是一些示例代码,展示了如何解决这些问题,方法是放弃DataOutputStream并直接使用OutputStream。

public static void myWriteInt(OutputStream out, int value) throws IOException
{
    out.write(value % 0xff);
    out.write( (value >> 8) % 0xff);
    out.write((value >> 16) % 0xff);
    out.write((value >> 24) % 0xff);

}
public static void main(String[] args) throws Exception
{

    ByteArrayOutputStream out = new ByteArrayOutputStream();
    // Replace with
    // OutputStream out = socket.getOutputStream()

    out.write((byte) 37);
    out.write((byte) 37);

    myWriteInt(out, 26);
    out.write((byte) 0);

    myWriteInt(out, 1);
    myWriteInt(out, 11);

    out.write("SET_PROBLE\0".getBytes("UTF-8"));

    System.out.println(DatatypeConverter.printHexBinary(out.toByteArray()));

为了避免处理套接字,我正在写ByteArrayOutputStream,因此我们可以打印出十六进制值并显示它符合您的要求。 只需替换套接字输出流即可。

此代码打印出以下内容(为了清晰起见,我添加了一些空格)

2525 1A000000 00 01000000 0B000000 5345545F50524F424C4500

最后一个块是SET_PROBLE,后跟一个0。

我还包括一个自定义的little-endian int marshaller(myWriteInt),但还有其他方法 - 比如使用临时ByteBuffer设置为little endian模式。

希望这可以帮助。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM