Java:多线程聊天服务器仅向一个客户端发送消息

时间:2014-07-02 17:00:11

标签: java multithreading sockets

在我之前的问题得到很多帮助后,我终于试图建立一个多客户端。它不能正常工作,我会在发布完整代码之前尝试解释代码的基础知识。

基础课程:

ChatServer.Java - 启动ServerSocket。等待用户连接。将用户添加到ArrayList。为每个用户启动一个新线程。它启动的线程将等待来自客户端的输入和循环客户端列表并将消息发送给所有客户端。

CharServer2.Java:只是启动聊天服务器的GUI界面

Chat1:连接到套接字。发送和接收消息。两个动作都在不同的线程上

ChatClient.Java:用于Chat1触发器的GUI。

现在,如果我启动服务器并连接一个客户端,它可以正常工作。如果我添加两个客户端,事情会变得粗糙:(。

假设我添加了User1和User2。 User1发送消息:ConcurrentModificationException User2发送消息:没有异常。代码循环在Arraylist。 查找两个套接字并尝试向两者发送消息。但该消息仅到达用户1

我在代码中遇到的另一个问题是,每当我关闭任何一个用户的窗口时,ChatServer都会抛出套接字关闭的异常。请注意,这一切都发生在我的本地机器上。两个用户虽然占用不同的端口。

以下是整个代码:

ChatServer.Java

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.util.ArrayList;
import java.util.Date;
import java.util.Iterator;

public class ChatServer implements Runnable {

    private static int port; 
    private static String ip_add;
    private Socket socket;
    private ArrayList<Socket> clients;
    private ServerSocket ss;

    public ChatServer(String ip_add_in, int port_in) {
        // TODO Auto-generated constructor stub
        port = port_in;
        ip_add = ip_add_in;

        clients = new ArrayList<Socket>();
    }



    @Override
    public void run() {
        // TODO Auto-generated method stub

        System.out.println("ChatServer Start!!" + new Date() );

        try {
            ss = new ServerSocket(port, 10);

            while(true){
                socket = ss.accept();
                System.out.println("ChatServer Accepts!!" + new Date() );
                clients.add(socket);
                sendWelcomeMessage();

                Thread transmit = new Thread(new transmitMessagestoAll(socket));

                transmit.setName("" + socket.getPort());
                transmit.start();

//              (new Thread(new cleanUp(clients))).start();

                if(clients.isEmpty()) {
                    System.out.println("All users Gone");
                    break;
                }
            }


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


    }

    public void sendWelcomeMessage() {
// send message via writer
    }


    public class transmitMessagestoAll implements Runnable {

        private ArrayList<Socket> clientList;
        private Socket currentClient;
        private BufferedReader reader;
        private PrintWriter writer;
        String msg;
        public transmitMessagestoAll(Socket curr){

            clientList = new ArrayList<Socket>();
            clientList = clients;
            currentClient = curr;
        }


        @Override
        public void run() {
            // TODO Auto-generated method stub


            System.out.println(Thread.currentThread().getName());


            while(!clientList.isEmpty()){


                System.out.println(clientList.size());
                try {
                    reader = new BufferedReader(new InputStreamReader(currentClient.getInputStream()));
                    msg = reader.readLine();


                    while(msg!=null){
                        for (Socket thisClient : clientList) {
                            System.out.println(Thread.currentThread().getName() 
                                               + ">>>>>"
                                               + thisClient.getPort());
                            writer = new PrintWriter(thisClient.getOutputStream());

                            System.out.println("Transmitting");
                            writer.println(msg);
                            writer.flush();
                            msg = reader.readLine();
                        }
                        System.out.println("-----------------");
                    }

                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    System.out.println("All users Gone! Breaking");
                    e.printStackTrace();
                    break;


                }

            }



        }


    }

Chat1.Java

import java.awt.*; 
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.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.*;

import javax.swing.*;
import javax.xml.ws.handler.MessageContext.Scope;


public class Chat1 {

    JFrame frame;
    JPanel msg_pan, chat_pan,connect_pan;
    JButton send,connect;
    JTextField server_ip;
    JTextArea type_area, chat_area;

    private static String user;
    private SendMsg send_action = new SendMsg();
    private Connect connect_action = new Connect();
    private Socket writerSocket; 
    //  private Socket readerSocket;
    static String ip_address;
    static int port;
    private PrintWriter writer;
    private ReaderThread readerRunner;
    private SenderThread senderRunner;
    Thread senderThread;


    Thread  readerThread;

    public Chat1(String name, String ip_add_in, int port_in){
        user = name;
        ip_address = ip_add_in;
        port = port_in;

    }


    public void create_window() {

    // GUI and add action Listeners 

    }



    class SendMsg implements ActionListener{

        @Override
        public void actionPerformed(ActionEvent e) {
            // TODO Auto-generated method stub
            String msg = type_area.getText();

            if (msg != null && msg != "") {
                msg = user + " :: "  +  msg ;
                senderRunner = new SenderThread(msg);
                type_area.setText(null);
                senderThread = new Thread(senderRunner);
                senderThread.start();
            }



        }


    }



    public void startchat(){



        create_window();

//      System.out.println("Window Done");

        connect_socket();



    }

    public void connect_socket(){

        try {
            System.out.println("Start Chat" + new Date());
            System.out.println(ip_address);
            System.out.println(port);
            writerSocket = new Socket(ip_address,port);

            if(writerSocket.isBound())
            {
                readerRunner = new ReaderThread();
                readerThread = new Thread(readerRunner);
                readerThread.start();

                System.out.println("Thread Started");

            }

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


    }

    public class ReaderThread implements Runnable {

        InputStreamReader streamReader; 
        BufferedReader reader;
        String msg;

        public void run(){

            try {

                System.out.println("Entered ReaderThread Run");
                streamReader = new InputStreamReader(writerSocket.getInputStream());
                reader = new BufferedReader(streamReader);

                while (true) {
                    msg = reader.readLine();
                    if (msg != null) {
                        msg = msg + "\n";
                        chat_area.append(msg);  

                    }


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

            System.out.println("Leaving ReaderThread Run");

        }

    }

    public class SenderThread implements Runnable{

        String msg;
        public SenderThread(String msg_in){
            msg = msg_in + "\n";
        }

        public void run(){

            System.out.println("Entered SenderThread Run" + msg);


            try {

                if (writer == null) {
                    writer = new PrintWriter(writerSocket.getOutputStream());   
                }

                System.out.println("Writer has Error-->" + writer.checkError());

                writer.println(msg);
                writer.flush();
//              writer.close();

            } catch (UnknownHostException e) {
                // TODO Auto-generated catch block
                System.out.println("Sender Thread Run Exception 1");
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                System.out.println("Sender Thread Run Exception 2");
                e.printStackTrace();
            }

            System.out.println("Leaving SenderThread Run");

        }
    }

}

1 个答案:

答案 0 :(得分:0)

我在代码中发现了错误。当代码将消息推送到所有客户端时,有一个readLine方法调用,它有效地消除了文本,因此它将空白行推送到第二个和其他客户端。通过该修复,并发修改的问题也消失了。我可以为任何可能在类似行上工作的人发布完整的代码。只需添加评论即可发布..

代码更正: Class ChatServer

  • 内部类:transmitMessagestoAll
  • 方法运行,在clientList的循环内,对readLine的调用被移动到循环外部。