线程中的例外 - 多线程乐透程序

时间:2016-06-21 19:20:40

标签: java multithreading

我收到一个我无法解决的异常。

package advanced.net;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;

public class LottoClient {

    private InetAddress serverAddress;

    private int serverPort = LottoProtocol.SERVER_PORT;

    public static void main(String[] args) {
        System.out.println("Starting Client");
        LottoClient lottoClient1 = null;
        lottoClient1 = new LottoClient(); // This was not a TODO
        lottoClient1.startClient(args);
    }

    public LottoClient() {
    }

    private String getTicketFromServer() {
        String lotteryTicket = null;
        BufferedReader reader = null; // to get response from server
        PrintWriter writer = null; // to send request to server
        System.out.println("Getting Ticket");
        try {
            Socket socket = new Socket(serverAddress, serverPort);

            InputStream in = socket.getInputStream();
            OutputStream out = socket.getOutputStream();

            reader = new BufferedReader(new InputStreamReader(in));
            writer = new PrintWriter(out, true); // true for autoflush

            lotteryTicket = reader.readLine(); // read the response
        } catch (java.io.IOException e) {
            System.err.println("Error getting ticket");
            e.printStackTrace();
        } finally {
            try {
                if (reader != null) {
                    reader.close();
                }
                if (writer != null) {
                    writer.close();
                }
            } catch (java.io.IOException e) {
                e.printStackTrace();
            }
        }

        // TODO 08. Return the lottery ticket String.
        return lotteryTicket;
    }

    /**
     * configData[0] is the name or IP address of the server
     */
    private void processConfigData(String configData[]) {
        try {
            // set address of server
            if (configData != null && configData.length >= 1) {
                serverAddress = InetAddress.getByName(configData[0]);
            } else {
                // default case is set in our protocol
                String host = LottoProtocol.SERVER_HOST;
                serverAddress = InetAddress.getByName(host);
            }
        } catch (java.net.UnknownHostException e) {
            e.printStackTrace();
        }
    }

    public void startClient(String args[]) {
        processConfigData(args);
        String lottoTicket = getTicketFromServer();
        System.out.println(lottoTicket);
    }
}

package advanced.net;

import java.util.*;
import java.net.*;
import java.io.*;

public class LottoServer {

    // TODO 01. Make the handler a subclass of Thread.
    private class ClientRequestHandler extends Thread {

        private Socket socket = null;

        public ClientRequestHandler() {
            // Default Constructor
        }

        public ClientRequestHandler(Socket clientSocket) {
            socket = clientSocket;
        }

        /**
         * Generate a lotto ticket. Returns a formatted string containing 6
         * numbers from 1 to 49.
         */
        private String getTicket() {
            int theNumbers[] = new int[LottoProtocol.NUM_OF_NUMBERS];

            for (int i = 0; i < LottoProtocol.NUM_OF_NUMBERS; i++) {
                int newNumber;
                boolean isDuplicate = false;
                do {
                    isDuplicate = false; // reset isDuplicate, in case it has
                    // been set to true

                    // we want the numbers to be in the range of 1 to maxValue
                    // 0 to 48, and then add 1 to make it 1 to 49
                    newNumber = (int) (numberGenerator.nextDouble()
                            * (LottoProtocol.MAX_VALUE - 1) + 1);

                    // Compare to the numbers entered previously, to make sure
                    // it is
                    // not a duplicate.
                    // If it is, then ignore it, and get a new random number.
                    for (int j = 0; j < i && !isDuplicate; j++) {
                        if (newNumber == theNumbers[j]) {
                            isDuplicate = true;
                        }
                    }
                } while (isDuplicate);

                theNumbers[i] = newNumber;
            }
            Arrays.sort(theNumbers);
            StringBuffer sb = new StringBuffer();
            sb.append("Your numbers are: ");
            for (int k = 0; k < LottoProtocol.NUM_OF_NUMBERS; k++) {
                sb.append(String.valueOf(theNumbers[k]) + " ");
            }
            return sb.toString();
        }

