如何选择要从多个流中关闭的流?

时间:2013-12-05 23:48:33

标签: java multithreading

直到现在我才意识到我程序中的断开连接按钮失败了。如果我有3个客户端,并且其中任何一个单击断开连接,则只有最后一个客户端断开连接。如何选择需要关闭的实例?如果我想删除第一个用户中的3个用户..

服务器:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;

public class Server {
    private Set<Socket> sockets = new HashSet<Socket>();
    private Set<String> names = new HashSet<String>();
    private Socket sock;
    private static int port;
    private Calendar cal = Calendar.getInstance();
    private SimpleDateFormat date = new SimpleDateFormat("dd/mm/yyyy hh:mm:ss");

    public Server(int input) {
        port = input;
    }

    public static void main(String[] args) {
        /*
         * user defines port number, server initialized
         */
        System.out.println("enter a port");
        Scanner input = new Scanner(System.in);
        port = input.nextInt();
        new Server(port).go();
        input.close();
    }

    public void go() {
        try {
            /*
             * wait for connections, add connections to Set, setup streams per
             * connection in new threads
             */
            System.out.println("waiting for connetion");
            @SuppressWarnings("resource")
            ServerSocket serverSocket = new ServerSocket(port);
            while (true) {
                sock = serverSocket.accept();
                sockets.add(sock);
                Thread t = new Thread(new ClientHandler(sock));
                t.start();
                System.out.println("connected: " + sock.getInetAddress());
            }
        } catch (IOException ex) {
            ex.printStackTrace();
            System.out.println("server setup failed");
        }
    }

    class ClientHandler implements Runnable {
        /*
         * client handler sets up streams
         */
        private BufferedReader in;
        private PrintWriter out;
        private String name;

        public ClientHandler(Socket sock) {
            try {
                in = new BufferedReader(new InputStreamReader(
                        sock.getInputStream()));
                out = new PrintWriter(sock.getOutputStream(), true);
            } catch (IOException e) {
                e.printStackTrace();
                System.out.println("stream setup failed");
            }
        }

        @Override
        public void run() {
            /*
             * First check if user exists, if true than close connection and
             * warn user about name. Then relay message to all clients, if user
             * DC's than remove the socket from the Set
             */
            String message;
            try {
                name = in.readLine();
                if (names.contains(name)) {
                    System.out.println("duplicate name detected, removing..");
                    out.println("choose new name and reconnect: "
                            + sock.getInetAddress());
                    sock.close();
                    sockets.remove(sock);
                } else {
                    names.add(name);
                    System.out.println("Users active: " + names);
                    shout("user: " + name + " connected!" + " from "
                            + sock.getInetAddress());
                }
                while ((message = in.readLine()) != null) {
                    /*
                     * call method which checks if user tries to enter a command
                     * such as /laugh or /roll, otherwise relay the message to
                     * all clients
                     */
                    swich(message);
                }
            } catch (IOException ex) {
                System.out.println("user disconnected: " + name + " "
                        + sock.getInetAddress());
                shout("user disconnected: " + name + " "
                        + sock.getInetAddress());
                names.remove(name);
                remove(sock);
            }
        }

        public synchronized void shout(String message) {
            // send message to all clients in Set
            for (Socket sock : sockets) {
                try {
                    PrintWriter writer = new PrintWriter(
                            sock.getOutputStream(), true);
                    writer.println(date.format(cal.getTime()) + " " + message
                            + "\n");
                } catch (IOException e) {
                    e.printStackTrace();
                }

            }

        }

        public void swich(String message) throws IOException {
            // check if user calls a chat command
            // otherwise shout message to all clients
            switch (message) {
            case "/disconnect":
                out.println("disconnected");
                remove(sock);
                break;
            case "/laugh":
                String[] laughs = { "HahHA!", "HAHAAH!!!!", "haaaaa!!!",
                        "hohohoohohahhaa!!!", "huehuehue!" };
                shout(name + " " + laughs[(int) (Math.random() * 5)]);
                break;
            case "/roll":
                shout(name + " rolls "
                        + Integer.toString((int) ((Math.random() * 6) + 1)));
                break;
            case "kirby!":
                shout("(>'-')> <('-'<) ^(' - ')^ <('-'<) (>'-')>");
                break;
            default:
                shout(message);
                System.out.println("client says : "
                        + date.format(cal.getTime()) + message);
            }
        }

    }

