目前我有一个服务器和一个客户端,并且当客户端连接到服务器时,将创建一个线程来处理来自相应客户端的所有回复,并发送任何需要的答案。我现在的问题是,我需要能够通过每个现有线程向各自的客户端发送消息。
我正在考虑这样做:
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
中调用一个方法,该方法将向每个线程发送消息吗?
答案 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;
}
}
服务器输出:
客户端1的输出:
客户端2的输出:
客户端3输出:
答案 1 :(得分:0)
我会在ServerThread中创建一个静态方法getInstance(int threadId)。
在其中,您将创建一个同步的静态Map(请参见Collections类)。
在通知中,只需在地图上导航并将您的消息发送到ServerThread实例即可。
(注意:如果是TreMap,它将按键排序)