邮件仅发送给在聊天程序中发送邮件的客户端

时间:2017-04-11 04:05:44

标签: java multithreading sockets

在我的聊天客户端/服务器程序中,我无法将消息广播到所有连接的客户端。发送的消息似乎只是发送回原始服务器,即使我正在迭代ArrayList。我有一个套接字的ArrayList和一个方法,它将读取消息作为参数接收,并为每个套接字创建一个PrintWriter。我认为这个问题与我的客户课程有关(对不起,如果我错了),但我还没弄清楚是什么。

客户类:

public class H7Client extends Thread implements ActionListener{

private JTextField jtfPortName = new JTextField(20);
private JTextField jtfHostName = new JTextField(20);
private String hostName;
private int portNumber;

private JTextArea jtaChat = new JTextArea("Send a message to the client", 15,40);
private JTextArea jtaRecive = new JTextArea("WELCOME TO THE CHAT!", 15,40);
private JTextField jtfUName = new JTextField("user");



public H7Client(){
    JFrame defaultFrame = new JFrame();

    JLabel jlPortName = new JLabel("Enter The Port number");
    JLabel jlHostName = new JLabel("Enter the Host name");
    JLabel jlUName = new JLabel("Enter a username");

    JButton jbSetSocketInfo = new JButton("Confirm Port and Host Info");
    JButton jbExit = new JButton("Exit");
    JButton jbSendText = new JButton("Send");

    jbSetSocketInfo.addActionListener(this);
    jbExit.addActionListener(this);
    jbSendText.addActionListener(this);



    JPanel jpNorth = new JPanel();
    JPanel jpCenter = new JPanel();
    JPanel jpLabels = new JPanel();

    defaultFrame.add(jpNorth,BorderLayout.NORTH);
    jpNorth.add(jbSetSocketInfo,BorderLayout.EAST);
    jpNorth.add(jbSendText, BorderLayout.CENTER);
    jpNorth.add(jbExit,BorderLayout.WEST);


    defaultFrame.add(jpCenter,BorderLayout.CENTER);
    jpCenter.add(jtaChat,BorderLayout.SOUTH);
    jpCenter.add(jpLabels,BorderLayout.NORTH);

    jpLabels.setLayout(new GridLayout(2,3));
    jpLabels.add(jlHostName);
    jpLabels.add(jlPortName);
    jpLabels.add(jlUName);
    jpLabels.add(jtfHostName);
    jpLabels.add(jtfPortName);
    jpLabels.add(jtfUName);

    defaultFrame.add(jtaRecive,BorderLayout.SOUTH);

    defaultFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);


    defaultFrame.setLocationRelativeTo(null);
    defaultFrame.setSize(800,800);
    defaultFrame.setVisible(true);

}

public void setClientComms(String message){
    try{
        // open communications to the server
        Socket s = new Socket(hostName, portNumber);
        ClientThread ct = new ClientThread(s, message);
    }
    catch(IOException e){
        e.printStackTrace();
    }
}

class ClientThread extends Thread{

    public ClientThread(Socket sock, String msg) {

        try {

            // open input stream
            InputStream in = sock.getInputStream();
            BufferedReader br = new BufferedReader(
                    new InputStreamReader(in));

            // open output stream
            OutputStream out = sock.getOutputStream();
            PrintWriter pout = new PrintWriter(
                    new OutputStreamWriter(out));


            // write something to the server
            pout.println(msg);

            // make sure it went
            pout.flush();

            // read something back from server
            String incomingMessage = br.readLine();

            // print the something to the user
            System.out.println("Message: " + msg);
            //jtaChat.setText("");
            jtaRecive.append("\n" + msg);


            // Send the terminating string to the server
            pout.println("quit");
            pout.flush();

            // close everything
            pout.close();
            br.close();
            sock.close();
        } catch (UnknownHostException uhe) {
            System.out.println("What host you speak of?");
        } catch (IOException ioe) {
            System.out.println("Bad IO?");
            ioe.printStackTrace();
        }
    }
}

public void actionPerformed(ActionEvent event) {
    if (event.getActionCommand().equals("Exit")) {
        System.exit(0);
    } else if (event.getActionCommand().equals("Send")) {
        String chatMessage = jtaChat.getText();
        jtaChat.setText("");
        setClientComms(chatMessage);


    } else if (event.getActionCommand().equals("Confirm Port and Host Info")) {
        hostName = jtfHostName.getText();
        //NEED TO ADD IN WAY TO HANDLE IP ADDRESSES
        portNumber = Integer.parseInt(jtfPortName.getText());
    }
}


public static void main(String [] args) {

    new H7Client();


}

}

服务器类:

public class H7Server{

public ArrayList<Socket> clients = new ArrayList<Socket>();

public static void main(String[] args){new H7Server();}
public H7Server()
{



    ServerSocket ss = null;

    try {
        System.out.println("getLocalHost: "+ InetAddress.getLocalHost() );
        System.out.println("getByName:    "+InetAddress.getByName("localhost") );

        ss = new ServerSocket(16789);
        Socket cs = null;
        while(true){        // run forever once up
            //try{
            cs = ss.accept();               // wait for connection
            clients.add(cs);
            ThreadServer ths = new ThreadServer( cs );
            ths.start();
       } // end while
    }
    catch( BindException be ) {
        System.out.println("Server already running on this computer, stopping.");
    }
    catch( IOException ioe ) {
        System.out.println("IO Error");
        ioe.printStackTrace();
    }

} // end main

class ThreadServer extends Thread {
    Socket cs;

    public ThreadServer( Socket cs ) {
        this.cs = cs;
    }

    public void run() {

           BufferedReader br;
           String clientMsg;
           try {
               br = new BufferedReader(
                       new InputStreamReader(
                               cs.getInputStream()));


               clientMsg = br.readLine();                // from client
               System.out.println("Server read: " + clientMsg);
               while(clientMsg != null) {
                   sendMessage(clientMsg);
               }

           } catch (IOException e) {
               System.out.println("Inside catch");
               e.printStackTrace();
           }


    }

    public synchronized void sendMessage(String s){
        try{
            for(Socket sock: clients) {
                PrintWriter pw = new PrintWriter(new OutputStreamWriter(sock.getOutputStream()));

                pw.println(s);
                pw.flush();
            }
        }
        catch(IOException e){
            e.printStackTrace();
        }


    }

} // end class ThreadServer

}

1 个答案:

答案 0 :(得分:0)

您怀疑的客户端类和服务器类都存在问题。您需要解决两件事。

首先,您从服务器收到消息,但没有对其执行任何操作。客户端在incomingMessage的构造函数的try块中收到ClientThread但未使用。可能的解决方法是将其附加到jtaReceive并删除其他附加内容,但不要执行此操作。

对于实时聊天,客户端必须至少有两个线程:一个用于发送消息,另一个用于不断检查是否有任何消息要接收。也许,这是你试图用ClientThread实现的,但遗憾的是它不起作用。除了错误的代码之外,您使用ClientThread会创建Thread,但实际上从未运行过它。您需要有一个线程,在run方法中,包含一个永远从服务器接收消息的while循环。一个实现是这样的:(你可以重命名为你喜欢的任何东西)

class ReceiverThread extends Thread {

    private BufferedReader s;

    public ReceiverThread(Socket sock) throws IOException {
        s = new BufferedReader(new InputStreamReader(sock.getInputStream()));
    }

    @Override
    public void run() {
        while (true) 
            try {
                String message = s.readLine();
                // ...code to do whatever with message...
            } catch (IOException e) {
                e.printStackTrace();
            }
    }

}

此外,您还需要创建一个保持打开的套接字(当您确认主机和端口信息时,可以使用套接字创建并启动此线程)。

服务器类的问题是让我们所有人的问题:臭名昭着的ConcurrentModificationException。您可以阅读它here,但是当您不应该修改(添加,删除等)数据结构时,基本上会抛出此异常。有问题的数据结构是ArrayList的{​​{1}},并且当您发送消息时,when在Socket循环期间。基本上,当该循环正在运行时,创建for-each的{​​{1}}循环将它们添加到while并抛出异常。要修复,您需要在Socket循环中停止修改ArrayList,可能是通过删除while循环,保持while循环直到ArrayList循环结束,甚至当for循环处于活动状态时,要添加for个套接字,但有很多方法可以执行此操作。

我假设您的服务器只接收一条消息,只是为了测试,但如果您决定要能够聊多条消息,则必须使用您用于客户端类的额外线程。

祝你好运:)。

注意:我建议不要使用Queue(调用for的线程)来处理网络内容/可能需要一些时间的任何事情,否则您的应用程序GUI将实际冻结。