我正在尝试制作聊天应用程序。在下面的代码中,我正在尝试实现用户注册功能,但是我遇到了ObjectInputStream.readBoolean()
的问题。基本上,客户端程序提示用户输入用户名和密码,以注册新用户或以现有用户身份登录。数据被发送到服务器,服务器根据用户列表验证数据(实际上是HashMap
)。然后,服务器将告诉客户端信息是否有效(由布尔isUserValid
表示)。我希望客户端再次提示信息是否无效,所以我有一个while (true)
并在信息有效时中断。但是,似乎客户端没有正确接收布尔值isUserValid
。当isUserValid
为真时,它可以正常工作......
以下是ChatClient的代码:
import javax.swing.*;
import java.io.*;
import java.net.*;
import java.util.*;
public class ChatClient implements Runnable {
public static final int PORT = 1234;
private Socket client;
private ObjectInputStream input;
private ObjectOutputStream output;
...
@Override
public void run() {
...
boolean isRegistering = JOptionPane.showOptionDialog(null, "Log in or register?", "", JOptionPane.YES_NO_OPTION, JOptionPane.PLAIN_MESSAGE, null, new String[]{"Log in", "Register"}, null) == 1;
try {
// Let the server know that the client wants to register.
output.writeBoolean(isRegistering);
} catch (IOException e) {
e.printStackTrace();
System.exit(1);
}
// This will repeatedly prompt the user if the entered info is not valid.
// Invalid user info can be duplicate usernames while registering, or if the password is invalid.
while (true) {
try {
// I need to generalize this to Object[] because one element is a String while the other is a char[].
// I know this is not good practice, but how else can I do it?
Object[] userInfo;
if (isRegistering) {
// The difference between registration dialog and login dialog is only word choice.
userInfo = Dialogs.registrationDialog();
} else {
userInfo = Dialogs.loginDialog();
}
output.writeObject(userInfo);
// Break out of the cycle of prompts if the user is valid.
// For some reason this works when the user is valid, but fails to read a boolean if the server writes false.
// For example, if I first register username "fdsa" password "123", then the registration is successful,
// but then if I register "fdsa" "456", the registration is unsuccessful, and the server writes false.
// The client should then loop again and show another registration dialog, but apparently input.readBoolean()
// does not receive the false boolean.
if (input.readBoolean()) break;
} catch (IOException e) {
e.printStackTrace();
System.exit(1);
}
}
}
public static void main(String[] args) {
new Thread(new ChatClient()).run();
}
}
服务器代码:
import java.io.*;
import java.net.*;
import java.util.*;
public class IncomingClientHandler implements Runnable {
private List<Message> messageList;
private Socket client;
private ObjectOutputStream output;
private ObjectInputStream input;
private Map<String, char[]> usersList;
public IncomingClientHandler(List<Message> l, Map<String, char[]> u, Socket c) {
usersList = u;
messageList = l;
client = c;
try {
output = new ObjectOutputStream(c.getOutputStream());
input = new ObjectInputStream(c.getInputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void run() {
System.out.println("New client accepted at " + client.getInetAddress());
try {
boolean isRegistering = input.readBoolean();
Object[] userInfo;
while (true) {
try {
userInfo = (Object[]) input.readObject();
boolean isUserValid;
if (isRegistering) {
// The user will not be valid if the same username is already registered.
isUserValid = !usersList.containsKey(userInfo[0]);
} else {
try {
// The user will not be valid if the password doesn't match.
isUserValid = Arrays.equals(usersList.get(userInfo[0]), (char[]) userInfo[1]);
} catch (NullPointerException e) {
isUserValid = false;
}
}
System.out.println("The entered user info is " + (isUserValid ? "valid." : "invalid."));
output.writeBoolean(isUserValid);
if (isUserValid) break;
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
if (isRegistering) {
usersList.put((String) userInfo[0], (char[]) userInfo[1]);
}
...
} catch (IOException e) {
e.printStackTrace();
}
}
}
我遗漏了很多我认为与我的问题无关的代码,但是如果你想要完整的项目,它也是on Github.