UDP服务器即使最后启动服务器也从客户端获取数据

时间:2016-01-11 16:32:05

标签: java udp

我目前正在攻读编程考试,在早期的考试集中,一个问题有以下代码。

public class Question18 {
public static class Question18Server implements Runnable {

    DatagramSocket serverSocket;
    byte[] receiveData = new byte[1024];
    byte[] sendData = new byte[1024];

    public Question18Server(int port) throws SocketException{
        serverSocket = new DatagramSocket(port);
    }
    public void run() {
        while (true) {
            DatagramPacket receivePacket = new
                    DatagramPacket(receiveData,
                    receiveData.length);
            try {
                serverSocket.receive(receivePacket);
                String sentence = new String(receivePacket.getData());
                System.out.println("RECEIVED: " + sentence);
            } catch (IOException e) {
            }
        }
    }
}
public static class Question18Client implements Runnable {
    int port;
    DatagramSocket clientSocket;
    InetAddress IPAddress;
    public Question18Client(int port) throws SocketException,
            UnknownHostException {
        this.port = port;
        clientSocket = new DatagramSocket();
        IPAddress = InetAddress.getByName("localhost");
    }
    public void run() {
        for (int i = 0; i < 4; i++) {
            byte[] sendData = new byte[1024];
            String sentence = "Hello " + i * 2;
            sendData = sentence.getBytes();
            DatagramPacket sendPacket = new DatagramPacket(sendData,
                    sendData.length, IPAddress, port);
            try {
                clientSocket.send(sendPacket);
            } catch (IOException e) {
            }
        }
    }
}
public static void main(String[] args) {
    try {

        Thread server = new Thread(new Question18Server(9000));
        Thread client = new Thread(new Question18Client(9000));

        server.start();
        client.start();

    } catch (Exception e) {
    }
  }
}

我遇到麻烦的问题是:

如果server.start()和client.start()被反转,输出会是什么?

我对UDP没有太多经验,我可能误解了一些东西,但我最初的想法是服务器可能会收到客户端发送的一些datagramPackets。

但令我惊讶的是它收到了所有数据发送。

我尝试将代码更改为以下内容,以便在两个线程的开头之间创建一个小暂停,但它仍在工作。

        client.start();            
        long waittime = System.currentTimeMillis() + 5000;
        while(System.currentTimeMillis() < waittime)
        {}            
        server.start();

我真的希望有人可以解释为什么这有效,我目前的理论是

a)由于我使用“localhost”

,因此数据存储在我的计算机上

b)DatagramPackets在一段时间内搜索正确的IP和端口。

2 个答案:

答案 0 :(得分:1)

由于UDP中不需要连接设置,因此发布者订户的启动顺序不如TCP中那么重要。在UDP中,后期用户不一定会看到所有数据包,即使用户没有迟到也无法保证。

在您的代码中,Question18Client发布商Question18Server订阅者。尝试以下实验:

  1. 启动发布商
  2. 使用递增整数作为内容发送1024个数据包
  3. 启动订阅者
  4. 使用递增整数作为内容发送另一个1024
  5. 例如:

    import java.io.IOException;
    import java.net.DatagramPacket;
    import java.net.DatagramSocket;
    import java.net.InetAddress;
    import java.net.SocketException;
    import java.net.SocketTimeoutException;
    import java.net.UnknownHostException;
    
    public class SoQuestion {
        private static class Publisher {
            private DatagramSocket socket;
            private InetAddress address;
            private int port;
    
            private int count = 1;
    
            public Publisher(int port, String host) 
                throws SocketException, UnknownHostException {
                this.port = port;
                address = InetAddress.getByName(host);
                socket = new DatagramSocket();
            }
    
            public void publish(int packets) {
                System.out.println(
                    "Publishing " + packets + 
                    " packets via UDP to port " + this.port
                    );
    
                for (int i = 1; i <= packets; i++,count++) {
    
                    String data = "" + count;
                    byte[] dataBytes = data.getBytes();
    
                    DatagramPacket packet = new DatagramPacket(
                        dataBytes,
                        dataBytes.length,
                        address,
                        port
                        );
    
                    try {
                        socket.send(packet);
                        System.out.println(data + " sent");
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    
        private static class Subscriber extends Thread {
    
            private int port;
            private String host;
    
            private InetAddress address;
            private DatagramSocket socket;
    
            private byte[] buffer = new byte[1024*1024];
            private volatile boolean finished;
    
            public Subscriber(int port, String host) throws SocketException{
                this.port = port;
                this.host = host;
            }
    
            @Override
            public void run() {
                try {
                    address = InetAddress.getByName(host);
                    socket = new DatagramSocket(port, address);
                    socket.setSoTimeout(5000);
    
                    System.out.println("Subscribed via UDP to port " + port);
                    while (!finished) {
    
                        DatagramPacket packet = new DatagramPacket(
                            buffer,
                            buffer.length
                            );
    
                        socket.receive(packet);
                        System.out.println(
                            new String(
                                packet.getData(), 
                                0, 
                                packet.getLength()
                                ) + " received"
                            );
    
                    }
    
                    System.out.println("Subscription finished");
                } catch (SocketTimeoutException x ) {
                    System.out.println("Subscription timed-out.");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
    
            public void finish() {
                this.finished = true;
            }
        }
    
        public static void main(String[] args) {
            try {
                int packets = 1024;
    
                Publisher publisher = new Publisher(9000, "localhost");
                publisher.publish(packets);
    
                Subscriber subscriber = new Subscriber(9000, "localhost");
                subscriber.start();
    
                Thread.sleep(2000);
    
                publisher.publish(packets);
    
                //subscriber.finish();
    
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    

    当我运行时:

    javac SoQuestion.java
    java SoQuestion|sort -k 1,1n -k 2,2r
    

    我看到前1024个数据包没有收到,并且x64 Linux 3.16.7-29上的下一个1024匹配接收:

    1 sent
    ...
    1024 sent
    1025 sent
    1025 received
    ...
    2048 sent
    2048 received
    

答案 1 :(得分:0)

使用DatagramSocket发送数据不需要另一侧的监听器。数据不会随处可见。它也不存储在等待侦听器套接字打开的任何地方。您看到的行为很可能是由您的代码引起的。

你应该对你正在捕捉的异常做一些事情而不是忽略它们。

您还应该确保停止Question18Server。 ServerSocket位于receive()中而未关闭。

您真的需要为客户端使用线程吗?你不能在没有启动线程的情况下将它作为主类的一部分运行。

我认为如果你解决这些问题,你就会开始看到真正发生的事情。