2012-10-26 20 views
3

我试图通过套接字连接的C应用程序,期望某个头和数据体,但是,当我试图遵守该格式时出现一堆问题,它应该是这样的:JAVA - 使用自定义套接字协议

头:
- 2个字节的数据包开始。
- 4个字节,表示数据包大小加头。
- 数据包类型为1个字节。

正文:
- 4个字节表示params的数量。

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

这里是服务器期待的示例:

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

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

从我正在调查它似乎倒序,所以他们得到正确的字节,但在错误的顺序。

现在我想实现如下:

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

请包括代码的关键部分 – amphibient

+5

您应该使用发送* bytes *的原始'OutputStream',而不是字符或序列化对象。 –

+1

听起来好像有人正在使用“文本”编辑器:)使用像wireshark这样的工具来查看单线数据,以确保有关发送内容的假设是正确的。 – 2012-10-26 18:50:23

回答

2

托马斯是,当然,大约使用直接和的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十六进制)。同样你需要几个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十六进制)时,则需要(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

而且我已经包括了一个自定义的小端INT编组(myWriteInt),但还有其他方法 - 例如使用临时ByteBuffer设置为小端模式。

希望这会有所帮助。

+0

这真的很有帮助,非常感谢你的时间和很大的帮助! – bassprodukt