所以,我一直在研究这个 TCP Bank 应用程序。成功登录后,麻烦就开始了。一旦我登录,应用程序就会给我这些选项(1-5),但是当我尝试更新密码(选项 5)时,一切都冻结了。就像应用程序卡住了并且完全没有响应。
我检查了代码,似乎在我尝试存钱时发生了冻结。 Client 类中的第 140 行出现了这个奇怪的“EOFException”,提到了 ObjectInputStream 的问题。
我很确定冻结与提交过程中客户端和服务器的通信方式有关。我已经研究了代码的两面,但我不太清楚是什么导致了这种冻结。除此之外,我尝试了一些错误处理和日志记录,但我仍然陷入困境。
任何有关如何解决登录后冻结问题的帮助或想法都将是一个巨大的帮助。非常感谢!
因此,登录我的 TCP Bank 应用程序后,我想更新我的密码(即选项 1)。但整个过程并没有顺利地更改密码,而是冻结了。我希望提交能够无缝运行,但应用程序却变得没有响应。
我深入研究了代码,检查了密码更新期间客户端和服务器之间的通信,甚至添加了一些错误处理和日志记录以跟踪发生的情况。然而,尽管如此,每次我点击 1 时仍然会发生冻结
这很令人费解,我有点被困在这里。任何解决登录后冻结问题的见解或指导将不胜感激!非常感谢您提供的任何帮助。
这是我尝试过的
客户
package TCP;
import java.io.*;
import java.net.*;
import java.util.Scanner;
public class Client {
private static final String SERVER_IP = "127.0.0.1";
private static final int SERVER_PORT = 8888;
public static void main(String[] args) {
try (Socket socket = new Socket(SERVER_IP, SERVER_PORT);
ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
Scanner scanner = new Scanner(System.in)) {
boolean loggedIn = false;
String userId = ""; // Store logged-in user ID
while (true) {
if (!loggedIn) {
System.out.println("Welcome! Choose an option:");
System.out.println("1. Register an account");
System.out.println("2. Login");
int choice = scanner.nextInt();
scanner.nextLine(); // Consume newline
if (choice == 1) {
// Registration
System.out.print("Enter PPSN: ");
String id = scanner.nextLine();
System.out.print("Enter Name: ");
String name = scanner.nextLine();
System.out.print("Enter Email: ");
String email = scanner.nextLine();
System.out.print("Enter Password: ");
String password = scanner.nextLine();
System.out.print("Enter Address: ");
String address = scanner.nextLine();
System.out.print("Enter Balance: ");
String balance = scanner.nextLine();
// Send registration data to server
out.writeObject("REGISTER");
out.writeObject(id);
out.writeObject(name);
out.writeObject(email);
out.writeObject(password);
out.writeObject(address);
out.writeObject(balance);
String response = (String) in.readObject();
System.out.println("Server: " + response);
} else if (choice == 2) {
// Login
System.out.print("Enter PPSN: ");
String id = scanner.nextLine();
System.out.print("Enter Password: ");
String password = scanner.nextLine();
// Send login data to server
out.writeObject("LOGIN");
out.writeObject(id);
out.writeObject(password);
String response = (String) in.readObject();
if (response.equals("LOGIN_SUCCESS")) {
loggedIn = true;
System.out.println("Login successful!");
userId = id;
} else {
System.out.println("Login failed. Try again.");
}
}
} else {
System.out.println("Logged in! Options:");
System.out.println("1. Lodge money to the user account.");
System.out.println("2. Retrieve all registered users listing.");
System.out.println("3. Transfer money to another account.");
System.out.println("4. View all transactions on your bank account.");
System.out.println("5. Update your password.");
System.out.println("0. Log out.");
int choice = scanner.nextInt();
scanner.nextLine(); // Consume newline
switch (choice) {
// Inside the client while loop, under case 1 (Lodge money)
case 1:
// Lodge money
out.writeObject("GET_BALANCE");
out.writeObject(userId); // Send the user's ID to the server
double currentBalance = in.readDouble();
System.out.println("Your current balance is: " + currentBalance);
System.out.print("Enter the amount to lodge: ");
double amountToLodge = scanner.nextDouble();
scanner.nextLine(); // Consume newline
// Send the request to lodge money to the server
out.writeObject("LODGE_MONEY");
out.writeDouble(amountToLodge);
// Read the updated balance from the server
double updatedBalance = in.readDouble();
System.out.println("Updated balance: " + updatedBalance);
break;
case 2:
// Retrieve all registered users listing
// Implement functionality to retrieve and display all registered users
// Example:
out.writeObject("RETRIEVE_USERS");
// Receive and display the user listing from the server
break;
case 3:
// Transfer money to another account
// Implement functionality to transfer money to another account
// Example:
// Collect recipient details (email, PPS number, etc.)
// Send details to the server for the transfer process
break;
case 4:
// View all transactions
// Implement functionality to view all transactions on the bank account
// Example:
out.writeObject("VIEW_TRANSACTIONS");
// Receive and display the transactions from the server
break;
case 5:
// Update password
// Implement functionality to update the user's password
// Example:
System.out.print("Enter new password: ");
String newPassword = scanner.nextLine();
out.writeObject("UPDATE_PASSWORD");
out.writeObject(newPassword);
String updateResponse = (String) in.readObject();
System.out.println("Server: " + updateResponse);
break;
case 0: // Option to exit or log out
System.out.println("Logged out...");
out.writeObject("LOGOUT"); // Inform server about logout
loggedIn = false; // Reset logged-in state
break;
default:
System.out.println("Invalid choice. Please choose a valid option.");
break;
}
}
}
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
package TCP;
import java.io.*;
import java.net.*;
import java.util.HashMap;
import java.util.HashSet;
public class Server {
private static final int SERVER_PORT = 8888;
private static HashMap<String, String[]> accounts = new HashMap<>();
private static HashSet<String> emailSet = new HashSet<>();
private static HashSet<String> idSet = new HashSet<>();
private static HashMap<Socket, String> loggedInUsers = new HashMap<>();
private static final String DATABASE_FILE = "TCP/database.txt";
public static void main(String[] args) {
loadAccounts();
try (ServerSocket serverSocket = new ServerSocket(SERVER_PORT)) {
System.out.println("Server started. Listening on port " + SERVER_PORT);
while (true) {
Socket clientSocket = serverSocket.accept();
System.out.println("Client connected: " + clientSocket);
new Thread(() -> handleClient(clientSocket)).start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
private static void handleClient(Socket clientSocket) {
ObjectOutputStream out = null;
ObjectInputStream in = null;
try {
out = new ObjectOutputStream(clientSocket.getOutputStream());
in = new ObjectInputStream(clientSocket.getInputStream());
while (true) {
String option = (String) in.readObject();
if (option.equals("REGISTER")) {
String id = (String) in.readObject();
String name = (String) in.readObject();
String email = (String) in.readObject();
String password = (String) in.readObject();
String address = (String) in.readObject();
String balance = (String) in.readObject();
if (accounts.containsKey(id)) {
out.writeObject("DUPLICATE_ID");
} else if (checkDuplicateEmail(email)) {
out.writeObject("DUPLICATE_EMAIL");
} else {
String[] userDetails = {name, email, password, address, balance};
accounts.put(id, userDetails);
out.writeObject("Registration successful!");
saveAccounts();
}
} else if (option.equals("LOGIN")) {
String id = (String) in.readObject();
String password = (String) in.readObject();
if (accounts.containsKey(id) && accounts.get(id)[2].equals(password)) {
loggedInUsers.put(clientSocket, id);
out.writeObject("LOGIN_SUCCESS");
} else {
out.writeObject("LOGIN_FAILURE");
}
} else if (option.equals("GET_BALANCE")) {
String userId = (String) in.readObject();
double balance = 0.0;
if (accounts.containsKey(userId)) {
String[] userDetails = accounts.get(userId);
balance = Double.parseDouble(userDetails[userDetails.length - 1]);
}
out.writeDouble(balance);
} else if (option.equals("LODGE_MONEY")) {
try {
String userId = loggedInUsers.get(clientSocket);
double amountToLodge = in.readDouble();
if (userId != null && accounts.containsKey(userId)) {
String[] userDetails = accounts.get(userId);
double currentBalance = Double.parseDouble(userDetails[userDetails.length - 1]);
double updatedBalance = currentBalance + amountToLodge;
userDetails[userDetails.length - 1] = String.valueOf(updatedBalance);
accounts.put(userId, userDetails);
out.writeDouble(updatedBalance);
} else {
out.writeDouble(-1.0);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
if (out != null) {
out.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (in != null) {
in.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
clientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private static boolean checkDuplicateEmail(String email) {
for (String[] userDetails : accounts.values()) {
if (userDetails[1].equals(email)) {
return true;
}
}
return false;
}
private static void loadAccounts() {
try (BufferedReader br = new BufferedReader(new FileReader(DATABASE_FILE))) {
String line;
while ((line = br.readLine()) != null) {
String[] userInfo = line.split(",");
String userId = userInfo[0];
String[] userDetails = new String[userInfo.length - 1];
System.arraycopy(userInfo, 1, userDetails, 0, userDetails.length);
accounts.put(userId, userDetails);
}
} catch (IOException e) {
e.printStackTrace();
}
}
private static void saveAccounts() {
try (BufferedWriter bw = new BufferedWriter(new FileWriter(DATABASE_FILE))) {
for (String userId : accounts.keySet()) {
String[] userDetails = accounts.get(userId);
StringBuilder line = new StringBuilder(userId);
for (String detail : userDetails) {
line.append(",").append(detail);
}
bw.write(line.toString());
bw.newLine();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
服务器端似乎没有处理选项5。比如:
else if (option.equals("UPDATE_PASSWORD")) {
...
}
...失踪了。
所以当客户选择选项5时,步骤是:
"UPDATE_PASSWORD"
到服务器。option
。option
没有处理此类字符串,因此根据代码,服务器进入下一个循环等待下一个option
。option
变量中。密码不太可能是任何预定义的字符串选项,因此服务器会忽略它并进入下一个循环并等待下一个option
。String updateResponse = (String) in.readObject();
所以现在双方都在等待对方输入(死锁)。
为防止出现这种情况,请确保以相同的方式处理两侧的选项。
此外,在提供的代码中,客户端有状态(
loggedIn
变量),而不是在服务器端。那么服务器如何知道每个客户端处于哪个状态(以便正确处理每个状态)?需要注意的是,连接的状态至少应该保存在服务器端。