简体   繁体   中英

I am having trouble with my logic for a UDP client application

I am working on a Java application that communicates via UDP to a server. This is a specific server, in that all it does is relay message" from one client to another, across a network, with a VERY specific message format. The message format is small and compact to make use of an extremely small bandwidth. There are unique rules for this server:

  1. The server only accepts UDP datagrams in it's very specific message format.
  2. The server is subscription based. It will only send the clients messages if they are subscribed to a specific message protocol (eg, chat, time, temperature, channel, etc.).
  3. When you subscribe to services, you MUST send the server a permanent UDP listen port so it can send you your subscribed messages. If you don't listen on that port, you will not get your messages.
  4. You can ask the server for information (server status, message status, etc.), but if you ask too much, it will disconnect you.
  5. The previously mentioned information does not include client to client messages. Those will be sent out by the server whenever they are received. A client does not have to ask for the messages once it subscribes to the message protocol.
  6. Clients must send regular heartbeat messages to the server to let the server know you are still interested in its services. If the heartbeats are sent too often, the server will disconnect you.
  7. The server also sends out regular heartbeats to let clients know it is still operating.

At startup, I send this server an empty service subscription, just to get onto its list of subscribers (which is correct according to the server rules).

After that initial message, I start sending my heartbeats, once every 5 seconds (which is correct according to the server rules).

At this point, I launch a thread to listen for messages from the server.

Finally, I send a subscription request to the server for the services I would like to receive messages about.

It is at this point that I am having problems. If my application is started before the server application is running or if the server application is restarted while my application is running, I don't get any messages from the server.

I think the reason for this is because my listener thread is blocking, waiting for messages that will never come. If I start my application first, my request for services goes out, but the server never receives the request. I then start listening, but the server will never talk to me because (according to the server) I haven't subscribed. I cannot send a subscription request constantly, or the server will disconnect me. The server documentation says, that if two server heartbeats are missed, then a client should re-subscribe. However, I cannot wrap my head around how to do this. Here is what I have. I have indicated where I believe the "trouble" is with the comment "Here is where my listener is blocking, waiting for messages from the server.".

Main

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;
    }

}

So, any suggestions on how I can get around this?

Thanks!

myDatagramSocket.receive(myDatagramPacket);

From the docs:

This method blocks until a datagram is received.

If you never register at the server, you are not going to recieve messages and the thread keeps on blocking.

Implementing a timeout on clientside would enable you to keep track of failed registration attempts, for example via

setSoTimeout

Also, you may want to set run = false; after breaking you while loop, since you are not listening anymore at this point.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM