客户端-服务器聊天应用程序 - 消息在 fwd_all 和 add_user 方法中重复,但我该如何解决?
Client-Server Chat App - Messages are duplicating within the fwd_all and add_user methods but how do I resolve?
如上所述,我的问题是在 add user 和 fwd all 这两个方法中,我已经进行了一些调试,发现重复是在那里引起的,我想知道我的源代码中是否还有其他地方导致功能异常?
下面是服务器的源代码 class 我可以确认这是问题的根源:
public class TCP_Server extends javax.swing.JFrame {
ArrayList<String> C_Username; // Arraylist of users connected to the server
ArrayList C_OutStream; // Preparing Arraylist of output streams to client
/**
* Constructor to initialise the jFrame via 'generated code'.
*/
public TCP_Server() {
initComponents();
Chat_LogS.setEditable(false); // textarea not interactable
}
/**
* Client handler uses the interface 'Runnable' for multi-threading to
* provide responsiveness in the snippet of code below that connect or
* disconnect clients while processes operate 'concurrently'.
*/
public class ClientHandler implements Runnable {
BufferedReader from_Client; // Data buffer from client
Socket connection; // Part of communication channel
PrintWriter client; // format data as text (UTF-8)
public ClientHandler(Socket clientSocket, PrintWriter user) {
client = user;
try {
/* Opens the communication channel */
connection = clientSocket;
/* Prepares the input streams */
InputStreamReader in_Client = new InputStreamReader(connection.getInputStream());
from_Client = new BufferedReader(in_Client);
} catch (Exception ex) {
/* If communication isn't successful */
Chat_LogS.append("Unexpected exception occurerd \n");
}
}
/**
* Method of Runnable interface for 'thread safe operation' of connect
* or disconnect users from the chat.
*/
@Override
public void run() {
/* Correspond to dialogue provided in the if statement */
String msg;
String connect = "Connect";
String disconnect = "Disconnect";
String chat = "Chat";
String[] data;
/* Enclosed in try catch block, server is to reply to client */
try {
while ((msg = from_Client.readLine()) != null) {
/* Response of server in textarea */
Chat_LogS.append("Received: " + msg + "\n");
/* Split array of string to substrings via ':' */
data = msg.split(":");
for (String token : data) {
Chat_LogS.append(token + "\n");
}
/* If statement for corresponding words declared above */
// Here are squiggly lines due to absent long data type...
if (data[2].equals(connect)) {
fwd_All((data[0] + ":" + data[1] + ":" + chat));
Add_User(data[0]);
} else if (data[2].equals(disconnect)) {
fwd_All((data[0] + ":has left the chat" + ":" + chat));
Remove_User(data[0]);
} else if (data[2].equals(chat)) {
fwd_All(msg);
} else {
Chat_LogS.append("No condition is met \n");
}
}
} catch (Exception ex) {
Chat_LogS.append("Connection for a user is lost \n");
C_OutStream.remove(client);
}
}
}
/* Auto generated code can be modified in JFrame */
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
jScrollPane1 = new javax.swing.JScrollPane();
Chat_LogS = new javax.swing.JTextArea();
Start_Btn = new javax.swing.JButton();
Online_Btn = new javax.swing.JButton();
Clear_Btn = new javax.swing.JButton();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
setTitle("Server Frame");
setName("server"); // NOI18N
setResizable(false);
Chat_LogS.setColumns(20);
Chat_LogS.setRows(5);
jScrollPane1.setViewportView(Chat_LogS);
Start_Btn.setText("Start Server");
Start_Btn.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
Start_BtnActionPerformed(evt);
}
});
Online_Btn.setText("Online Users");
Online_Btn.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
Online_BtnActionPerformed(evt);
}
});
Clear_Btn.setText("Clean Page");
Clear_Btn.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
Clear_BtnActionPerformed(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(Start_Btn)
.addGap(18, 18, 18)
.addComponent(Online_Btn, javax.swing.GroupLayout.PREFERRED_SIZE, 138, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(18, 18, 18)
.addComponent(Clear_Btn, javax.swing.GroupLayout.PREFERRED_SIZE, 103, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(jScrollPane1))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 265, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(Clear_Btn)
.addComponent(Online_Btn)
.addComponent(Start_Btn))
.addContainerGap())
);
pack();
}// </editor-fold>
/* Available to open communication channel and accept client(s) request */
private void Start_BtnActionPerformed(java.awt.event.ActionEvent evt) {
Thread starter = new Thread(new ServerStart());
starter.start();
Chat_LogS.append("*Server is Activated* \n");
}
/* Print in the server chat log: list of users connected to chat server */
private void Online_BtnActionPerformed(java.awt.event.ActionEvent evt) {
Chat_LogS.append("Online users: \n");
for (String current_user : C_Username) {
Chat_LogS.append(current_user + "\n");
}
}
/* Clean 'slate' of the server chat log */
private void Clear_BtnActionPerformed(java.awt.event.ActionEvent evt) {
Chat_LogS.setText("");
}
/* Main method to execute the server class UI */
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
new TCP_Server().setVisible(true);
}
});
}
// Did I do anything wrong in here?
public class ServerStart implements Runnable {
@Override
public void run() {
C_OutStream = new ArrayList();
C_Username = new ArrayList();
long id = 1L;
try {
/* Opens the communication channel */
ServerSocket serverSock = new ServerSocket(1183);
while (true) {
/* Accepting client request */
Socket clientSock = serverSock.accept();
/* Sending response to client */
PrintWriter wr = new PrintWriter(clientSock.getOutputStream());
C_OutStream.add(wr);
/* Communicates with client handler class - accepting connections*/
Thread listener = new Thread(new ClientHandler(clientSock, wr));
listener.start();
Chat_LogS.append("Connection Successful \n");
}
} catch (Exception ex) {
Chat_LogS.append("Experiencing Connectivity Issues \n");
}
}
}
/* Server approves new client to join the chatroom */
// Made changes here for the ID
public void Add_User(String data) {
String msg;
String add = ": :Connect";
String done = "Server: :Done";
String name = data;
C_Username.add(name);
Chat_LogS.append("New member: " + name + " has joined \n");
String[] tempList = new String[(C_Username.size())];
C_Username.toArray(tempList);
for (String tkn : tempList) {
msg = (tkn + add);
fwd_All(msg);
}
fwd_All(done);
}
/* Sever approves of client request to be removed from chat room */
// Made changes here for the ID
public void Remove_User(String data) {
String msg;
String add = ": :Connect";
String done = "Server: :Done";
String name = data;
C_Username.remove(name);
String[] tempList = new String[(C_Username.size())];
C_Username.toArray(tempList);
for (String token : tempList) {
msg = (token + add);
fwd_All(msg);
}
fwd_All(done);
}
/* Iterates to all clients connected to the server */
// This is a problem; it sends same dialogue twice!!!
// I dont know if the implementation is done correct.
public void fwd_All(String msg) {
Iterator it = C_OutStream.iterator();
while (it.hasNext()) {
try {
PrintWriter wr = (PrintWriter) it.next();
wr.println(msg); // Recipient of message
Chat_LogS.append("Sending to: " + msg + "\n");
wr.flush();
//Chat_LogS.setCaretPosition(Chat_LogS.getDocument().getLength());
} catch (Exception ex) {
Chat_LogS.append("Error forwarding message \n");
}
}
}
// Variables declaration - do not modify
private javax.swing.JTextArea Chat_LogS;
private javax.swing.JButton Clear_Btn;
private javax.swing.JButton Online_Btn;
private javax.swing.JButton Start_Btn;
private javax.swing.JScrollPane jScrollPane1;
// End of variables declaration
}
以下是在聊天室中连接新用户后服务器日志中产生的输出:
// When second user connects
Connection Successful
Received: Vincent:has connected:Connect
Vincent
has connected
Connect
Sending to: Vincent:has connected:Chat
Sending to: Vincent:has connected:Chat
New member: Vincent has joined
Sending to: Bruce: :Connect
Sending to: Bruce: :Connect
Sending to: Vincent: :Connect
Sending to: Vincent: :Connect
Sending to: Server: :Done
Sending to: Server: :Done
感谢 sudipn,我找到了解决方案,这是因为 chatlogS 附加在转发消息的 while 循环内:
这里是所做的更改:
/* Iterates to all clients connected to the server */
public void fwd_All(String msg) {
Iterator it = C_OutStream.iterator();
Chat_LogS.append("Forwarding Message: " + msg + "\n"); // NEW
Chat_LogS.setCaretPosition(Chat_LogS.getDocument().getLength()); //NEW
while (it.hasNext()) {
try {
PrintWriter wr = (PrintWriter) it.next();
wr.println(msg); // Recipient of message
wr.flush();
} catch (Exception ex) {
Chat_LogS.append("Error forwarding message \n");
}
}
}
这是现在的输出:
Connection Successful
Received: Bruce:has connected:Connect
Forwarding Message: Bruce:has connected:Chat
New member: Bruce has joined
Forwarding Message: Vincent: :Connect
Forwarding Message: Bruce: :Connect
Forwarding Message: Server: :Done
即使发送消息:
Received: Bruce:Hello:Chat
Forwarding Message: Bruce:Hello:Chat
Received: Vincent:Greetings:Chat
Forwarding Message: Vincent:Greetings:Chat
您的错误的原因是两个循环:
Add_User
中的第一个for (String tkn : tempList) {
- 和
fwd_All
里面的第二个while (it.hasNext()) {
从第一个循环开始,调用 fwd_All
,第二个循环 运行。
当数组只有一个元素时(用户Bruce),for
在Add_User
中循环一次运行在此 运行 中,它调用 fwd_All
,其中 while
循环也 运行 一次。
现在当 C_Username
数组中有两个元素(Bruce 和 Vincent)时,for
在 Add_User
方法 运行s 中循环两次。在用户 Bruce 的 for
循环的第一个 运行 中,它调用 fwd_All
并且现在在此方法中 while 循环迭代两次(因为C_Outstream
中有两个条目)。因此,您会看到重复的输出。 while 循环结束后,控件移回 for
循环,第二个用户 运行s 然后再次调用 fwd_All
方法和迭代器 运行s两次。
调试您的代码以获得更好的理解。我希望这可以解释为什么您的日志数量不断增加。
提示:两个数组列表(C_Username
、C_OutStream
)是相互关联的。所以一个快速的解决办法是:
public void Add_User(String data) {
String msg;
String add = ": :Connect";
String done = "Server: :Done";
String name = data;
C_Username.add(name);
Chat_LogS.append("New member: " + name + " has joined \n");
for (int i = 0; i < C_Username.size(); i++) {
PrintWriter wr = C_OutStream[i];
msg = C_Username[i] + add;
fwd(msg, wr);
fwd(done, wr);
}
}
private void fwd(String msg, PrintWriter wr) {
try {
wr.println(msg); // Recipient of message
Chat_LogS.append("Sending to: " + msg + "\n");
wr.flush();
} catch (Exception ex) {
Chat_LogS.append("Error forwarding message \n");
}
}
与 Remove_User
相似。
如上所述,我的问题是在 add user 和 fwd all 这两个方法中,我已经进行了一些调试,发现重复是在那里引起的,我想知道我的源代码中是否还有其他地方导致功能异常?
下面是服务器的源代码 class 我可以确认这是问题的根源:
public class TCP_Server extends javax.swing.JFrame {
ArrayList<String> C_Username; // Arraylist of users connected to the server
ArrayList C_OutStream; // Preparing Arraylist of output streams to client
/**
* Constructor to initialise the jFrame via 'generated code'.
*/
public TCP_Server() {
initComponents();
Chat_LogS.setEditable(false); // textarea not interactable
}
/**
* Client handler uses the interface 'Runnable' for multi-threading to
* provide responsiveness in the snippet of code below that connect or
* disconnect clients while processes operate 'concurrently'.
*/
public class ClientHandler implements Runnable {
BufferedReader from_Client; // Data buffer from client
Socket connection; // Part of communication channel
PrintWriter client; // format data as text (UTF-8)
public ClientHandler(Socket clientSocket, PrintWriter user) {
client = user;
try {
/* Opens the communication channel */
connection = clientSocket;
/* Prepares the input streams */
InputStreamReader in_Client = new InputStreamReader(connection.getInputStream());
from_Client = new BufferedReader(in_Client);
} catch (Exception ex) {
/* If communication isn't successful */
Chat_LogS.append("Unexpected exception occurerd \n");
}
}
/**
* Method of Runnable interface for 'thread safe operation' of connect
* or disconnect users from the chat.
*/
@Override
public void run() {
/* Correspond to dialogue provided in the if statement */
String msg;
String connect = "Connect";
String disconnect = "Disconnect";
String chat = "Chat";
String[] data;
/* Enclosed in try catch block, server is to reply to client */
try {
while ((msg = from_Client.readLine()) != null) {
/* Response of server in textarea */
Chat_LogS.append("Received: " + msg + "\n");
/* Split array of string to substrings via ':' */
data = msg.split(":");
for (String token : data) {
Chat_LogS.append(token + "\n");
}
/* If statement for corresponding words declared above */
// Here are squiggly lines due to absent long data type...
if (data[2].equals(connect)) {
fwd_All((data[0] + ":" + data[1] + ":" + chat));
Add_User(data[0]);
} else if (data[2].equals(disconnect)) {
fwd_All((data[0] + ":has left the chat" + ":" + chat));
Remove_User(data[0]);
} else if (data[2].equals(chat)) {
fwd_All(msg);
} else {
Chat_LogS.append("No condition is met \n");
}
}
} catch (Exception ex) {
Chat_LogS.append("Connection for a user is lost \n");
C_OutStream.remove(client);
}
}
}
/* Auto generated code can be modified in JFrame */
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
jScrollPane1 = new javax.swing.JScrollPane();
Chat_LogS = new javax.swing.JTextArea();
Start_Btn = new javax.swing.JButton();
Online_Btn = new javax.swing.JButton();
Clear_Btn = new javax.swing.JButton();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
setTitle("Server Frame");
setName("server"); // NOI18N
setResizable(false);
Chat_LogS.setColumns(20);
Chat_LogS.setRows(5);
jScrollPane1.setViewportView(Chat_LogS);
Start_Btn.setText("Start Server");
Start_Btn.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
Start_BtnActionPerformed(evt);
}
});
Online_Btn.setText("Online Users");
Online_Btn.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
Online_BtnActionPerformed(evt);
}
});
Clear_Btn.setText("Clean Page");
Clear_Btn.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
Clear_BtnActionPerformed(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(Start_Btn)
.addGap(18, 18, 18)
.addComponent(Online_Btn, javax.swing.GroupLayout.PREFERRED_SIZE, 138, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(18, 18, 18)
.addComponent(Clear_Btn, javax.swing.GroupLayout.PREFERRED_SIZE, 103, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(jScrollPane1))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 265, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(Clear_Btn)
.addComponent(Online_Btn)
.addComponent(Start_Btn))
.addContainerGap())
);
pack();
}// </editor-fold>
/* Available to open communication channel and accept client(s) request */
private void Start_BtnActionPerformed(java.awt.event.ActionEvent evt) {
Thread starter = new Thread(new ServerStart());
starter.start();
Chat_LogS.append("*Server is Activated* \n");
}
/* Print in the server chat log: list of users connected to chat server */
private void Online_BtnActionPerformed(java.awt.event.ActionEvent evt) {
Chat_LogS.append("Online users: \n");
for (String current_user : C_Username) {
Chat_LogS.append(current_user + "\n");
}
}
/* Clean 'slate' of the server chat log */
private void Clear_BtnActionPerformed(java.awt.event.ActionEvent evt) {
Chat_LogS.setText("");
}
/* Main method to execute the server class UI */
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
new TCP_Server().setVisible(true);
}
});
}
// Did I do anything wrong in here?
public class ServerStart implements Runnable {
@Override
public void run() {
C_OutStream = new ArrayList();
C_Username = new ArrayList();
long id = 1L;
try {
/* Opens the communication channel */
ServerSocket serverSock = new ServerSocket(1183);
while (true) {
/* Accepting client request */
Socket clientSock = serverSock.accept();
/* Sending response to client */
PrintWriter wr = new PrintWriter(clientSock.getOutputStream());
C_OutStream.add(wr);
/* Communicates with client handler class - accepting connections*/
Thread listener = new Thread(new ClientHandler(clientSock, wr));
listener.start();
Chat_LogS.append("Connection Successful \n");
}
} catch (Exception ex) {
Chat_LogS.append("Experiencing Connectivity Issues \n");
}
}
}
/* Server approves new client to join the chatroom */
// Made changes here for the ID
public void Add_User(String data) {
String msg;
String add = ": :Connect";
String done = "Server: :Done";
String name = data;
C_Username.add(name);
Chat_LogS.append("New member: " + name + " has joined \n");
String[] tempList = new String[(C_Username.size())];
C_Username.toArray(tempList);
for (String tkn : tempList) {
msg = (tkn + add);
fwd_All(msg);
}
fwd_All(done);
}
/* Sever approves of client request to be removed from chat room */
// Made changes here for the ID
public void Remove_User(String data) {
String msg;
String add = ": :Connect";
String done = "Server: :Done";
String name = data;
C_Username.remove(name);
String[] tempList = new String[(C_Username.size())];
C_Username.toArray(tempList);
for (String token : tempList) {
msg = (token + add);
fwd_All(msg);
}
fwd_All(done);
}
/* Iterates to all clients connected to the server */
// This is a problem; it sends same dialogue twice!!!
// I dont know if the implementation is done correct.
public void fwd_All(String msg) {
Iterator it = C_OutStream.iterator();
while (it.hasNext()) {
try {
PrintWriter wr = (PrintWriter) it.next();
wr.println(msg); // Recipient of message
Chat_LogS.append("Sending to: " + msg + "\n");
wr.flush();
//Chat_LogS.setCaretPosition(Chat_LogS.getDocument().getLength());
} catch (Exception ex) {
Chat_LogS.append("Error forwarding message \n");
}
}
}
// Variables declaration - do not modify
private javax.swing.JTextArea Chat_LogS;
private javax.swing.JButton Clear_Btn;
private javax.swing.JButton Online_Btn;
private javax.swing.JButton Start_Btn;
private javax.swing.JScrollPane jScrollPane1;
// End of variables declaration
}
以下是在聊天室中连接新用户后服务器日志中产生的输出:
// When second user connects
Connection Successful
Received: Vincent:has connected:Connect
Vincent
has connected
Connect
Sending to: Vincent:has connected:Chat
Sending to: Vincent:has connected:Chat
New member: Vincent has joined
Sending to: Bruce: :Connect
Sending to: Bruce: :Connect
Sending to: Vincent: :Connect
Sending to: Vincent: :Connect
Sending to: Server: :Done
Sending to: Server: :Done
感谢 sudipn,我找到了解决方案,这是因为 chatlogS 附加在转发消息的 while 循环内:
这里是所做的更改:
/* Iterates to all clients connected to the server */
public void fwd_All(String msg) {
Iterator it = C_OutStream.iterator();
Chat_LogS.append("Forwarding Message: " + msg + "\n"); // NEW
Chat_LogS.setCaretPosition(Chat_LogS.getDocument().getLength()); //NEW
while (it.hasNext()) {
try {
PrintWriter wr = (PrintWriter) it.next();
wr.println(msg); // Recipient of message
wr.flush();
} catch (Exception ex) {
Chat_LogS.append("Error forwarding message \n");
}
}
}
这是现在的输出:
Connection Successful
Received: Bruce:has connected:Connect
Forwarding Message: Bruce:has connected:Chat
New member: Bruce has joined
Forwarding Message: Vincent: :Connect
Forwarding Message: Bruce: :Connect
Forwarding Message: Server: :Done
即使发送消息:
Received: Bruce:Hello:Chat
Forwarding Message: Bruce:Hello:Chat
Received: Vincent:Greetings:Chat
Forwarding Message: Vincent:Greetings:Chat
您的错误的原因是两个循环:
Add_User
中的第一个for (String tkn : tempList) {
- 和
fwd_All
里面的第二个while (it.hasNext()) {
从第一个循环开始,调用 fwd_All
,第二个循环 运行。
当数组只有一个元素时(用户Bruce),for
在Add_User
中循环一次运行在此 运行 中,它调用 fwd_All
,其中 while
循环也 运行 一次。
现在当 C_Username
数组中有两个元素(Bruce 和 Vincent)时,for
在 Add_User
方法 运行s 中循环两次。在用户 Bruce 的 for
循环的第一个 运行 中,它调用 fwd_All
并且现在在此方法中 while 循环迭代两次(因为C_Outstream
中有两个条目)。因此,您会看到重复的输出。 while 循环结束后,控件移回 for
循环,第二个用户 运行s 然后再次调用 fwd_All
方法和迭代器 运行s两次。
调试您的代码以获得更好的理解。我希望这可以解释为什么您的日志数量不断增加。
提示:两个数组列表(C_Username
、C_OutStream
)是相互关联的。所以一个快速的解决办法是:
public void Add_User(String data) {
String msg;
String add = ": :Connect";
String done = "Server: :Done";
String name = data;
C_Username.add(name);
Chat_LogS.append("New member: " + name + " has joined \n");
for (int i = 0; i < C_Username.size(); i++) {
PrintWriter wr = C_OutStream[i];
msg = C_Username[i] + add;
fwd(msg, wr);
fwd(done, wr);
}
}
private void fwd(String msg, PrintWriter wr) {
try {
wr.println(msg); // Recipient of message
Chat_LogS.append("Sending to: " + msg + "\n");
wr.flush();
} catch (Exception ex) {
Chat_LogS.append("Error forwarding message \n");
}
}
与 Remove_User
相似。