    public void remove(Socket soc) {
        try {
            soc.close();
            sockets.remove(soc);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

客户端:

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;

public class Client {

    private JTextArea tArea;
    private JTextField tField;
    private JTextField portText;
    private JTextField hostText;
    private BufferedReader in;
    private Socket sock;
    private static PrintWriter out;
    private static String name;
    private String host;
    private String port;

    public static void main(String[] args) {
        System.out.println("Enter username");
        Scanner input = new Scanner(System.in);
        name = input.nextLine();
        input.close();
        new Client().go();

    }

    public void go() {
        /*
         * build gui
         */
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                JFrame frame = new JFrame("hakobChat");
                JPanel topPanel = new JPanel();
                JLabel portLabel = new JLabel("port");
                JLabel hostLabel = new JLabel("host");
                portText = new JTextField(6);
                hostText = new JTextField(12);
                JButton connect = new JButton("connect");
                connect.addActionListener(new connectListener());
                JButton disconnect = new JButton("disconnect");
                disconnect.addActionListener(new disconnectListener());
                tField = new JTextField(30);
                tField.addActionListener(new sendListener());
                tArea = new JTextArea(30, 50);
                tArea.setEditable(false);
                tArea.setLineWrap(true);
                JScrollPane tScroll = new JScrollPane(tArea,
                        JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
                        JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
                JButton button = new JButton("send");
                button.addActionListener(new sendListener());
                topPanel.add(hostLabel);
                topPanel.add(hostText);
                topPanel.add(portLabel);
                topPanel.add(portText);
                topPanel.add(connect);
                topPanel.add(disconnect);
                frame.setSize(300, 500);
                frame.setVisible(true);
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.getContentPane().add(topPanel, BorderLayout.NORTH);
                frame.getContentPane().add(tScroll, BorderLayout.CENTER);
                frame.getContentPane().add(tField, BorderLayout.SOUTH);
                frame.getContentPane().add(button, BorderLayout.EAST);
                frame.pack();
            }
        });
    }

    public void setupNetwork(String host, int port) {
        /*
         * setup in and out stream send user name to server to check if
         * duplicate start thread for incoming messages
         */
        try {
            sock = new Socket(host, port);
            in = new BufferedReader(
                    new InputStreamReader(sock.getInputStream()));
            out = new PrintWriter(sock.getOutputStream(), true);
            out.println(name);
            showMessage("Connected!");
            showMessage("enter /laugh or /roll  or kirby! for some fun!");
            Thread t = new Thread(new IncomingReader());
            t.start();
        } catch (IOException ex) {
            ex.printStackTrace();
            showMessage("please enter valid network");
        }
    }

    class IncomingReader implements Runnable {
        // receive messages from server
        public void run() {
            try {
                String message = null;
                while ((message = in.readLine()) != null) {
                    showMessage(message + "\n");
                }
            } catch (Exception e) {
                e.printStackTrace();
                showMessage("choose new name and reconnect please");
            }
        }
    }

    public synchronized void sendMessage(String message) {
        try {
            switch (message) {
            case "/laugh":
                out.println("/laugh");
                break;
            case "/roll":
                out.println("/roll");
                break;
            case "kirby!":
                out.println("kirby!");
                break;
            default:
                out.println("(" + name + ")" + ": " + message);
            }

        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("fail send message");
        }
    }

    public void showMessage(final String message) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                tArea.append(message + "\n");
                tArea.setCaretPosition(tArea.getDocument().getLength());
                // SetCaretPosition forces autos scroll
            }
        });
    }

    class sendListener implements ActionListener {
        // listens for user to trying to send a message
        public void actionPerformed(ActionEvent ev) {
            sendMessage(tField.getText());
            tField.setText("");
        }
    }

    class disconnectListener implements ActionListener {
        public void actionPerformed(ActionEvent ev) {
            try {
                out.println("/disconnect");
            } catch (NullPointerException e) {
                showMessage("not connected");
            }
        }
    }

    class connectListener implements ActionListener {
        public void actionPerformed(ActionEvent ev) {
            host = hostText.getText();
            port = portText.getText();
            if (!host.equals("") && !port.equals("") && port.matches("[1-9]+")) {
                // make sure user enters valid inputs
                // before setting up network
                setupNetwork(host, Integer.parseInt(port));
            } else {
                showMessage("enter valid network credentials");
            }
        }

    }

}

另外,我如何避免这种情况&#34; @SuppressWarnings(&#34;资源&#34;)&#34;。如果我没有提供这个eclipse警告,那么serverSocket会用黄色加下划线。

2 个答案:

答案 0 :(得分:1)

您需要在Socket内保存用于客户端的ClientHandler

您只需添加

即可
private Socket sock;

ClientHandler内,并添加:

this.sock = sock;

在其构造函数内部。

目前,您正在使用服务器中保存的Socket,它始终是最后连接的客户端的套接字,而不是属于当前客户端的Socket

答案 1 :(得分:1)

这只是一个范围问题。 Socket sock成员不应该是Server类的成员。它应该是ClientHandler类的一部分。每个客户一个。