如何通过所有线程发送消息?

时间:2019-12-26 18:59:12

标签: java multithreading

目前我有一个服务器和一个客户端,并且当客户端连接到服务器时,将创建一个线程来处理来自相应客户端的所有回复,并发送任何需要的答案。我现在的问题是,我需要能够通过每个现有线程向各自的客户端发送消息。

我正在考虑这样做:

public class ServerThread extends Thread {
    //ignore most of the constructor, just things i need
    public ServerThread(Socket socket, int threadId, Manager manager) throws Exception {
        try {
            this.socket = socket;
            this.threadId=threadId;
            this.manager=manager;
            in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
            manager.addThread(); //This should add this Thread to the Collection in the Manager class      
        } catch (IOException ex) {
            throw new Exception("Error", ex);
        }
    }


    public void notify(String message){
        // Do something
    }

    //In the end of the thread i would call manager.removeThread to remove the Thread from the Collection

}

public class Manager {

    private //Thread Collection here

    public Manager(){
         //Initialize the collection;
    }

    public void addThread(){
        //Add thread
    }

    public void removeThread(){
        //Remove Thread
    }
}

如果这是一个可行的解决方案,那么我需要什么Collection来存储线程,以及notify(String message)方法的外观如何?它需要在Manager中调用一个方法,该方法将向每个线程发送消息吗?

2 个答案:

答案 0 :(得分:1)

如果要创建多客户端服务器,通常建议在服务器类的主线程(或单独的线程)中,服务器将接受传入的套接字(客户端),并且每个套接字都接受创建新线程来为该客户端提供服务,最好将服务作为实现可运行或扩展线程的单独类来使用。 每个服务线程将等待与之关联的客户端的输入,并根据客户端的请求进行回复。

如果您希望向所有连接的客户端广播数据,那么您需要具有一个存储客户端服务对象的ArrayList,然后遍历它,每次循环都将数据发送到其中一个已连接的客户端,但是您必须确保删除与ArrayList断开连接的客户端,否则它将开始引发异常。

通常,客户端服务类具有接受的套接字,输入流和输出流。

这是我制作的多客户端回显服务器的一个示例,也许会对您有所帮助。

public class TcpServer {

public TcpServer(){
    ServerSocket server = null;
    try{
        server = new ServerSocket(9991);
        while(!server.isClosed()){
            Socket acceptedSocket = server.accept();
            EchoService service = new EchoService(acceptedSocket);
            service.start();

        }
    }catch (IOException e){
        e.printStackTrace();
    } finally {
        if(server!=null) {
            try {
                server.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

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

这是服务类别:

public class EchoService extends Thread {
private Socket acceptedSocket;
private DataInputStream is;
private DataOutputStream os;

public EchoService(Socket acceptedSocket) {
    try {
        this.acceptedSocket = acceptedSocket;
        is = new DataInputStream(acceptedSocket.getInputStream());
        os = new DataOutputStream(acceptedSocket.getOutputStream());
    } catch (IOException e) {
        try {
            if (this.acceptedSocket != null)
                acceptedSocket.close();
            if(is != null)
                is.close();
            if(os != null)
                os.close();
        } catch (IOException e1) {
            e1.printStackTrace();
        }
    }
}


@Override
public void run() {
    super.run();
    try {
        while (!acceptedSocket.isClosed()) {
            String usrMsg = is.readUTF();
            String serverMsg = "server: "+usrMsg;
            os.writeUTF(serverMsg);
            os.flush();
        }
    } catch (IOException e) {
        try {
            if(this.acceptedSocket != null)
                acceptedSocket.close();
            if(is != null)
                is.close();
            if(os != null)
                os.close();
        } catch (IOException e1) {
            e1.printStackTrace();
        }
    }
}}

这是相同的示例,但具有广播功能

服务器类:

package TCP;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;

public class TcpServer {
public static ArrayList<EchoService> connectedServices;

public TcpServer(){
    ServerSocket server = null;
    try{
        server = new ServerSocket(9991);
        System.out.println("server started");
        connectedServices = new ArrayList<>();
        while(!server.isClosed()){
            Socket acceptedSocket = server.accept();
            System.out.println("client connected: " 
            +acceptedSocket.getInetAddress());
            EchoService service = new EchoService(acceptedSocket);
            service.start();

        }
    }catch (IOException e){
        e.printStackTrace();
    } finally {
        if(server!=null) {
            try {
                server.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

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

public static void removeConnectedService(EchoService client) {
    boolean removed = connectedServices.remove(client);
    System.out.println("client has been removed"+ 
    client.getAcceptedSocket().getInetAddress()+", "+removed);
}

public static void broadCastMsg(long id, String usrMsg) throws IOException {
    for(EchoService client: connectedServices){
        if(client.getId()!=id)
        {
            String serverMsg = "server broadcast: " + usrMsg;
            client.getOs().writeUTF(serverMsg);
            client.getOs().flush();
        }
    }

}
}

服务类别:

    package TCP;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;

public class EchoService extends Thread {
    private Socket acceptedSocket;
    private DataInputStream is;
    private DataOutputStream os;

    public EchoService(Socket acceptedSocket) {
        try {
            this.acceptedSocket = acceptedSocket;
            is = new DataInputStream(acceptedSocket.getInputStream());
            os = new DataOutputStream(acceptedSocket.getOutputStream());

        } catch (IOException e) {
            try {
                if (this.acceptedSocket != null)
                    acceptedSocket.close();
                if(is != null)
                    is.close();
                if(os != null)
                    os.close();
            } catch (IOException e1) {
                e1.printStackTrace();
            }
        }
    }


    @Override
    public void run() {
        super.run();
        try {
            TcpServer.connectedServices.add(this);
            while (!acceptedSocket.isClosed()) {
                String usrMsg = is.readUTF();
                if(usrMsg.contains("BROADCAST"))
                    TcpServer.broadCastMsg(this.getId(),usrMsg);
                else {
                    String serverMsg = "server: " + usrMsg;
                    os.writeUTF(serverMsg);
                    os.flush();
                }
            }
        } catch (IOException e) {
            TcpServer.removeConnectedService(this);
            try {
                if(this.acceptedSocket != null)
                    acceptedSocket.close();
                if(is != null)
                    is.close();
                if(os != null)
                    os.close();
            } catch (IOException e1) {
                e1.printStackTrace();
            }
        }
    }

    public DataInputStream getIs() {
        return is;
    }

    public DataOutputStream getOs() {
        return os;
    }

    public Socket getAcceptedSocket() {
        return acceptedSocket;
    }
}

服务器输出:

enter image description here

客户端1的输出:

enter image description here

客户端2的输出:

enter image description here

客户端3输出:

enter image description here

答案 1 :(得分:0)

我会在ServerThread中创建一个静态方法getInstance(int threadId)。

在其中,您将创建一个同步的静态Map(请参见Collections类)。

在通知中,只需在地图上导航并将您的消息发送到ServerThread实例即可。

(注意:如果是TreMap,它将按键排序)

相关问题