繁体   English   中英

java 服务器 Socket 向错误的客户端发送数据

[英]java server Socket sending data to wrong Client

正如标题所说,如果您尝试执行此程序,启动 2 个客户端,并尝试向第一个客户端发送消息“登录”或“注册”,服务器将接收输入但将响应重定向到第二个套接字(最后一个一个连接的人)。 当服务器尝试向客户端发送响应时,您可以通过查看服务器控制台上打印的端口号来看到这一点

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();
        }
    }
}

属性中的“静态”关键字意味着属性的值分布在 class 的所有对象中,因为该值不存储在 object 中,而简单地说,存储在 ZA2F2ED4F8EBC2CBB4C21A29DC40AB61Z 中

如果您不确切知道“静态”代表什么,可以查看以下页面: java 中的 Static 关键字

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("StackOverflow");

    test1.printHello(); // "StackOverflow"
    test2.printHello(); // "StackOverflow" <- same as in "test1"
  }
}

问题在于,在您的“ServerThread”class 中,所有属性都是 static,因此它们在不同对象之间共享。 因此,如果您覆盖客户端 2 中的变量“socket”,您将覆盖客户端 1 的“socket”。

因此,从 Client 和 ServerThread class 的属性和方法中删除“静态”关键字,这应该可以解决问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM