【问题标题】:How can a server know when the message it receives is actally over?服务器如何知道它收到的消息实际上何时结束?
【发布时间】:2012-06-04 03:10:19
【问题描述】:

我正在尝试实现一个服务器,它在收到消息时会执行以下操作:

try{
       ObjectInputStream is = new ObjectInputStream(clientSocket.getInputStream());
       String message = (String)is.readObject();
       ActivateCommand(message,clientSocket);
       is.close();
    }

和激活命令:

private void ActivateEwolfCommand(String msg, Socket clientSocket) throws IOException 
{
    ObjectOutputStream os = new ObjectOutputStream(clientSocket.getOutputStream());
    Gson gsonObject = new Gson();
    .
    //code which makes a Json string
    .
    os.writeObject(json);
os.close();
}

现在,当我通过 junit 测试向本地主机发送消息对其进行测试时,它可以正常工作。但是当尝试从 C# 客户端连接到服务器时,客户端连接但服务器在到达 clientSocket.getInputStream() 点时抛出 EOF 异常。 我猜这是因为服务器不知道消息何时结束,但我不知道是否真的如此,如果是这样,那么我该如何解决?

【问题讨论】:

  • 作为一名程序员,您可以在最后使用一些独特的信息流式传输数据。在接收点放置一个 if 语句,检查代码是否到达结束位!如果是则退出循环
  • 但正如你所看到的,我只是在制作 String msg = (String)is.readObject() 并且我在字符串 var 中收到了消息......我怎么能告诉它在它发生时停止看到一些特殊字符或什么?
  • 如果你想实现一个服务器Netty可能有用:netty.io

标签: java sockets client-server inputstream eofexception


【解决方案1】:

如果您想通过套接字发送字符串,那么ObjectInputStreamObjectOutputStream 不是正确的流实现。这些流实现使用 Java 对象序列化。即使您序列化 String 实例,生成的字节也与使用适当字符编码的纯字符串到字节转换不同。

而且 C# 应用程序根本不理解 Java 序列化。

考虑使用PrintWriter 将字符串写入您的流并使用BufferedReader 进行读取。

PrintWriter writer = new PrintWriter(new OutputStreamWriter(clientSocket.getOutputStream(), "UTF-8"));
writer.println(...);


BufferedReader reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream(), "UTF-8"));
String line = reader.readLine();

然后您可以逐行读取和写入字符串。 这只是一个起点。如果你想实现自己的协议,你必须注意更多的点。例如,您可以阅读一些 TCP 协议的规范,例如 POP3FTPHTTP 1.0

【讨论】:

  • 只是为了确定......我已经看到了一些在读取文件时使用 BufferedReader 的示例,它是这样的:尝试 { BufferedReader in = new BufferedReader(new FileReader("infilename" ));字符串 str; while ((str = in.readLine()) != null) { process(str); } in.close(); } catch (IOException e) { } 我假设这一行从文件中读取整行,直到每次 \n 字符?这意味着在服务器情况下,只有当我假设某人没有向我传递完整文件时,我才能在没有 while 循环的情况下使用缓冲读取器?
  • 这取决于你自己的协议规范。您可以指定您的客户端应向您的服务器发送一个单行字符串,并且您的服务器始终以一行响应。或者您可以定义您的服务器可以发送一大堆行,其中空行标记响应结束。但是,作为响应的一部分,您必须转义空行。或者您可以发送包含剩余字节数的一行,然后是该行。如果您决定实现自己的协议,这完全取决于您。
【解决方案2】:

这就是为什么使用套接字和对象流创建自己的客户端-服务器协议是一个坏主意的原因。很多人花了很多年才带你,哦,好吧:

  • 肥皂
  • 休息
  • RMI
  • 黑森州
  • CORBA
  • 节俭

还有许多其他协议。当然,如果不是 5 个或 6 个,其中之一足以解决您的问题,包括所有框架问题。

【讨论】:

    【解决方案3】:

    InputStreamread() 上没有更多可用数据时 - 这基本上就是导致 EOF 的原因。有多少数据可用是由客户端决定的——它写入它一侧的 Socket 的OutputStream 的数据在服务器端的 Socket 的InputStream 上显示为这样。您可以调用InputStream.available() 来估算可能仍为read() 的字节数。

    但是,您的代码尝试使用 ObjectInputStream 读取对象 - 此类有自己的协议来读取序列化字节流并将其转换为对象 - 如果找不到完成任务的字节,则可能会抛出EOF 异常。如果您的客户端使用 C# - 为序列化对象写入的字节格式肯定与服务器端 ObjectInputStream 所期望的不同。

    【讨论】:

    • 这是否意味着 InputStream.available() 在这里不起作用?
    • InputStream.available() 的工作量与它告诉您使用 ObjectInputStream 可以读取多少原始字节一样多 - 这工作正常,但这还不足以从 - 因为不匹配完全读取一个对象C#序列化和java反序列化之间的字节格式。您需要考虑使用一些更高级别的框架来处理 C# 和 java 之间的数据互操作性 - 或者使用某种 xml 序列化。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-11-05
    • 2018-09-13
    • 2019-06-27
    • 1970-01-01
    • 2021-10-16
    • 2016-02-12
    • 1970-01-01
    相关资源
    最近更新 更多