【发布时间】:2014-06-07 13:45:06
【问题描述】:
我有一个套接字连接,我希望通过它发送 XML 消息,使用 DOM 类 (DocumentBuilder et al) 来构造和解析 XML 文档,但我不知道在等待消息时处理关闭连接的好方法。
消息可能以任何顺序到达(即我不知道哪一端将发送下一条消息)并且我想避免任何基于sleep() 的解决方案用于阻止 - 我想学习如何做到这一点比那更好。我尝试了以下设置的多种变体:
class XML {
static Message readMessage(InputStream s) {
// try/catch and setup of builder omitted for brevity
Document doc = builder.parse(s);
// Traverse the doc tree to built the Message, then return
}
static void writeMessage(Message m, OutputStream s) {
// Build a Document from the provided message
Transformer transformer = tf.newTransformer();
transformer.transform(new DOMSource(doc), new StreamResult(output));
output.write('\n');
}
}
class Connection {
Socket s;
Thread reader;
Connection(Socket s) {
this.s = s;
reader = new Thread(new Runnable() {
void run() {
while (true) {
Message m = XML.readMessage(s.getInputStream());
// Handle the message here, e.g. by dispatching UI events
}
}
});
reader.start();
}
void sendMessage(Message msg) {
XML.writeMessage(msg, s.getOutputStream());
}
void close() {
if (reader.isAlive()) {
reader.interrupt();
}
if (!socket.isClosed()) {
socket.close();
}
}
}
我可以让服务器和客户端正常连接并开始等待消息,只需在每一侧用各自的Socket 实例化一个Connection。发送和接收消息也可以正常工作。
但是,我想不出一种干净地关闭连接的方法。我不断遇到各种异常。确切的消息取决于上面骨架中的实现细节,但据我所知,它们都是在套接字关闭后读取线程尝试读取消息时出现的,或者在读取线程仍在读取时套接字关闭时出现。我总是使用上面的close() 方法关闭连接。
由于我只是将流传递给 DOM 库,因此我无法精确控制它的读取方式。
如何正确结束连接,而不会导致阅读器线程出现异常?
【问题讨论】:
-
您是要打开一个连接并拥有一个请求/响应,还是要在同一个连接上拥有多个请求/响应?
-
@BrettOkken:我在“对话”期间保持连接打开,所以我期待双方发送多条消息,没有特定的顺序,直到一方发送一个特殊的“断开”消息并关闭连接。此时,双方都应关闭其套接字并退出。
-
那么您可能必须定义一个包装 xml 的协议,以清楚地定义各个 xml 文档的开始和结束。然后,您需要在解析 xml 时包装套接字输入流并模拟文件结尾(即输入流读取返回 -1)。同样,发送方需要包装输出流并发送此特殊标记以指示消息结束。
-
在你的
close()方法中,中断reader线程后,调用reader.join()。这应该让它有机会干净地退出并停止所有操作,前提是您不只是忽略循环中的 IOExceptions。 (通常在 Java 中处理 I/O 循环的最好方法是让 try/catch 在循环之外,这样循环会在遇到错误时自动终止。) -
你也可以看看这个其他帖子,所以关注“优雅关机”:Java Sockets and Dropped Connections。也许这足以摆脱错误。
标签: java multithreading sockets