简体   繁体   English

我的 Java 多线程 TCP 服务器经常崩溃

[英]Constant crashes with my Java Multi-threaded TCP Server

So i know this is a big one with a lot of code but i dont know what the issue is as the login system seems to work fine but when i try to add a bug or view a bug it will crash the server and i have to restart 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");
        }
    }
}




I just want to simply make it so that the bugs are registered to the server and then can be show on the client side without anything crashing我只想简单地做到这一点,以便将错误注册到服务器,然后可以在客户端显示而不会出现任何崩溃

the execption thrown:抛出的异常:

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)

The "An established connection was aborted by the software in your host machine" exception is the client noticing the server process has crashed and closed the connection, while writing at Client.java:83. “已建立的连接被主机中的软件中止”异常是客户端注意到服务器进程已崩溃并关闭连接,同时写入 Client.java:83。

It would be more helpful to see crash information from the Server process where the defect appears to occur.从出现缺陷的服务器进程中查看崩溃信息会更有帮助。 However even without that, I notice you are using a space-delimited protocol, ie:但是即使没有那个,我注意到您正在使用以空格分隔的协议,即:

Client:客户:

// Send the ADD command and the bug report details to the server
outToServer.writeBytes("ADD " + appName + " " + dateTime + " " + platform + " " + problem + " " + status + "\n");

Server:服务器:

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

However this probably only functions as you intend if none of those fields includes an embedded space character, If they do, then it throws off the server parsing of the fields.但是,如果这些字段都不包含嵌入的空格字符,这可能只会按您的预期运行,如果包含,则它会抛出服务器对这些字段的解析。 and the trailing words in your new record will be truncated.并且您的新记录中的尾随单词将被截断。 The same assumption/problem occurs elsewhere in the server code.服务器代码中的其他地方也出现了同样的假设/问题。

I'm not sure why this would cause an actual crash, but you should probably choose a better delimiter character that is less likely to appear embedded in the field values.我不确定为什么这会导致实际崩溃,但您可能应该选择一个更好的分隔符,它不太可能出现在字段值中。

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

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