[英]Constant crashes with my Java Multi-threaded TCP Server
所以我知道這是一個有很多代碼的大問題,但我不知道問題是什么,因為登錄系統似乎工作正常,但是當我嘗試添加錯誤或查看錯誤時,它會使服務器崩潰,我必須重啟服務器:
import java.io.*;
import java.net.*;
import java.util.*;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
public class Server
{
// User database
private static Map<String, String> userDatabase = new HashMap<>();
// Bug report database
private static Map<Integer, String> bugDatabase = new HashMap<>();
private static int nextBugId = 1;
public static void main(String[] args) throws Exception
{
// Create a server socket
ServerSocket welcomeSocket = new ServerSocket(6789);
// Create a thread pool with a fixed number of threads
Executor executor = Executors.newFixedThreadPool(10);
while (true)
{
// Accept a new client connection
Socket connectionSocket = welcomeSocket.accept();
// Create a new thread for the client and submit it to the thread pool
Runnable clientHandler = new ClientHandler(connectionSocket);
executor.execute(clientHandler);
}
}
// Inner class for handling client requests
private static class ClientHandler implements Runnable
{
private Socket connectionSocket;
private BufferedReader inFromClient;
private DataOutputStream outToClient;
public ClientHandler(Socket socket) throws Exception
{
connectionSocket = socket;
inFromClient = new BufferedReader(new InputStreamReader(connectionSocket.getInputStream()));
outToClient = new DataOutputStream(connectionSocket.getOutputStream());
}
public void run()
{
try
{
// Read request from the client
String request = inFromClient.readLine();
if (request.startsWith("REGISTER"))
{
// Parse the request
String[] tokens = request.split(" ");
String username = tokens[1];
String password = tokens[2];
// Check if the username is already taken
if (userDatabase.containsKey(username))
{
outToClient.writeBytes("ERROR: Username already taken\n");
}
else
{
// Add the user to the database
userDatabase.put(username, password);
outToClient.writeBytes("OK\n");
}
}
else if (request.startsWith("LOGIN"))
{
// Parse the request
String[] tokens = request.split(" ");
String username = tokens[1];
String password = tokens[2];
// Check if the username and password are correct
if (!userDatabase.containsKey(username))
{
outToClient.writeBytes("ERROR: Invalid username\n");
}
else if (!userDatabase.get(username).equals(password))
{
outToClient.writeBytes("ERROR: Invalid password\n");
}
else
{
outToClient.writeBytes("OK\n");
}
}
else if (request.startsWith("ADD"))
{
// Parse the request
String[] tokens = request.split(" ");
String appName = tokens[1];
String dateTimeStamp = tokens[2];
String platform = tokens[3];
String problemDesc = tokens[4];
String status = tokens[5];
// Add the bug report to the database
int bugId = nextBugId++;
bugDatabase.put(bugId, appName + " " + dateTimeStamp + " " + platform + " " + problemDesc + " " + status);
outToClient.writeBytes("OK " + bugId + "\n");
}
else if (request.startsWith("UPDATE"))
{
// Parse the request
String[] tokens = request.split(" ");
int bugId = Integer.parseInt(tokens[1]);
String newStatus = tokens[2];
// Update the bug report in the database
if (updateBugStatus(bugId, newStatus))
{
outToClient.writeBytes("OK\n");
}
else
{
outToClient.writeBytes("ERROR: Invalid bug ID\n");
}
}
else if (request.startsWith("VIEW"))
{
// Send all the bug reports to the client
for (int bugId : bugDatabase.keySet())
{
outToClient.writeBytes(bugId + " " + bugDatabase.get(bugId) + "\n");
}
outToClient.writeBytes("OK\n");
}
else if (request.startsWith("QUIT"))
{
// Close the connection to the client
connectionSocket.close();
}
else
{
// Print an error message if the request is invalid
outToClient.writeBytes("ERROR: Invalid request\n");
}
}
catch (IOException ex)
{
System.out.println("Error: An I/O exception occurred");
}
} // Helper method to update the status of a bug report in the database
private boolean updateBugStatus(int bugId, String newStatus)
{
if (!bugDatabase.containsKey(bugId))
{
return false;
}
String[] bugDetails = bugDatabase.get(bugId).split(" ");
bugDetails[4] = newStatus;
bugDatabase.put(bugId, String.join(" ", bugDetails));
return true;
}
}
}
import java.io.*;
import java.net.*;
import java.util.*;
public class Client
{
public static void main(String[] args)
{
try
{
// Create a socket to connect to the server
Socket clientSocket = new Socket("localhost", 6789);
// Create input and output streams to read from and write to the server
BufferedReader inFromServer = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
DataOutputStream outToServer = new DataOutputStream(clientSocket.getOutputStream());
// Read input from the user
BufferedReader userInput = new BufferedReader(new InputStreamReader(System.in));
while (true)
{
// Print a prompt to the user
System.out.print("Enter a command (REGISTER, LOGIN, or QUIT): ");
// Read the command from the user
String command = userInput.readLine();
if (command.equals("REGISTER"))
{
// Read the username and password from the user
System.out.print("Enter a username: ");
String username = userInput.readLine();
System.out.print("Enter a password: ");
String password = userInput.readLine();
// Send the REGISTER command and the username and password to the server
outToServer.writeBytes("REGISTER " + username + " " + password + "\n");
// Read the response from the server
String response = inFromServer.readLine();
System.out.println(response);
}
else if (command.equals("LOGIN"))
{
// Read the username and password from the user
System.out.print("Enter a username: ");
String username = userInput.readLine();
System.out.print("Enter a password: ");
String password = userInput.readLine();
// Send the LOGIN command and the username and password to the server
outToServer.writeBytes("LOGIN " + username + " " + password + "\n");
// Read the response from the server
String response = inFromServer.readLine();
System.out.println(response);
// If the login was successful, allow the user to add a bug report
if (response.equals("OK"))
{
while (true)
{
// Print a prompt to the user
System.out.print("Enter a command (ADD, UPDATE,VIEW ,or QUIT): ");
// Read the command from the user
String command2 = userInput.readLine();
if (command2.equals("ADD"))
{
// Read the bug report details from the user
System.out.print("Enter the application name: ");
String appName = userInput.readLine();
System.out.print("Enter the date and time stamp: ");
String dateTime = userInput.readLine();
System.out.print("Enter the platform: ");
String platform = userInput.readLine();
System.out.print("Enter the problem description: ");
String problem = userInput.readLine();
System.out.print("Enter the status (Open, Assigned, or Closed): ");
String status = userInput.readLine();
// Send the ADD command and the bug report details to the server
outToServer.writeBytes("ADD " + appName + " " + dateTime + " " + platform + " " + problem + " " + status + "\n");
// Read the response from the server
String response2 = inFromServer.readLine();
System.out.println(response2);
}
else if (command2.equals("UPDATE"))
{
// Read the bug report ID and new status from the user
System.out.print("Enter the bug report ID: ");
int bugId = Integer.parseInt(userInput.readLine());
System.out.print("Enter the new status (Open, Assigned, or Closed): ");
String newStatus = userInput.readLine();
// Send the UPDATE command and the bug report ID and new status to the server
outToServer.writeBytes("UPDATE " + bugId + " " + newStatus + "\n");
// Read the response from the server
String updateResponse = inFromServer.readLine();
System.out.println(updateResponse);
}
else if (command2.equals("VIEW"))
{
// Send the VIEW command to the server
outToServer.writeBytes("VIEW\n");
// Read the response from the server
String response2 = inFromServer.readLine();
// Print the bug reports received from the server
while (!response2.equals("OK"))
{
System.out.println(response2);
response2 = inFromServer.readLine();
}
}
else if (command2.equals("QUIT"))
{
// Send the QUIT command to the server
outToServer.writeBytes("QUIT\n");
// Close the connection to the server
clientSocket.close();
// Terminate the loop
break;
}
else
{
// Print an error message if the command is invalid
System.out.println("Invalid command");
}
}
}
}
else if (command.equals("QUIT"))
{
// Send the QUIT command to the server
outToServer.writeBytes("QUIT\n");
// Close the connection to the server
clientSocket.close();
// Terminate the loop
break;
}
else
{
// Print an error message if the command is invalid
System.out.println("Invalid command");
}
}
}
catch (UnknownHostException ex)
{
System.out.println("Error: Unable to connect to the server");
}
catch (IOException ex)
{
System.out.println("Error: An I/O exception occurred");
}
catch (NumberFormatException ex)
{
System.out.println("Error: Invalid input");
}
}
}
我只想簡單地做到這一點,以便將錯誤注冊到服務器,然后可以在客戶端顯示而不會出現任何崩潰
拋出的異常:
Exception in thread "main" java.net.SocketException: An established connection was aborted by the software in your host machine
at java.base/sun.nio.ch.NioSocketImpl.implWrite(NioSocketImpl.java:420)
at java.base/sun.nio.ch.NioSocketImpl.write(NioSocketImpl.java:440)
at java.base/sun.nio.ch.NioSocketImpl$2.write(NioSocketImpl.java:826)
at java.base/java.net.Socket$SocketOutputStream.write(Socket.java:1035)
at java.base/java.net.Socket$SocketOutputStream.write(Socket.java:1031)
at java.base/java.io.DataOutputStream.writeBytes(DataOutputStream.java:282)
at Client.main(Client.java:83)
“已建立的連接被主機中的軟件中止”異常是客戶端注意到服務器進程已崩潰並關閉連接,同時寫入 Client.java:83。
從出現缺陷的服務器進程中查看崩潰信息會更有幫助。 但是即使沒有那個,我注意到您正在使用以空格分隔的協議,即:
客戶:
// Send the ADD command and the bug report details to the server
outToServer.writeBytes("ADD " + appName + " " + dateTime + " " + platform + " " + problem + " " + status + "\n");
服務器:
else if (request.startsWith("ADD"))
{
// Parse the request
String[] tokens = request.split(" ");
String appName = tokens[1];
String dateTimeStamp = tokens[2];
String platform = tokens[3];
String problemDesc = tokens[4];
String status = tokens[5];
// Add the bug report to the database
int bugId = nextBugId++;
bugDatabase.put(bugId, appName + " " + dateTimeStamp + " " + platform + " " + problemDesc + " " + status);
outToClient.writeBytes("OK " + bugId + "\n");
但是,如果這些字段都不包含嵌入的空格字符,這可能只會按您的預期運行,如果包含,則它會拋出服務器對這些字段的解析。 並且您的新記錄中的尾隨單詞將被截斷。 服務器代碼中的其他地方也出現了同樣的假設/問題。
我不確定為什么這會導致實際崩潰,但您可能應該選擇一個更好的分隔符,它不太可能出現在字段值中。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.