java服务器Socket发送数据到错误的客户端
java server Socket sending data to wrong Client
如标题所述,如果您尝试执行此程序,启动 2 个客户端,并尝试向第一个客户端发送消息 'login' 或 'register',服务器将接收输入但重定向对第二个套接字的响应(最后一个连接的套接字)。当服务器尝试向客户端发送响应时,您可以通过查看打印在服务器控制台上的端口号来看到这一点
public class Server {
private ServerSocket server;
public Server() {
try {
server = new ServerSocket(10000);
System.out.println("[INFO] server running");
} catch (IOException e) {
System.out.println(e);
}
}
public static void main(String[] args) {
Server server = new Server();
server.run();
}
public void run() {
try {
while (true) {
Socket clientRequest = server.accept();
new Thread(new ServerThread(clientRequest)).start();
}
} catch (IOException e) {
System.out.println(e);
}
}
}
class ServerThread implements Runnable {
private static Socket socket;
private static Connection dbConnection = null;
private static OutputStream outputStream;
private static ObjectOutputStream objectOutputStream;
private static InputStream inputStream;
private static ObjectInputStream objectInputStream;
private static List<String> messages = new ArrayList<String>();
private static MessageDigest messageDigest;
private static String username = "";
private static boolean invalidUsername;
public ServerThread(Socket richiestaClient) {
try {
socket = richiestaClient;
System.out.println("[INFO] " + socket + " connected ");
outputStream = socket.getOutputStream();
objectOutputStream = new ObjectOutputStream(outputStream);
inputStream = socket.getInputStream();
objectInputStream = new ObjectInputStream(inputStream);
} catch (IOException e) {
System.out.println("[ERROR] errore di i/o");
}
}
public void run() {
// conversazione lato server
try {
boolean active = true;
while (active) {
System.out.println("[THREAD] " + Thread.currentThread().getName());
System.out.println("[DEBUG] current socket: " + socket);
String msg = (String) objectInputStream.readObject();
System.out.println("[CLIENT] " + msg);
// -- SELECT CASE FOR USER LOGIN/REGISTER --
switch (msg) {
case "login":
login(dbConnection);
break;
case "register":
register(dbConnection);
break;
default:
break;
}
}
} catch (IOException | ClassNotFoundException e) {
System.out.println("[ERROR] errore nello switch azioni ioexception " + e);
}
}
private static void register(Connection dbConnection) {
System.out.println("[THREAD] " + Thread.currentThread().getName());
System.out.println("[DEBUG] client selected register " + socket);
messages.add("username");
messages.add("You selected register");
invalidUsername = true;
while (invalidUsername) {
messages.add("input the username you want");
send(messages);
// getting username (assuming not taken for testing purpose)
boolean usernameExists = false;
if (usernameExists) {
System.out.println("[DEBUG] username exists, not available for the registration");
messages.add("username");
messages.add("sorry, username is taken :(");
} else {
System.out.println("[DEBUG] username does not exists, available for the registration");
messages.add("password");
messages.add("username is not taken yet :)");
invalidUsername = false;
}
}
System.out.println("[DEBUG] username not taken, sending result to " + socket);
}
private static void login(Connection dbConnection) {
System.out.println("[THREAD] " + Thread.currentThread().getName());
System.out.println("[DEBUG] client selected login " + socket);
messages.add("username");
messages.add("You selected login");
messages.add("Input your username");
send(messages);
try {
username = (String) objectInputStream.readObject();
System.out.println("[INFO] received " + username + " from " + socket);
} catch (ClassNotFoundException | IOException e) {
System.out.println("[DEBUG] error while waiting for client login username");
}
}
// sending messages, flushing stream and clearing messages list
private static void send(List<String> messagesToSend) {
System.out.println("[THREAD] " + Thread.currentThread().getName());
System.out.println("[DEBUG] Sending data to " + socket);
try {
objectOutputStream.writeObject(messagesToSend);
objectOutputStream.flush();
messages.clear();
} catch (IOException e) {
System.out.println("[ERROR] error occurred while sending message");
}
}
}
public class Client {
private static Socket socket;
private static OutputStream outputStream;
private static ObjectOutputStream objectOutputStream;
private static InputStream inputStream;
private static ObjectInputStream objectInputStream;
public Client() {
try {
socket = new Socket("127.0.0.1", 10000);
outputStream = socket.getOutputStream();
objectOutputStream = new ObjectOutputStream(outputStream);
inputStream = socket.getInputStream();
objectInputStream = new ObjectInputStream(inputStream);
} catch (IOException e) {
System.out.println(e);
}
}
public static void main(String[] args) {
Client client = new Client();
client.conversazione();
}
public void conversazione() {
// conversazione lato client
Scanner scan = new Scanner(System.in);
String command = "default";
String message = "";
String username = "";
List<String> messages = new ArrayList<String>();
System.out.println("what do you want to do? (login/register)");
while (true) {
try {
switch (command) {
case "default":
System.out.println("[DEBUG] switch option: default");
message = scan.nextLine();
send(message);
break;
case "username":
System.out.println("[DEBUG] switch option: username");
username = scan.nextLine();
send(username);
break;
case "password":
System.out.println("[DEBUG] switch option: password");
// not implemented yet
break;
default:
break;
}
// getting messages from the server, using the first one as "header" to know what to do
System.out.println("[DEBUG] waiting for message " + socket);
messages = (List<String>) objectInputStream.readObject();
System.out.println("Received [" + (messages.size() - 1) + "] messages from: " + socket);
command = messages.get(0);
messages.remove(0);
for (String msg : messages) {
System.out.println(msg);
}
messages.clear();
} catch (Exception e) {
e.printStackTrace();
}
}
}
// send message to the server and reset the stream
public static void send(String message) {
try {
System.out.println("[DEBUG] sending data as " + socket);
objectOutputStream.writeObject(message);
objectOutputStream.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
attributes中的“static”关键字表示属性的值分布在class的所有对象中,因为该值不存储在对象中,而是简单地说,存储在class.
如果您不知道“静态”到底是什么意思,请查看以下页面:Static keyword in java
public class Test {
// static attribute
private static String hello = "world";
public void setHello(String newValue) {
Test.hello = newValue;
}
public void printHello() {
System.out.println(Test.hello);
}
}
public class Main {
public static void main(String[] args) {
Test test1 = new Test();
Test test2 = new Test();
test1.printHello(); // -> "world"
test2.printHello(); // -> "world"
// Note that we seem to change only the value of "hello" in object "test1".
// However, since the attribute "test1" is static, the value "changes" for all objects of the class.
test1.setHello("Whosebug");
test1.printHello(); // "Whosebug"
test2.printHello(); // "Whosebug" <- same as in "test1"
}
}
问题是在您的“ServerThread”中 class 所有属性都是静态的,因此它们在不同的对象之间共享。因此,如果您覆盖客户端 2 中的变量“socket”,您将覆盖客户端 1 的“socket”。
因此从 Client 和 ServerThread 的属性和方法中删除“static”关键字class,这应该可以解决问题。
如标题所述,如果您尝试执行此程序,启动 2 个客户端,并尝试向第一个客户端发送消息 'login' 或 'register',服务器将接收输入但重定向对第二个套接字的响应(最后一个连接的套接字)。当服务器尝试向客户端发送响应时,您可以通过查看打印在服务器控制台上的端口号来看到这一点
public class Server {
private ServerSocket server;
public Server() {
try {
server = new ServerSocket(10000);
System.out.println("[INFO] server running");
} catch (IOException e) {
System.out.println(e);
}
}
public static void main(String[] args) {
Server server = new Server();
server.run();
}
public void run() {
try {
while (true) {
Socket clientRequest = server.accept();
new Thread(new ServerThread(clientRequest)).start();
}
} catch (IOException e) {
System.out.println(e);
}
}
}
class ServerThread implements Runnable {
private static Socket socket;
private static Connection dbConnection = null;
private static OutputStream outputStream;
private static ObjectOutputStream objectOutputStream;
private static InputStream inputStream;
private static ObjectInputStream objectInputStream;
private static List<String> messages = new ArrayList<String>();
private static MessageDigest messageDigest;
private static String username = "";
private static boolean invalidUsername;
public ServerThread(Socket richiestaClient) {
try {
socket = richiestaClient;
System.out.println("[INFO] " + socket + " connected ");
outputStream = socket.getOutputStream();
objectOutputStream = new ObjectOutputStream(outputStream);
inputStream = socket.getInputStream();
objectInputStream = new ObjectInputStream(inputStream);
} catch (IOException e) {
System.out.println("[ERROR] errore di i/o");
}
}
public void run() {
// conversazione lato server
try {
boolean active = true;
while (active) {
System.out.println("[THREAD] " + Thread.currentThread().getName());
System.out.println("[DEBUG] current socket: " + socket);
String msg = (String) objectInputStream.readObject();
System.out.println("[CLIENT] " + msg);
// -- SELECT CASE FOR USER LOGIN/REGISTER --
switch (msg) {
case "login":
login(dbConnection);
break;
case "register":
register(dbConnection);
break;
default:
break;
}
}
} catch (IOException | ClassNotFoundException e) {
System.out.println("[ERROR] errore nello switch azioni ioexception " + e);
}
}
private static void register(Connection dbConnection) {
System.out.println("[THREAD] " + Thread.currentThread().getName());
System.out.println("[DEBUG] client selected register " + socket);
messages.add("username");
messages.add("You selected register");
invalidUsername = true;
while (invalidUsername) {
messages.add("input the username you want");
send(messages);
// getting username (assuming not taken for testing purpose)
boolean usernameExists = false;
if (usernameExists) {
System.out.println("[DEBUG] username exists, not available for the registration");
messages.add("username");
messages.add("sorry, username is taken :(");
} else {
System.out.println("[DEBUG] username does not exists, available for the registration");
messages.add("password");
messages.add("username is not taken yet :)");
invalidUsername = false;
}
}
System.out.println("[DEBUG] username not taken, sending result to " + socket);
}
private static void login(Connection dbConnection) {
System.out.println("[THREAD] " + Thread.currentThread().getName());
System.out.println("[DEBUG] client selected login " + socket);
messages.add("username");
messages.add("You selected login");
messages.add("Input your username");
send(messages);
try {
username = (String) objectInputStream.readObject();
System.out.println("[INFO] received " + username + " from " + socket);
} catch (ClassNotFoundException | IOException e) {
System.out.println("[DEBUG] error while waiting for client login username");
}
}
// sending messages, flushing stream and clearing messages list
private static void send(List<String> messagesToSend) {
System.out.println("[THREAD] " + Thread.currentThread().getName());
System.out.println("[DEBUG] Sending data to " + socket);
try {
objectOutputStream.writeObject(messagesToSend);
objectOutputStream.flush();
messages.clear();
} catch (IOException e) {
System.out.println("[ERROR] error occurred while sending message");
}
}
}
public class Client {
private static Socket socket;
private static OutputStream outputStream;
private static ObjectOutputStream objectOutputStream;
private static InputStream inputStream;
private static ObjectInputStream objectInputStream;
public Client() {
try {
socket = new Socket("127.0.0.1", 10000);
outputStream = socket.getOutputStream();
objectOutputStream = new ObjectOutputStream(outputStream);
inputStream = socket.getInputStream();
objectInputStream = new ObjectInputStream(inputStream);
} catch (IOException e) {
System.out.println(e);
}
}
public static void main(String[] args) {
Client client = new Client();
client.conversazione();
}
public void conversazione() {
// conversazione lato client
Scanner scan = new Scanner(System.in);
String command = "default";
String message = "";
String username = "";
List<String> messages = new ArrayList<String>();
System.out.println("what do you want to do? (login/register)");
while (true) {
try {
switch (command) {
case "default":
System.out.println("[DEBUG] switch option: default");
message = scan.nextLine();
send(message);
break;
case "username":
System.out.println("[DEBUG] switch option: username");
username = scan.nextLine();
send(username);
break;
case "password":
System.out.println("[DEBUG] switch option: password");
// not implemented yet
break;
default:
break;
}
// getting messages from the server, using the first one as "header" to know what to do
System.out.println("[DEBUG] waiting for message " + socket);
messages = (List<String>) objectInputStream.readObject();
System.out.println("Received [" + (messages.size() - 1) + "] messages from: " + socket);
command = messages.get(0);
messages.remove(0);
for (String msg : messages) {
System.out.println(msg);
}
messages.clear();
} catch (Exception e) {
e.printStackTrace();
}
}
}
// send message to the server and reset the stream
public static void send(String message) {
try {
System.out.println("[DEBUG] sending data as " + socket);
objectOutputStream.writeObject(message);
objectOutputStream.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
attributes中的“static”关键字表示属性的值分布在class的所有对象中,因为该值不存储在对象中,而是简单地说,存储在class.
如果您不知道“静态”到底是什么意思,请查看以下页面:Static keyword in java
public class Test {
// static attribute
private static String hello = "world";
public void setHello(String newValue) {
Test.hello = newValue;
}
public void printHello() {
System.out.println(Test.hello);
}
}
public class Main {
public static void main(String[] args) {
Test test1 = new Test();
Test test2 = new Test();
test1.printHello(); // -> "world"
test2.printHello(); // -> "world"
// Note that we seem to change only the value of "hello" in object "test1".
// However, since the attribute "test1" is static, the value "changes" for all objects of the class.
test1.setHello("Whosebug");
test1.printHello(); // "Whosebug"
test2.printHello(); // "Whosebug" <- same as in "test1"
}
}
问题是在您的“ServerThread”中 class 所有属性都是静态的,因此它们在不同的对象之间共享。因此,如果您覆盖客户端 2 中的变量“socket”,您将覆盖客户端 1 的“socket”。
因此从 Client 和 ServerThread 的属性和方法中删除“static”关键字class,这应该可以解决问题。