2016-06-21 51 views
-1

我收到了一個我無法解決的異常。線程異常 - 多線程樂透程序

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語句來檢查代碼中的關鍵點。我相信這是我告訴線程在客戶端連接後啓動的地方,但我無法關注空指針的來源。

+3

什麼是異常的堆棧跟蹤? –

+1

什麼類型的異常? – Compass

+1

'我無法追蹤空指針來自哪裏'你可以[編輯](http://stackoverflow.com/posts/37952889/edit)你的問題包括那個'NullPointerException'的棧跟蹤? – dorukayhan

回答

0

如果您附加了您提到的異常的堆棧跟蹤將會很有幫助。但是離開那個放在一邊,你的問題在於(可能 - 再次,沒有堆棧跟蹤)在ClientRequestHandler類的handleClientRequests()方法,具體表現在以下行:

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

BufferedReader的JavaDoc,readline()回報:

包含該行內容的字符串,不包含任何行終止字符,如果已到達流尾,則返回null。

所以,如果你的服務器收到一個空的消息,第一次調用到readline()將返回null,並在下一行:

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

,你會得到一個NullPointerException。作爲一個簡單的修復,你可以扭轉這種平等檢查和使用:

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

這解決了異常的問題,但我不打算第一個調用應該有一個NULL指針。一旦我根據您的建議進行更改,我不會收到任何例外,但我也沒有收到返回的號碼。 – user3625654

+0

問題解決!有一行錯誤的代碼。非常感謝! – user3625654