如何分组到2个客户端发送消息
How to group to 2 clients to send messages
我想做的是第 2 组客户并让他们相互交流。因此,如果连接了 2 个客户端,它们将只能相互通信,如果连接了第三个客户端,它将无法与其他 2 个客户端通信,但会创建另一组 2 个客户端,依此类推......我的下面的代码目前从一个客户端向所有客户端广播一条消息,但我希望它能像上面描述的那样工作,并且一直很难找到解决方案。感谢任何帮助。
public class ChatServer {
private static final int PORT = 9001;
private static HashSet<String> names = new HashSet<String>();
private static HashSet<PrintWriter> writers = new HashSet<PrintWriter>();
static int clientCounter = 0;
public static void main(String[] args) throws Exception {
System.out.println("The chat server is running.");
ServerSocket listener = new ServerSocket(PORT);
try {
while (true) {
new Handler(listener.accept()).start();
}
} finally {
listener.close();
}
}
private static class Handler extends Thread {
private String name;
private Socket socket;
private BufferedReader in;
private PrintWriter out;
public Handler(Socket socket) {
this.socket = socket;
}
public void run() {
try {
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(), true);
while (true) {
out.println("SUBMITNAME");
name = in.readLine();
if (name == null) {
return;
}
synchronized (names) {
if (!names.contains(name)) {
names.add(name);
break;
}
}
}
out.println("NAMEACCEPTED");
clientCounter++;
if (clientCounter > 0 && clientCounter <= 2) {
writers.add(out);
while (true) {
String input = in.readLine();
if (input == null) {
return;
}
for (PrintWriter writer : writers) {
writer.println("MESSAGE " + name + ": " + input);
}
}
} else {
clientCounter = 1;
}
} catch (IOException e) {
System.out.println(e);
} finally {
if (name != null) {
names.remove(name);
}
if (out != null) {
writers.remove(out);
}
try {
socket.close();
} catch (IOException e) {
}
}
}
}
}
我能想到的最简单的解决方案是:
制作一个 class 扩展线程并将两个套接字作为输入
所有这些class在运行中所做的就是等待任何东西被写入第一个套接字并将其发送到第二个套接字
您的主要功能只是等待连接
当它获得一个连接时,它接受它并保存套接字(我从现在起将其称为 socketA)但一直在等待第二个连接(因为您的聊天程序需要两个客户端)
一旦出现第二个连接,您就接受它(这将是 socketB)
它现在从你的 class 开始创建两个对象,一个以 socketA 作为第一个参数,socketB 作为第二个参数,另一个以 socketB 作为第一个参数,socketA 作为第二个参数
第一个实例负责从 socketA 向 socketB 发送消息,第二个实例负责从 socketB 向 socketA 发送消息,让我们两个聊天
你的 main 现在只需要等待下一个连接并从头“重启”
这是让它发挥作用的一种方法。首先,您需要修改接受连接的循环,以便它跟踪“先前接受的套接字”。当客户端连接时,您检查是否有 previousSocket
:如果没有,您将其当前套接字存储为 previousSocket
。如果有的话,你现在有两个已经连接的客户端,他们可以互相通信了:
Socket previousSocket = null;
while (true) {
Socket newSocket = listener.accept();
if (previousSocket == null) {
previousSocket = newSocket;
} else {
new Handler(previousSocket, newSocket).start();
new Handler(newSocket, previousSocket).start();
previousSocket = null;
}
}
您需要进行的另一项更改是将“对等”的概念添加到您的处理程序 class。对等方是您用来与其他客户端通信的套接字。然后,将向所有客户端发送消息的 for
循环替换为仅向对等方发送消息的代码:
peerOut.println("MESSAGE " + name + ": " + input);
这里有一个更完整的代码示例,用于修改后的 Handler class 来说明。为简洁起见,我省略了名称注册和错误处理 - 您需要将其添加回来。
private static class Handler extends Thread {
private String name;
private Socket socket;
private Socket peerSocket;
private BufferedReader in;
private PrintWriter out;
public Handler(Socket socket, Socket peerSocket) {
this.socket = socket;
this.peerSocket = peerSocket;
}
public void run() {
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
// name registration and error handling omitted for brevity
PrintWriter peerOut = new PrintWriter(peerSocket.getOutputStream(), true);
while (true) {
String input = in.readLine();
if (input == null) {
return;
}
// Replaces "for (PrintWriter writer : writers) { ... }"
peerOut.println("MESSAGE " + name + ": " + input);
}
}
}
我想做的是第 2 组客户并让他们相互交流。因此,如果连接了 2 个客户端,它们将只能相互通信,如果连接了第三个客户端,它将无法与其他 2 个客户端通信,但会创建另一组 2 个客户端,依此类推......我的下面的代码目前从一个客户端向所有客户端广播一条消息,但我希望它能像上面描述的那样工作,并且一直很难找到解决方案。感谢任何帮助。
public class ChatServer {
private static final int PORT = 9001;
private static HashSet<String> names = new HashSet<String>();
private static HashSet<PrintWriter> writers = new HashSet<PrintWriter>();
static int clientCounter = 0;
public static void main(String[] args) throws Exception {
System.out.println("The chat server is running.");
ServerSocket listener = new ServerSocket(PORT);
try {
while (true) {
new Handler(listener.accept()).start();
}
} finally {
listener.close();
}
}
private static class Handler extends Thread {
private String name;
private Socket socket;
private BufferedReader in;
private PrintWriter out;
public Handler(Socket socket) {
this.socket = socket;
}
public void run() {
try {
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(), true);
while (true) {
out.println("SUBMITNAME");
name = in.readLine();
if (name == null) {
return;
}
synchronized (names) {
if (!names.contains(name)) {
names.add(name);
break;
}
}
}
out.println("NAMEACCEPTED");
clientCounter++;
if (clientCounter > 0 && clientCounter <= 2) {
writers.add(out);
while (true) {
String input = in.readLine();
if (input == null) {
return;
}
for (PrintWriter writer : writers) {
writer.println("MESSAGE " + name + ": " + input);
}
}
} else {
clientCounter = 1;
}
} catch (IOException e) {
System.out.println(e);
} finally {
if (name != null) {
names.remove(name);
}
if (out != null) {
writers.remove(out);
}
try {
socket.close();
} catch (IOException e) {
}
}
}
}
}
我能想到的最简单的解决方案是:
制作一个 class 扩展线程并将两个套接字作为输入
所有这些class在运行中所做的就是等待任何东西被写入第一个套接字并将其发送到第二个套接字
您的主要功能只是等待连接
当它获得一个连接时,它接受它并保存套接字(我从现在起将其称为 socketA)但一直在等待第二个连接(因为您的聊天程序需要两个客户端)
一旦出现第二个连接,您就接受它(这将是 socketB)
它现在从你的 class 开始创建两个对象,一个以 socketA 作为第一个参数,socketB 作为第二个参数,另一个以 socketB 作为第一个参数,socketA 作为第二个参数
第一个实例负责从 socketA 向 socketB 发送消息,第二个实例负责从 socketB 向 socketA 发送消息,让我们两个聊天
你的 main 现在只需要等待下一个连接并从头“重启”
这是让它发挥作用的一种方法。首先,您需要修改接受连接的循环,以便它跟踪“先前接受的套接字”。当客户端连接时,您检查是否有 previousSocket
:如果没有,您将其当前套接字存储为 previousSocket
。如果有的话,你现在有两个已经连接的客户端,他们可以互相通信了:
Socket previousSocket = null;
while (true) {
Socket newSocket = listener.accept();
if (previousSocket == null) {
previousSocket = newSocket;
} else {
new Handler(previousSocket, newSocket).start();
new Handler(newSocket, previousSocket).start();
previousSocket = null;
}
}
您需要进行的另一项更改是将“对等”的概念添加到您的处理程序 class。对等方是您用来与其他客户端通信的套接字。然后,将向所有客户端发送消息的 for
循环替换为仅向对等方发送消息的代码:
peerOut.println("MESSAGE " + name + ": " + input);
这里有一个更完整的代码示例,用于修改后的 Handler class 来说明。为简洁起见,我省略了名称注册和错误处理 - 您需要将其添加回来。
private static class Handler extends Thread {
private String name;
private Socket socket;
private Socket peerSocket;
private BufferedReader in;
private PrintWriter out;
public Handler(Socket socket, Socket peerSocket) {
this.socket = socket;
this.peerSocket = peerSocket;
}
public void run() {
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
// name registration and error handling omitted for brevity
PrintWriter peerOut = new PrintWriter(peerSocket.getOutputStream(), true);
while (true) {
String input = in.readLine();
if (input == null) {
return;
}
// Replaces "for (PrintWriter writer : writers) { ... }"
peerOut.println("MESSAGE " + name + ": " + input);
}
}
}