是否可以让多个线程侦听同一个DatagramSocket?

时间:2013-11-29 23:25:55

标签: java multithreading serversocket datagram

我正在用java写一个聊天程序,我已经被困了好几个小时了。这是我的等待客户端连接到服务器的类。 每次新客户端连接时,我都会创建一个新的ChatClient(String name, DatagramSocket serverSocket,InetAddress IPAddress, int port)对象。

我的想法是每个ChatClient对象都在侦听套接字,并且当一个包从与ChatClient相同的IP发送时,它将处理它,否则什么也不做。

就像现在一样,当我只连接一个客户端时;客户端获取每2个包,然后在WaitForConnection()中运行run()获取其余的包。

所以我的问题是,是否有可能让多个线程在同一个DatagramSocket上监听而不会丢失(每个人都会发送所有内容)。如果有解决方案,怎么办?

private ArrayList<ChatClient> clients;
    private DatagramSocket serverSocket;
    private boolean running;

    public WaitForConnection() {
        running = true;
        clients = new ArrayList<ChatClient>();

        try {
            serverSocket = new DatagramSocket(ChatServer.port);
        } catch (SocketException e) {
            System.out
                    .println("Couldn't open socket. Port might alreadybe in use");
            e.printStackTrace();
        }
        try {
            serverSocket.setReuseAddress(true);
        } catch (SocketException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    @Override
    public void run() {

        while (running) {
            for (ChatClient ch : clients) {
                System.out.println(ch.toString());
            }

            byte[] handShake = new byte[1024];
            DatagramPacket receivePacket = new DatagramPacket(handShake,
                    handShake.length);

            try {
                serverSocket.receive(receivePacket);
            } catch (IOException e) {
                System.out.println("Waiting for connections error");
                e.printStackTrace();
            }
            String connect = new String(receivePacket.getData());
            System.out.println(connect);

            InetAddress IPAddress = receivePacket.getAddress();

            // if connect == "OPEN_CONNECTION" -> new client want to connect.
            if (connect.contains("openconnection")) {

                int port = receivePacket.getPort();

                try {

                    ChatClient chatClient = new ChatClient(
                            IPAddress.getHostName(), serverSocket, IPAddress,
                            port);

                    // Don't want double clients.
                    for (int i = 0; i < clients.size(); i++) {
                        if (clients.get(i).equals(chatClient)) {
                            clients.remove(i);
                        }
                    }
                    clients.add(chatClient);

                } catch (IOException e) {
                    System.out.println("Couldn't connect to client");
                    e.printStackTrace();
                }
            }
        }
    }
}

如果你需要查看它,可以使用ChatClient代码。

public class ChatClient extends Thread {
    private InetAddress IPAddress;
    private DatagramSocket serverSocket;
    private int port;
    private String name;

    public ChatClient(String name, DatagramSocket serverSocket,
            InetAddress IPAddress, int port) throws IOException {
        super(name);
        this.name = name;
        this.IPAddress = IPAddress;
        this.serverSocket = serverSocket;
        this.port = port;

        byte[] confirmConnection = new byte[1024];
        String connected = "Connection to server established";
        confirmConnection = connected.getBytes();

        serverSocket.send(new DatagramPacket(confirmConnection,
                confirmConnection.length, IPAddress, port));
        start();

    }

    public void run() {
        while (true) {
            byte[] message = new byte[1024];
            DatagramPacket receivedPacket = new DatagramPacket(message,
                    message.length);
            try {
                serverSocket.receive(receivedPacket);
            } catch (IOException e) {
                System.out
                        .println("Something went wrong receiving data in ChatClient");
            }
            if (receivedPacket.getAddress().equals(IPAddress)) {
                String connect = new String(receivedPacket.getData());
                connect = connect.toUpperCase();
                System.out.println(connect + "client side");
                message = connect.getBytes();
                try {
                    serverSocket.send(new DatagramPacket(message,
                            message.length, IPAddress, port));
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }
}

2 个答案:

答案 0 :(得分:4)

多个线程可以从同一个DatagramSocket接收,但只有一个线程可以获取每个数据报。

我不明白为什么你认为你需要这个。

答案 1 :(得分:1)

技术上不可能,因为网络硬件只接收一次数据包。但是一旦读完,你总是可以在内存中复制它。在你的代码中基本上只做Arrays.copyOf(receivePacket)

对于更复杂的版本,您可以使用NIO包并使用Selector。这将允许您通过单个线程运行所有网络连接,该线程将数据读取并分发到处理线程。如果您有来自许多客户端的多个连接,那么可以节省额外的线程开销。