多线程服务器-客户端应用程序多次发送响应
Multithreaded server-client application sends multiple time the response
我有一个多线程服务器-客户端应用程序。当我尝试在客户端之间进行通信时,我尝试发送的消息被发送了多次(例如,当我连接了 2-3 个客户端时,消息发送了 2 次,当我连接了 10 个客户端时,消息被发送了 6 次)。这是代码:
ServerProtocol
Class:
public class ServerProtocol {
private String nick;
private final ClientConn conn;
private static final HashMap < String, ClientConn > nicks = new HashMap < > ();
private static final String msg_WELCOME = "You are connected to server";
private static final String msg_OK = "Message sent";
private static final String msg_NICK_IN_USE = "Nick in use";
private static final String msg_SEND_FAILED = "Failed to send";
public ServerProtocol(ClientConn c) {
nick = null;
conn = c;
}
private byte[] authenticate(String mesaj) {
String id = mesaj.substring(0, 1);
if (!nicks.containsKey(id)) {
nicks.put(id, this.conn);
System.out.println(id + " joined.");
this.nick = id;
return msg_WELCOME.getBytes();
} else {
return msg_NICK_IN_USE.getBytes();
}
}
public boolean sendMsgCSP(String recipient, String msg) throws IOException {
if (nicks.containsKey(recipient)) {
int e = nicks.size();
for (int i = 0; i < e; i++) {
ClientConn c = nicks.get(recipient);
//c.sendMsgCC(nick.getBytes());
c.sendMsgCC(msg.getBytes());
System.out.println("message sent: " + msg + " to client " + recipient);
}
return true;
} else {
return false;
}
}
public byte[] process(byte[] msg) throws IOException {
//System.out.println(Arrays.toString(msg));
String mesaj = new String(msg);
if (!nicks.containsKey(nick)) {
return authenticate(mesaj);
}
System.out.println("message:" + mesaj);
if (sendMsgCSP(mesaj.substring(0, 1), mesaj.substring(1))) {
return msg_OK.getBytes();
} else {
return msg_SEND_FAILED.getBytes();
}
}
}
ClientConn
Class:
public class ClientConn implements Runnable {
private final Socket clients;
private OutputStream os;
private DataOutputStream dos;
private InputStream is;
private DataInputStream dis;
ClientConn(Socket client) {
this.clients = client;
try {
is = clients.getInputStream();
dis = new DataInputStream(is);
os = clients.getOutputStream();
dos = new DataOutputStream(os);
} catch (IOException ex) {
Logger.getLogger(ClientConn.class.getName()).log(Level.SEVERE, null, ex);
}
}
@Override
public void run() {
byte[] read, response;
ServerProtocol protocol = new ServerProtocol(this);
try {
while (true) {
read = readBytes();
//System.out.println(Arrays.toString(rd));
//System.out.println("message received: " + Arrays.toString(read));
response = protocol.process(read);
sendMsgCC(response);
}
} catch (IOException ex) {
System.out.println(ex);
}
}
public void sendMsgCC(byte[] myByteArray) throws IOException {
int start = 0;
int len = myByteArray.length;
if (len < 0) {
throw new IllegalArgumentException("Negative length not allowed");
}
if (start < 0 || start >= myByteArray.length) {
throw new IndexOutOfBoundsException("Out of bounds: " + start);
}
dos.writeInt(len);
if (len > 0) {
dos.write(myByteArray, start, len);
}
}
public byte[] readBytes() throws IOException {
int len = dis.readInt();
byte[] data = new byte[len];
if (len > 0) {
dis.readFully(data);
}
return data;
}
}
我认为问题出在 sendMsgCC 方法上,但我无法弄清楚
此处:
for (int i = 0; i < e; i++) {
ClientConn c = nicks.get(recipient);
c.sendMsgCC(msg.getBytes());
System.out.println("message sent: " + msg + " to client " + recipient);
}
您向收件人发送消息的次数与已连接客户端的次数一样多。为什么循环?
还有你的代码在没有同步或锁的情况下从多个线程读取和写入共享数据,请做好应对问题的准备。
我有一个多线程服务器-客户端应用程序。当我尝试在客户端之间进行通信时,我尝试发送的消息被发送了多次(例如,当我连接了 2-3 个客户端时,消息发送了 2 次,当我连接了 10 个客户端时,消息被发送了 6 次)。这是代码:
ServerProtocol
Class:
public class ServerProtocol {
private String nick;
private final ClientConn conn;
private static final HashMap < String, ClientConn > nicks = new HashMap < > ();
private static final String msg_WELCOME = "You are connected to server";
private static final String msg_OK = "Message sent";
private static final String msg_NICK_IN_USE = "Nick in use";
private static final String msg_SEND_FAILED = "Failed to send";
public ServerProtocol(ClientConn c) {
nick = null;
conn = c;
}
private byte[] authenticate(String mesaj) {
String id = mesaj.substring(0, 1);
if (!nicks.containsKey(id)) {
nicks.put(id, this.conn);
System.out.println(id + " joined.");
this.nick = id;
return msg_WELCOME.getBytes();
} else {
return msg_NICK_IN_USE.getBytes();
}
}
public boolean sendMsgCSP(String recipient, String msg) throws IOException {
if (nicks.containsKey(recipient)) {
int e = nicks.size();
for (int i = 0; i < e; i++) {
ClientConn c = nicks.get(recipient);
//c.sendMsgCC(nick.getBytes());
c.sendMsgCC(msg.getBytes());
System.out.println("message sent: " + msg + " to client " + recipient);
}
return true;
} else {
return false;
}
}
public byte[] process(byte[] msg) throws IOException {
//System.out.println(Arrays.toString(msg));
String mesaj = new String(msg);
if (!nicks.containsKey(nick)) {
return authenticate(mesaj);
}
System.out.println("message:" + mesaj);
if (sendMsgCSP(mesaj.substring(0, 1), mesaj.substring(1))) {
return msg_OK.getBytes();
} else {
return msg_SEND_FAILED.getBytes();
}
}
}
ClientConn
Class:
public class ClientConn implements Runnable {
private final Socket clients;
private OutputStream os;
private DataOutputStream dos;
private InputStream is;
private DataInputStream dis;
ClientConn(Socket client) {
this.clients = client;
try {
is = clients.getInputStream();
dis = new DataInputStream(is);
os = clients.getOutputStream();
dos = new DataOutputStream(os);
} catch (IOException ex) {
Logger.getLogger(ClientConn.class.getName()).log(Level.SEVERE, null, ex);
}
}
@Override
public void run() {
byte[] read, response;
ServerProtocol protocol = new ServerProtocol(this);
try {
while (true) {
read = readBytes();
//System.out.println(Arrays.toString(rd));
//System.out.println("message received: " + Arrays.toString(read));
response = protocol.process(read);
sendMsgCC(response);
}
} catch (IOException ex) {
System.out.println(ex);
}
}
public void sendMsgCC(byte[] myByteArray) throws IOException {
int start = 0;
int len = myByteArray.length;
if (len < 0) {
throw new IllegalArgumentException("Negative length not allowed");
}
if (start < 0 || start >= myByteArray.length) {
throw new IndexOutOfBoundsException("Out of bounds: " + start);
}
dos.writeInt(len);
if (len > 0) {
dos.write(myByteArray, start, len);
}
}
public byte[] readBytes() throws IOException {
int len = dis.readInt();
byte[] data = new byte[len];
if (len > 0) {
dis.readFully(data);
}
return data;
}
}
我认为问题出在 sendMsgCC 方法上,但我无法弄清楚
此处:
for (int i = 0; i < e; i++) {
ClientConn c = nicks.get(recipient);
c.sendMsgCC(msg.getBytes());
System.out.println("message sent: " + msg + " to client " + recipient);
}
您向收件人发送消息的次数与已连接客户端的次数一样多。为什么循环?
还有你的代码在没有同步或锁的情况下从多个线程读取和写入共享数据,请做好应对问题的准备。