我正在尝试通过套接字与需要某个标头和数据体的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());
}
你可以帮帮我吗?
提前多多感谢!
答案 0 :(得分:2)
当然,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)
需要时,将产生4个字节 - 0 0 0 26(或00 00 00 1A hex)(1A 00 00 00)。你明白了。这不会起作用。
以下是一些示例代码,展示了如何解决这些问题,方法是放弃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模式。
希望这有帮助。