我的标题可能不是最具描述性的,但我会尽量展示尽可能多的代码,希望它能帮助每个人更好地理解我的问题。以下是我的项目客户端查询服务器以获取信息的方式。这是典型请求的示例:
private String GENERATEGROUPKEY()
{
/* `out` is a PrintWriter using the sockets output stream */
out.println("GENERATEGROUPKEY");
try
{
/* `in` is a BufferedReader using the sockets input stream */
String response = in.readLine();
String[] temp = response.split(" ");
return temp[1];
}
catch (IOException ex)
{
return null; // throw connection error to client
}
}
我的问题是,在任何时候,服务器都可以通过同一个带有信息的套接字向客户端发送未经请求的消息(想想它就像聊天客户端接收消息一样)。我的不成功的想法是创建一个侦听这样一条消息的线程,只要我们不在另一个查询的中间,但这也是不成功的,因为即使我正在打断该线程,它仍然会占用应该的消息已经去了客户端查询。
private String GENERATEGROUPKEY()
{
out.println("GENERATEGROUPKEY");
listenThread.interrupt(); // block listenThread from recieving response
try
{
String response = in.readLine();
String[] temp = response.split(" ");
listenThread = new PulseThread(in); // we're done, so allow
listenThread.start();
return temp[1];
}
catch (IOException ex)
{
listenThread = new PulseThread(in); // we're done, so allow
listenThread.start();
return null; // throw connection error to client
}
}
这正是listenThread
的意思
public class PulseThread extends Thread
{
private BufferedReader in;
public PulseThread(BufferedReader in)
{
this.in = in;
}
@Override
public void run()
{
while (true)
{
if (Thread.currentThread().isInterrupted())
{
break;
}
try
{
String line = in.readLine();
System.out.println(line);
String[] params = line.split(" ");
if (params[0].equals("PULSED"))
{
NotificationManager.sendNotification("You have been pulsed!", "Pulsed by: " + params[1]);
}
}
catch (Exception ex)
{
}
}
}
}
我之前的印象是,在使用BufferedReader
的readLine()
阻塞调用中间中断线程只会取消阻塞调用,除非我做了别的错误。
非常感谢任何帮助,谢谢。
编辑:所以看看我的假设只是在这句话上面几行,似乎打断线程不取消readLine()
。我猜中断线程的想法是不行的。这样做的正确方法是什么?
这里的一般模式是你想要一个线程处理来自套接字的输出(在等待时阻塞),然后将消息分派给请求它们的正确的东西。
我喜欢并在多个项目中成功使用的一个实现是将随机生成的ID添加到“请求”作为通用标头的一部分(包括消息类型),并让服务器始终在响应中反映ID,允许客户端将请求与响应相关联,而不关心它是什么类型的消息。
具体而言,类似于SocketMessenger
类,有2个公共函数:sendRequest(type, body, callback)
和registerUnsolicitedHandler(type, callback)
。
sendRequest
使用type
和随机生成的ID构建消息头,将其添加到待处理的回复列表以及对回调函数的引用,然后将完成的消息发送到服务器。
registerUnsolicitedHandler
按照其名称建议,并将回调函数添加到消息类型的映射中,以便在传入消息没有ID时使用。
在处理传入消息的单独线程中,它对传入数据进行反序列化以从头部获取类型和ID,如果消息具有ID,则它搜索待处理的回复列表并使用消息体调用适当的回调(可能在主线程上调度) ,我正在掩盖锁定等一些细节,否则它会在未经请求的处理程序列表中搜索指定的类型并调用该回调。