1

Alright so for fun I'm practicing multithreading and networking in Java right now but I've ran into something really weird. I have my code structure as follows. Client and Server are threads, which contain PacketListeners which are also threads that just add packets to a ConcurrentLinkedQueue when received.

My Server class looks like this

public Server(int port) {
        setThreadName("ServerThread");
        this.clients = new ArrayList<SocketAddress>();
        try {
            //this.socket = new DatagramSocket(null);
            //this.socket.setReuseAddress(true);
            //this.socket.bind(new InetSocketAddress(port));
            //this.socket.setReuseAddress(true);
            //this.socket.bind(new InetSocketAddress(port));
            //sender = new PacketSender(socket);
            this.listener = new PacketListener(port);

        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        listener.start();
    }

    synchronized private void processPacket(DatagramPacket packet) {
            if (packet != null) {
                String data = new String(packet.getData(), 0, packet.getLength());
                System.out.println("Received a packet " + data);
                if (data.equalsIgnoreCase("connecting")) {
                    System.out.println("wut");
                } else {
                    System.out.println("Packet from :" + packet.getAddress().toString() + " saying: " + data);
                }
            } else {
                System.out.println("Packet == null");
            }
        }



        @Override
        public void run() {
            System.out.println("running server on port " + socket.getLocalPort());
            while (isRunning()) {
                if (listener.hasPacket()) {
                    System.out.println("listener has a packet");
                    processPacket(listener.getNextPacket());
                }
                sleep(1); // sleep for 1ms (keeps cpu usage from sky rocketing)
            }
        }

My PacketListener class looks like this

 public PacketListener(int port) throws IOException {
        this.socket = new DatagramSocket(null);
        this.socket.setReuseAddress(true);
        this.socket.bind(new InetSocketAddress(port));
        System.out.println("Packet listener bound @ " + socket.getLocalAddress() + " on port " + socket.getLocalPort());
        receivedPackets = new ConcurrentLinkedQueue<DatagramPacket>();
    }

    synchronized private void addPacket(DatagramPacket packet) {
        if (!receivedPackets.add(packet)) {
            System.err.println("We dropped a packet because full queue");
        } else {
            System.out.println("We added a received packet! - " + receivedPackets.size());
        }
    }

    synchronized public boolean hasPacket() {
        return !receivedPackets.isEmpty();
    }

    synchronized public DatagramPacket getNextPacket() {
        return receivedPackets.poll();
    }

    @Override
    public void run() {
        byte[] buffer = new byte[256];
        DatagramPacket inPacket = new DatagramPacket(buffer, buffer.length);
        while (isRunning()) {
            try {
                socket.receive(inPacket);
                addPacket(inPacket);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

Now the weird thing is that on the client end, say I send a few packets. Let's say I send "hello", then "test1", then "test2" The server will print out

Packet received
We added a received packet! - 1
listener has a packet

Packet received
Received a packet test1
We added a received packet! - 1
Packet from :/127.0.0.1 saying: test1
listener has a packet


Packet received
Received a packet test2
We added a received packet! - 1
Packet from :/127.0.0.1 saying: test2
listener has a packet

This should actually print out something along the lines of

We added a received packet! - 1
listener has a packet
Received a packet hello
Packet from :/127.0.0.1 saying: hello

We added a received packet! - 1
listener has a packet
Received a packet test1
Packet from :/127.0.0.1 saying: test1

We added a received packet! - 1
listener has a packet
Received a packet test2
Packet from :/127.0.0.1 saying: test2
7
  • 1
    What's weird? What were you expecting to see? Commented Sep 2, 2014 at 23:21
  • Is that everything that it prints out? Are you really sending all 3 packets, "hello", "test1", and "test2"? Your output makes sense if you were sending "test1" first, and if following the print of the packet contents, your listener then prints "test2", etc. Commented Sep 2, 2014 at 23:22
  • I have the client set up so that I type in strings and it sends them to the server, which is what the server is receiving and printing. I also have the client verifying the packet data via prints before I send it. It should say something like We added a received packet - 1 listener has a packet Received a packet hello Packet from /127.0.0.1 saying: hello and so on for all three Commented Sep 2, 2014 at 23:27
  • @CraigOtis is order of packets preserved with DatagramSockets? Multiple packets sent from one machine to another may be routed differently, and may arrive in any order. from Javadocs. Commented Sep 2, 2014 at 23:28
  • 1
    Having a fully working version will make things easier :) Commented Sep 3, 2014 at 0:01

1 Answer 1

3

I think the problem is that you are reusing the same instance of DatagramPacket over and over again.

This means that one thread receive packets, but in reality it is only always "updating" the same instance of DatagramPacket. The queue will contain the same instance a few times.

The second thread is then pulling from the queue the same instance, that changes while the various print are being executed, so the printed result are erratic.

Moreover, i don't know the internals of the DatagramPacket class, but internal locks of synchronization could cause one thread to wait for the other or things like that.

Just to make sure there is no mutating stuff between the two threads, i would write :

    while (isRunning()) {
        try {
            byte[] buffer = new byte[256];
            DatagramPacket inPacket = new DatagramPacket(buffer, buffer.length);
            socket.receive(inPacket);
            addPacket(inPacket);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
Sign up to request clarification or add additional context in comments.

7 Comments

Hmm, I'll try changing that to see if it helps. I see what you're saying. I think you're on to something here, because I too don't think the DatagramSocket class is concurrent.
Hmm, so this did help a bit but still, the first packet sent causes the server to only print up to "listener has a packet". I don't get how that can be printed but the function that runs as soon as that is printed doesn't run?
The "new DatagramPacket" is still before the "while(isRunning())", and not inside it?
Just added the Server constructor for you to see.
Thank you. It works now. I'm not sure why that change fixed it though.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.