        private void handleClientRequests() {
            BufferedReader reader = null; // to read client requests
            PrintWriter writer = null; // to send back response
            String request;

            try {
                InputStream in = socket.getInputStream();
                OutputStream out = socket.getOutputStream();

                reader = new BufferedReader(new InputStreamReader(in));
                writer = new PrintWriter(out, true); // true for autoflush

                writer.println("LottoServer 1.2");
                request = reader.readLine(); // read client request
                if (request
                        .equalsIgnoreCase(LottoProtocol.TICKET_REQUEST_COMMAND)) {
                    writer.println(getTicket()); // process the request
                }
            } catch (IOException ioe) {
                System.err.println("Error processing the request");
                ioe.printStackTrace();
            } finally {
                try {
                    if (reader != null) {
                        // TODO 05. Close the reader.
                        reader.close();
                    }
                    if (writer != null) {
                        // TODO 06. Close the writer.
                        writer.close();
                    }
                    if (socket != null) {
                        // TODO 07. Close the client socket.
                        socket.close();
                    }
                } catch (IOException ioe) {
                    ioe.printStackTrace();
                }
            }
        }

        public void run() {
            handleClientRequests();
        }

        public Socket getSocket() {
            return socket;
        }

        public void setSocket(Socket socket) {
            this.socket = socket;
        }
    }

    public static void main(String[] args) {
        LottoServer lottoServer1 = new LottoServer();
        lottoServer1.startServer();
    }

    private Random numberGenerator = new Random(System.currentTimeMillis());

    private ServerSocket serverSocket = null;

    public LottoServer() {
    }

    private void acceptConnections() {
        Socket clientSocket;
        while (true) {
            try {
                // TODO 02. Get the socket from the client.
                System.out.println("Socket Empty");
                clientSocket = null;
                clientSocket = serverSocket.accept();
                System.out.println("Socket Captured");
                // TODO 03. Create a new instance of the handler.
                ClientRequestHandler handler = null;
                handler = new ClientRequestHandler();
                System.out.println("Handler Created");
                handler.setSocket(clientSocket);
                Thread thread = new Thread(handler);
                System.out.println("Thread Created");
                // TODO 04. Start the new thread.
                thread.start();
                System.out.println("Thread Started Created");
            } catch (java.io.IOException e) {
                System.err.println("Error setting up connection");
                e.printStackTrace();
            }
        }
    }

    private void createServerSocket() {
        try {
            serverSocket = new ServerSocket(LottoProtocol.SERVER_PORT);
            System.out.println("Socket Created");
        } catch (java.io.IOException e) {
            String error = "Error setting up connection" + e.getMessage();
            System.err.println(error);
        }
    }

    public void startServer() {
        System.out.println("Server Started");
        createServerSocket();
        acceptConnections();
    }

}

package advanced.net;

public class LottoProtocol {

    public static final int MAX_VALUE = 49;

    public static final int NUM_OF_NUMBERS = 6;

    public static final String SERVER_HOST = "localhost";

    public static final int SERVER_PORT = 5123;

    public static final String TICKET_REQUEST_COMMAND = "GetTicket";
}

我已经编写了println语句来检查代码中的关键点。我相信这是我告诉线程在客户端连接后启动的地方,但是我无法跟踪空指针的来源。

1 个答案:

答案 0 :(得分:0)

如果您附加了您提到的异常的堆栈跟踪,那将会很有帮助。但是把它放在一边,你的问题就在handleClientRequests()类的ClientRequestHandler方法中,可能 - 再次,没有堆栈跟踪,特别是在以下行中:

request = reader.readLine(); // read client request

BufferedReader JavaDocs,readline()返回:

  

包含行内容的字符串,不包括任何行终止字符;如果已到达流的末尾,则为null。

因此,如果您的服务器收到空消息,则第一次调用readline()将返回null,并在下一行:

if (request.equalsIgnoreCase(LottoProtocol.TICKET_REQUEST_COMMAND)) {

你将获得NullPointerException。作为一个简单的修复,您可以反转此相等性检查并使用:

if (LottoProtocol.TICKET_REQUEST_COMMAND.equalsIgnoreCase(request)) {