Java 多客户端聊天服务器私人消息选项



我是stackoverflow的新手,如果之前问过这种问题,我很抱歉,但进行了快速搜索,我找不到任何像我这样的标题。我正在开发一个关于Java的多客户端聊天应用程序。我正在按照教程进行操作,我可以发送应用程序中每个用户都可以看到的消息。但是我想知道如何在聊天中创建并向特定用户发送私人消息。

import java.io.*;
import java.net.*;
import java.util.HashSet;
import java.util.Set;
public class ChatServer {
private int port;
private Set<String> userNames = new HashSet<>();
private Set<UserThread> userThreads = new HashSet<>();
public ChatServer(int port) {
this.port = port;
}
public static void main(String[] args) {
new ChatServer(9999).execute();
}
private void execute() {
try {
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("Server is running");
while (true) {
Socket socket = serverSocket.accept();
System.out.println("New user connected");
UserThread newUser = new UserThread(socket, this);
userThreads.add(newUser);
newUser.start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
public void addUserName(String s) {
this.userNames.add(s);
}
public void broadcast(String serverMessage, UserThread excludeUser) {
for (UserThread aUser : userThreads) {
if (aUser != excludeUser)
aUser.sendMessage(serverMessage);
}
}
}

上面的代码是我的服务器代码。

public void run() {
Console console = System.console();
String userName = console.readLine("Enter your username : ");
writer.println(userName);
String text;
do {
text = console.readLine("[" + userName + "]: ");
if (text.startsWith("[")) {
isTargeted = true;
this.aimUserName = text.substring(text.indexOf("[") + 1, text.indexOf("]"));
//System.out.println("Private Message to: " + aimUserName);
} else {
isTargeted = false;
}
writer.println(text);
} while (!text.equals("bye"));
try {
socket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

上面的这段代码是我的 write thread 类的一部分。如您所见,如果消息以"[name]"部分开头,则"名称"表示我们要发送私人消息的用户。通过这样做,我可以获取要发送私人消息的用户的名称,但我无法弄清楚如何将此消息广播给该特定用户。我相信我需要在 ChatServer 类中配置我的广播功能,但我真的不知道该怎么做。我应该遵循哪些步骤?

--编辑--

我一直在研究我的问题,我做了一些补充来解决我的问题。首先,我认为我应该把我所拥有的一切分享给你。我之前分享了我的ChatServer类。我有的其他课程是:

import java.io.IOException;
import java.net.Socket;
public class ChatClient {
public static void main(String[] args) {
new ChatClient().execute();
}
private void execute() {
try {
Socket socket = new Socket("localhost", 3);
System.out.println("Connected to chat server");
new ReadThread(socket, this).start();
new WriteThread(socket, this).start();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
import java.net.*;
import java.io.*;
public class ReadThread extends Thread{
private BufferedReader reader;
private Socket socket;
private ChatClient client;
public ReadThread(Socket socket, ChatClient client) {
this.socket = socket;
this.client = client;
InputStream input;
try {
input = this.socket.getInputStream();
this.reader = new BufferedReader(new InputStreamReader(input));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void run() {
while(true) {
try {
String response = this.reader.readLine();
System.out.println("n" + response);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
break;
}
}
}
}
import java.net.Socket;
import java.io.*;
public class UserThread extends Thread {
private Socket socket;
private ChatServer server;
PrintWriter writer = null;
public String userName;
public UserThread(Socket socket, ChatServer chatServer) {
this.socket = socket;
this.server = chatServer;
}

public void run() {
try {
InputStream input = socket.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(input));
OutputStream output = socket.getOutputStream();
writer = new PrintWriter(output,true);
String userName = reader.readLine();
this.userName = userName;
server.addUserName(userName);
String serverMessage = "New user connected: " + userName;
server.broadcast(serverMessage,this);

String clientMessage;
do {
clientMessage = reader.readLine();
serverMessage = "[" + userName + "] : " + clientMessage;
server.broadcast(serverMessage, this);      
}while(!clientMessage.equals("bye"));

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

public void sendMessage(String serverMessage) {
writer.println(serverMessage);
}

}
import java.net.*;
import java.io.*;
public class WriteThread extends Thread {
private Socket socket;
private ChatClient client;
private PrintWriter writer;
public WriteThread(Socket socket, ChatClient client) {
this.socket = socket;
this.client = client;
OutputStream output;
try {
output = socket.getOutputStream();
this.writer = new PrintWriter(output, true);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void run() {
Console console = System.console();
String userName = console.readLine("Enter your username : ");
writer.println(userName);
String text;
do {
text = console.readLine("[" + userName + "]: ");
if(text.startsWith("[")){
String aimUserName = text.substring(text.indexOf("[")+1,text.indexOf("]"));
System.out.println("Private Message to: " + aimUserName);}
writer.println(text);
}while(!text.equals("bye"));
/*do {
text = console.readLine("[" + userName + "]: ");
writer.println(text);
}while(!text.equals("bye"));*/
try {
socket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

}

这些代码工作正常,我可以非常干净地进行多聊天。但是在处理私人聊天内容时,我在ChatServer中添加了以下行:

public void privatebr(String serverMessage, String targetUserName){
for(UserThread aUser: userThreads){
if(aUser.userName == targetUserName)
aUser.sendMessage(serverMessage);
}

到用户线程,我将部分编辑为:

String clientMessage;
do {
clientMessage = reader.readLine();
serverMessage = "[" + userName + "] : " + clientMessage;
if(clientMessage.startsWith("[")){
String targetUserName = clientMessage.substring(clientMessage.indexOf("[")+1,clientMessage.indexOf("]"));
serverMessage = "[" + userName + "] : " + clientMessage;
server.privatebr(serverMessage, targetUserName);
}else{
server.broadcast(serverMessage, this);
}

}while(!clientMessage.equals("bye"));

但是当我进行所有这些编辑时,正常的多聊天进度被破坏了,我的错在哪里?为什么一切都坏了?

好问题!要回答您提出的问题,您应该保持用户对其套接字连接的Map,以便使用 DM,您只需选择要发送消息的用户。您还需要一个消息传递协议(见下文)

。但我必须告诉你,在当今时代使用Sockets和SocketServer类就像重新发明轮子一样。从做聊天服务器开始的地方是使用 Web 套接字协议。即使在这下面,您可能也需要定义一个消息协议(就像我所做的那样 - 我使用 JSON 和消息类型创建了一个消息传递协议,其中 websocket 事件 onMessage 中的字符串消息首先被解析为一个对象)

在所有平台上都有支持WS的实现:java,.net,python,php等。这应该是你的起点。

---更新---

我明白你来自哪里。为了帮助您理解套接字/服务器套接字,这里有一些指针和资源

  1. DatagramSockets(又名UDP):这是一种与常规TCP不同的传输协议,由Shockwave和Flash使用,这是Flash出现问题的根本原因。我强烈建议不要这样做
  2. Data
  3. & Object Input/OutputStreams:"Data"流仅是Java(无法连接到在其他平台上构建的技术)。对象流是相似的,除了你通过流传输实际的整个对象(也只有Java)没有人*(几乎没有人)再使用这些对象了。
  4. 套接字异常:使用 java.net。[服务器]套接字,您可能会遇到此异常。当您在套接字上等待更多数据(通过读/读线调用)并且套接字关闭时,就会发生这种情况。我花了很长时间才弄清楚这一点,但这个例外是你的朋友!当连接关闭时(在客户端或服务器端),您可以获得它。它允许在套接字上等待的线程唤醒,并允许您执行需要执行的任何清理操作。SocketException 是 IOException 的一个子类,所以你甚至可能没有意识到这是什么。但现在至少我已经警告过你
  5. 流与写入器和读取器:写入器和读取器用于将原始字节解释为 Java 字符和字符串。这是必要的,因为有多种文本格式(即ascii,windows-xx,utf-8,utf-16)。阅读器和编写器可帮助您读取和写入不同文本格式的文本(还可以从图像格式解释图像)。
  6. 缓冲写入器和
  7. 流:这些用于低效读取和写入。对于写入,这意味着使您能够编写消息的一部分,并且在准备好之前不发送它。对于阅读,这意味着例如逐行阅读流,而不是一次性阅读所有内容。
  8. TUS:tjacobs/io - https://sourceforge.net/p/tus/code/HEAD/tree/tjacobs/io/这是我多年前放在SourceForge上的Java库的旧集合,但这里的许多类都与处理套接字有关。特别是,请参阅 SocketServerEx、DataFetcher、Main/App、Timeout 和 IOUtils。在所有内容中,请真正查看DataFetcher,这是一个用于回调I/O侦听的轻量级线程框架。

祝你好运,玩得开心!

最新更新