英文:
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) {
}
}
}
}
}
英文:
What i'm trying to do is group 2 clients and make them communicate with eachother. So if 2 clients are connected they would only be able to communicate with eachother and if a third client got connected it would not be able to communicate with the 2 other clients but it would create another group of 2 clients and so on... My code below currently broadcasts one message from one client to all clients but i would like it work like described above and have been having a difficult time finding a solution. Any help is appreciated.
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) {
}
}
}
}
}
答案1
得分: 1
我能想到的最简单的解决方案是:
创建一个继承自Thread的类,并将两个套接字作为输入参数。
这个类在运行时的主要操作是等待第一个套接字有任何写入操作,并将写入的内容发送到第二个套接字。
你的主函数只需要等待连接。
当它获得一个连接时,接受这个连接并保存这个套接字(我将其称为socketA),但仍然继续等待第二个连接(因为你的聊天程序需要两个客户端)。
一旦第二个连接建立,你同样接受它(这将是socketB)。
现在,你从一开始就创建两个类的实例,一个以socketA作为第一个参数,socketB作为第二个参数,另一个以socketB作为第一个参数,socketA作为第二个参数。
第一个实例负责将消息从socketA发送到socketB,第二个实例负责将消息从socketB发送到socketA,从而实现了双向聊天。
现在,你的主函数只需等待下一个连接并且可以从头开始处理。
英文:
The easiest Solution i can think of is:
make a class that extends thread and takes two sockets as input
all this class does in run is to wait for anything being written to the first socket and sending it to the second socket
your main function simply waits for connections
when it get's a connection it accepts it and saves the socket (i call it socketA from now) but keeps waiting for a second connection (because you need two clients for your chat program)
once a second connection comes you accept it (this will be socketB)
it now creates two objects from your class from the beginning, one taking socketA as first, socketB as second argument, the other one taking socketB as first and socketA as second argument
the first instance takes care of sending messages from socketA to socketB, the second from socketB to socketA which let's the two chat
your main now just has to wait for the next connection and "restart" from the beginning
答案2
得分: 1
这里有一种使它工作的方法。首先,您需要修改接受连接的循环,以便它跟踪“先前接受的套接字”。当客户端连接时,您会检查是否存在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;
}
}
您需要进行的另一项更改是在您的Handler类中添加“对等”的概念。对等是您用来与另一客户端通信的套接字。然后,您将向所有客户端发送消息的for
循环替换为仅向对等发送消息的代码:
peerOut.println("MESSAGE " + name + ": " + input);
以下是用于修改后的Handler类的更完整代码示例,用于说明。为了简洁起见,我省略了名称注册和错误处理 - 您需要添加回来。
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()));
// 省略名称注册和错误处理以节省空间
PrintWriter peerOut = new PrintWriter(peerSocket.getOutputStream(), true);
while (true) {
String input = in.readLine();
if (input == null) {
return;
}
// 替换 "for (PrintWriter writer : writers) { ... }"
peerOut.println("MESSAGE " + name + ": " + input);
}
}
}
英文:
Here's one way to make it work. First you need to modify the loop that accepts connections, so that it keeps track of a "previously accepted socket". When a client connects, you check if there is previousSocket
: if there isn't you store the current its socket as previousSocket
. If there is one, you now have two clients that have connected, and they can communicate with each other:
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;
}
}
The other change you will need is to add the concept of a "peer" to your Handler class. The peer is the socket that you use to communicate with the other client. Then you replace the for
loop that sends messages to all clients with code that sends the message to the peer only:
peerOut.println("MESSAGE " + name + ": " + input);
Here's a more complete code sample for the modified Handler class to illustrate. I've omitted the name registration and error handling for brevity - you'll need to add it back.
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);
}
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论