我正在开发一个通过UDP与服务器通信的Java应用程序。这是一个特定的服务器,因为它所做的就是“通过网络从一个客户端到另一个客户端的中继消息,具有非常特定的消息格式。消息格式小而紧凑,可以使用带宽极小。此服务器有独特的规则:
在启动时,我发送此服务器为空服务订阅,只是为了进入其订阅者列表(根据服务器规则这是正确的)。
在初始消息之后,我开始每隔5秒发送一次心跳(根据服务器规则,这是正确的)。
此时,我启动一个线程来侦听来自服务器的消息。
最后,我向服务器发送订阅请求,以获取我希望收到的有关服务的消息。
正是在这一点上,我遇到了问题。如果我的应用程序在服务器应用程序运行之前启动,或者在我的应用程序运行时重新启动服务器应用程序,则不会从服务器收到任何消息。
我认为这是因为我的监听器线程正在阻塞,等待永远不会发生的消息。如果我首先启动我的应用程序,我的服务请求就会消失,但服务器永远不会收到请求。然后我开始听,但服务器永远不会跟我说话,因为(根据服务器)我没有订阅。我不能经常发送订阅请求,否则服务器将断开我的连接。服务器文档说,如果错过了两个服务器心跳,那么客户端应该重新订阅。但是,我无法解决如何做到这一点。这就是我所拥有的。我已经指出我认为“麻烦”的地方是评论“这是我的监听器阻止的地方,等待来自服务器的消息。”。
主要
public static void main(String[] args){
SubscribeToServices mySubscriptions = new SubscribeToServices();
mySubscriptions.subscribe(0); // 0 means no services
Heartbeat myHeartbeat = new Heartbeat();
Thread heartbeatThread = new Thread(myHeartbeat);
heartbeatThread.start();
MyListener listener = new MyListener();
Thread listenerThread = new Thread(listener);
listenerThread.start();
mySubscriptions.subscribe(1234); // a specific set of subscriptions
}
MyListener.java
public class MyListener implements Runnable {
private static final Logger LOG = Logger.getLogger(MyListener.class.getName());
private volatile boolean run = true;
private DatagramSocket myDatagramSocket;
private DatagramPacket myDatagramPacket;
private MessageHeader messageHeader;
private int receiveBufferSize;
private byte[] receiveBuffer;
private int messageID;
private Timer myTimer;
@Override
public void run() {
try {
// Create and bind a new DatagramSocket
myDatagramSocket = new DatagramSocket(null);
InetSocketAddress myInetSocketAddress = new InetSocketAddress(15347);
myDatagramSocket.bind(myInetSocketAddress);
} catch (SocketException se) {
LOG.log(Level.SEVERE, se.getMessage());
return;
}
// Set-up the receive buffer
receiveBuffer = new byte[2047];
myDatagramPacket = new DatagramPacket(receiveBuffer, 2047);
while (run) {
try {
// Receive the data from Server
// Here is where my listener is blocking, waiting for messages from the server.
myDatagramSocket.receive(myDatagramPacket);
} catch (IOException ioe) {
LOG.log(Level.SEVERE, ioe.getMessage());
break;
}
byte[] data = myDatagramPacket.getData();
receiveBufferSize = myDatagramPacket.getLength();
// Extract the message header and ID
messageHeader = ExtractMessageHeaders.extract(data, receiveBufferSize);
messageID = (messageHeader.getMessageID() & 0xff);
switch (messageID) {
// Do switch here ...
// Check for the heartbeat and other messages from the server.
}
myDatagramPacket.setLength(2047);
}
}
public boolean isRun() {
return run;
}
public void setRun(boolean run) {
LOG.log(Level.INFO, "Changing the listening thread.");
this.run = run;
}
}
那么,有关如何解决这个问题的任何建议吗?
谢谢!
答案 0 :(得分:0)
myDatagramSocket.receive(myDatagramPacket);
来自文档:
此方法将一直阻塞,直到收到数据报。
如果您从未在服务器上注册,则不会收到消息,并且线程会一直阻塞。
在客户端上实施超时将使您能够跟踪失败的注册尝试,例如通过
setSoTimeout
此外,您可能需要在断开循环后设置 run = false; ,因为此时您还没有收听。