【问题标题】:Unable to read socket response C server to Java client无法读取套接字响应 C 服务器到 Java 客户端
【发布时间】:2017-02-11 09:00:20
【问题描述】:

我在包括这里在内的所有地方搜索了可能的解决方案,并尝试了一些我找到的答案,但没有成功。

我实现了一个简单的 Java tcp 套接字客户端。客户端在一台 Java 服务器上工作得非常好,但我一直在接收来自用 C 编码的服务器的响应时遇到问题。 服务器似乎正在正确处理事务,并相应地发送回复。问题在于客户端能够接收回复的传入流。 这是我最初的实现:

        String msg_out = message;
        String reply;

        //the stream object to transmit message to server
        DataOutputStream outStream = new DataOutputStream(clientSocket.getOutputStream());

        outStream.writeBytes(msg_out + '\n');
        outStream.flush();

        //try to break away from locked read 
        //clientSocket.setSoTimeout(10000);

        //initial implementation
        //the object to receive reply server
        BufferedReader replyStream = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
        reply = replyStream.readLine();

        System.out.println("Reply from "+ host + ":" + port + " -> " + reply);

我下载了 Wireshark 并用它来监视服务器套接字正在侦听的相应端口中客户端和服务器之间的 tcp 数据包流量。我在其他主题类似的主题中看到了多个建议,不幸的是,我无法找到任何适合我的解决方案。我发现包含回复的数据包的标志值设置为 PSH(接收时不缓冲蒸汽,立即处理)。我认为Java客户端通过尝试缓冲回复导致连接重置(RST出现在失败数据包中,这是下一个发生的),因为这个标志。我尝试使用我在此处的线程中发现的此实现进行测试,尝试逐字节读取回复但无济于事:

  try {
            DataInputStream in = new  DataInputStream(clientSocket.getInputStream());
            int bytesRead = 0;
            byte[] messageByte = new byte[1000];
            boolean end = false;
            String messageString = "";
            messageByte[0] = in.readByte();
            messageByte[1] = in.readByte();
            ByteBuffer byteBuffer = ByteBuffer.wrap(messageByte, 0, 2);

            int bytesToRead = byteBuffer.getShort();
            System.out.println("About to read " + bytesToRead + " octets");

            //The following code shows in detail how to read from a TCP socket

            while(!end)
            {
                bytesRead = in.read(messageByte);
                messageString += new String(messageByte, 0, bytesRead);
                if (messageString.length() == bytesToRead )
                {
                    end = true;
                }
            }


            System.out.println("Server Reply: " + messageString);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

我无权访问 C 服务器的源代码,但它的开发人员向我发誓,问题不在于他,我相信他。我也知道他不能对它进行更改,因为它可以与使用的所有其他客户端架构一起工作,我正在编写的代码恰好是唯一与这个基于 C 的服务器交互的 Java 客户端。我的实现是否有错误,或者我可以使用其他实现以更简单的方式读取回复流?

这是尝试运行客户端/服务器通信进程的结果:

[2/10/17 14:23:49:658 EST] 00000031 SystemOut     O Outgoing transaction message:C00052!GDT43000KU!01!D-10!G-11!NORMAL!|                   
[2/10/17 14:23:49:658 EST] 0000011e SystemOut     O Buffersize in stream:8192
[2/10/17 14:23:49:737 EST] 0000011e SystemOut     O About to read 12336 octets
[2/10/17 14:23:49:737 EST] 0000011e SystemErr     R java.net.SocketException: Connection reset
[2/10/17 14:23:49:737 EST] 0000011e SystemErr     R     at java.lang.Throwable.<init>(Throwable.java:67)
[2/10/17 14:23:49:737 EST] 0000011e SystemErr     R     at java.net.SocketInputStream.read(SocketInputStream.java:118)
[2/10/17 14:23:49:737 EST] 0000011e SystemErr     R     at java.io.DataInputStream.read(DataInputStream.java:94)
[2/10/17 14:23:49:737 EST] 0000011e SystemErr     R     at com.gf.btv.RTDLTSS.domain.LTSSClient.TCPClientRequest(LTSSClient.java:141)
[2/10/17 14:23:49:737 EST] 0000011e SystemErr     R     at com.gf.btv.RTDLTSS.helper.LTSSClientThread.run(LTSSClientThread.java:147)
[2/10/17 14:23:49:737 EST] 0000011e SystemErr     R     at java.lang.Thread.run(Thread.java:736)

【问题讨论】:

  • 您确定他们使用 Big Endian 发送吗?一些 C 程序假定小端,
  • 当您尝试运行客户端时实际发生了什么
  • 服务器使用什么协议进行回复?它是在字节级别记录的吗?如果您不知道服务器期望它做什么,您怎么可能知道您的客户端是否在做正确的事情? (您有协议文档吗?或者您需要对协议进行逆向工程吗?如果您有协议文档,请分享。如果您需要对协议进行逆向工程,请向我们展示服务器发送给您的字节,以便我们尝试帮助您这样做。)
  • (RST 发生是因为您没有遵循服务器期望您遵循的协议,读取的数据少于发送的数据。)
  • 回答彼得的问题,这是我首先关心的问题之一,但服务器的开发人员说字节序应该是正确的。此外,我们有相反的沟通方式。我有一个 Java 服务器,他有一个运行相同协议的 C 客户端,这非常有效。我能够阅读和解析他的请求,我可以发送他得到的回复。我假设协议中是否存在一些不兼容,如果我的 Java 应用程序尝试从 C 应用程序读取传入流,则另一种方式的通信会在连接被重置时遇到类似的问题。

标签: java sockets tcpclient tcpserver


【解决方案1】:

RST 与 PSH 或缓冲读取器没有任何关系,但如果您需要读取二进制文件,则读取器不合适。 RST 表示对等方在您读取连接之前关闭了连接,这强烈表明您使用了错误的协议。请求协议是基于行的,但响应协议是基于长度字前缀的,这是不可信的。一个或另一个,或者别的什么。

如果你确定它确实是一个长度字前缀协议,试试这个:

int messageLength = in.readShort();
byte messageBytes = new byte[messageLength];
in.readFully(messageBytes);
// etc.

但您需要确认实际协议。猜测不会让你到达那里。

【讨论】:

  • 我会再次询问以确保我们知道字节序,但我真的认为问题不在于这个。
  • 您应该再次询问以确保您了解协议。您已经在此处使用了两个,而且两者都不太可能是正确的。很可能都不是正确的。
  • 我注意到假定的“短”(2 字节 int)值是 12336,这是两个字节的值,每个字节都包含 ASCII 字符“0”。我怀疑服务器实际上是以字符形式发送长度或其他值。
  • 对不起,我还在努力解决这个问题。 dave_thomson 似乎在做某事。所以字节序是大字节序(只是为了踢球,我尝试改变接收端的字节序但没有成功),就交换的消息结构而言,是的,协议是基于长度-字前缀的。流的长度在它的开头。我做了从字节到整数的转换,这并没有导致连接被重置,所以它更进一步,现在我正在处理 java.lang.StringIndexOutOfBoundsException,现在正在处理那个。
猜你喜欢
  • 2012-05-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-23
  • 2012-06-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多