2014-10-09 110 views
2

我正在爲計算機科學課程製作客戶端/服務器程序。HashMap InputStream/Scanner服務器問題

這個想法是,我們有一個服務器程序,它接受控制檯命令列表,執行它們,並通過輸入/輸出流返回響應。由於命令的格式化,我必須檢查空格和數字,並相應地拆分字符串(我已經完成)。問題似乎是從InputStream中檢索命令。

命令應該被接受:

放[字符串] [INT] - 這應該存儲在HashMap中的字符串(鍵)和int(值)

得到[字符串] - 這應該返回與此字符串

鍵集 相關的INT - 返回所有鍵

值 - 返回所有值

映射 - 返回所有映射

再見 - 退出客戶端

幫助 - 沒有做任何事情,但會列出所有的命令及其語法

教授給我們提供了服務器的大部分代碼,但我認爲它可能存在錯誤,因爲我一直在掃描儀上收到異常。看到下面的服務器代碼:

package mapserver; 

import java.io.BufferedReader; 
import java.io.IOException; 
import java.io.InputStream; 
import java.io.InputStreamReader; 
import java.io.OutputStream; 
import java.io.PrintWriter; 
import java.net.ServerSocket; 
import java.net.Socket; 
import java.util.Arrays; 
import java.util.HashMap; 
import java.util.List; 
import java.util.Map; 
import java.util.Scanner; 

public class MapServer 
{ 

    public static void main(String[] args) throws IOException 
    { 
     ServerSocket serverSocket = new ServerSocket(50000); 
     while (true) 
     { 
      Socket activeSock = serverSocket.accept(); 
      Thread th = new Thread(new MapServerThread(activeSock)); 
      th.start(); 
     } 
    }  
} 

class MapServerThread implements Runnable 
{ 
    private Map<String, Integer> map = new HashMap<>(); 
    private Socket sock; 
    public MapServerThread(Socket s) 
    { 
     sock = s; 

     List<String> strs = Arrays.asList("aaa a", "b", "a"); 
     for (String str : strs) 
     { 
      map.put(str, str.length()); 
     } 
    }  

    @Override 
    public void run() 
    { 
     try 
     { 
      InputStream in = sock.getInputStream(); 
      OutputStream out = sock.getOutputStream(); 
      BufferedReader reader = 
        new BufferedReader(new InputStreamReader(in)); 
      PrintWriter writer = new PrintWriter(out, true); 

      // welcome message 
      writer.println("Welcome to the map service."); 

      String inputLine = null; 
      while ((inputLine = reader.readLine()) != null) 
      { 
       Scanner sc = new Scanner(inputLine); 
       String fullLine = 
         sc.nextLine().toLowerCase().trim().replaceAll("\\s+", " "); 
       writer.println(fullLine); 

       int cmdLoc = 0; 
       for (int k = 0; k <fullLine.length(); k++) 
       { 
        if (fullLine.charAt(k)==' '); 
        { 
         cmdLoc = k; 
        } 
       } 

       String cmd; 
       if (cmdLoc == 0) 
       { 
        cmd = fullLine; 
        writer.println(cmd); 
       } 
       else 
       { 
        cmd = fullLine.substring(0, cmdLoc+1); 
        writer.println(cmd); 
       } 

       int startloc = cmd.length() + 1; 
       switch(cmd) 
       { 
        case "put": 
         int intlocation = startloc; 
         for (int k = 0; k < fullLine.length(); k++) 
         { 
          if (Character.isDigit(fullLine.charAt(k))) 
          { 
           intlocation = k; 
          } 
         } 

         // if the int is located at the beginning, the format 
         // is wrong. Let the user know 
         if (intlocation == startloc) 
         { 
          writer.println("Invalid entry. Correct format " 
            + "is \"put <string> <integer>\""); 
         } 

         // Split the user's entry for putting 
         else 
         { 
          String stringToPut = 
            fullLine.substring(startloc, intlocation+1); 
          int intToPut = 
            Integer.parseInt(fullLine.substring(intlocation)); 
          map.put(stringToPut, intToPut); 
          writer.println("Ok!"); 
         } 

         continue; 

        case "get": 
         int returnvalue = 
           map.get(fullLine.substring(startloc)); 
         writer.println(returnvalue); 
         continue; 

        case "keyset": 
         String result = map.keySet().toString(); 
         writer.println(result); 
         continue; 

        case "values" : 
         String result1 = map.values().toString(); 
         writer.println(result1); 
         continue; 

        case "mappings" : 
         writer.println(map.size()); 
         map.forEach(
            (k, v) -> 
             { writer.println(k + " " + v);} 
            );       
         continue; 

        case "bye" : 
         writer.println("See you later."); 
         sock.shutdownOutput(); 
         sock.close(); 
         return; 

        case "help" : 
         continue; 
        default : 
         writer.println("Not a recognized command"); 

       } 
      } 
     } catch (IOException ex) 
     { 
      throw new RuntimeException(ex); 
     } 

    }  
} 

我幾乎100%確定問題是在服務器程序,因爲我一直在用Telnet進行測試。我試過直接使用BufferedReader代替掃描器,但服務器似乎變得空白的字符串。有沒有人有任何想法?我已經擺弄了幾個小時,現在我無法弄清楚。

果殼中的問題:

後,我登錄時,服務器拋出:

Exception in thread "Thread-0" java.util.NoSuchElementException: No line found 
    at java.util.Scanner.nextLine(Scanner.java:1540) 
    at mapserver.MapServerThread.run(MapServer.java:67) 
    at java.lang.Thread.run(Thread.java:745) 

,我想不通爲什麼。如果我不使用掃描儀,出於某種原因服務器正在接收空白輸入,無論我輸入什麼內容。

這裏是正確的互動應該是什麼樣子:

Welcome to the MapService Client 
Enter the IP address of the server: localhost 
Please wait while I connect you... 
Welcome to the map service. 
Map service>mappings 
3 
a 1 
b 1 
aaa a 5 
Map service>put North Central College 2014 
Ok. 
Map service>keyset 
[a, b, aaa a, North Central College] 
Map service>get North Central  College 
2014 
Map service>help 
7 
help 
get key 
put key value 
values 
keyset 
mappings 
bye 
Map service>values 
[1, 1, 5, 2014] 
Map service>bye 
See you later. 
+0

你還沒有真正告訴我們是什麼問題 – ControlAltDel 2014-10-09 18:28:01

+0

我編輯它添加一些更 – aufty 2014-10-09 18:38:56

+0

我固定字符串錯誤。感謝您指出了這一點。在第一條命令後,我仍然遇到異常。 – aufty 2014-10-09 18:43:40

回答

1

您的代碼被打破,因爲它試圖解析兩次在同一行:

String inputLine = null; 
while ((inputLine = reader.readLine()) != null) //#1 

//... 

String fullLine =sc.nextLine().toLowerCase().trim().replaceAll("\\s+", " ");//#2 

您可以修復與特定部分:

String fullLine =inputLine.toLowerCase().trim().replaceAll("\\s+", " "); 

如果您收到一個空白的inputLine,無論出於何種原因,您可以跳過它w第i:

if(inputLine.trim().size()==0){ 
    continue;//invokes the next loop iteration 
} 

編輯:

我重寫了類,並試圖分裂的部分,使其更容易把握。請給一個反饋,即使您將其標示解決:

class MapServerThread implements Runnable { 

    private enum Commands { 
     PUT("(put)\\s(\\S+)\\s(\\d)"), 
     //add all your commands here and give an approriate regular expression 
     UNKNOWN(".+"); 

     private final String pattern; 

     Commands(String regexPattern) { 
      pattern = regexPattern; 
     } 

     private static Commands parseCommand(String s) { 
      Commands result = UNKNOWN; 

      s = s.toLowerCase(Locale.getDefault()); 

      for (Commands command : values()) { 
       if (command != UNKNOWN && command.pattern.matches(s)) { 
        result = command; 
        break; 
       } 
      } 
      return result; 
     } 
    } 

    private Map<String, Integer> map = new HashMap<>(); 
    private Socket sock; 

    public MapServerThread(Socket s) { 
     sock = s; 

     List<String> strs = Arrays.asList("aaa a", "b", "a"); 
     for (String str : strs) { 
      map.put(str, str.length()); 
     } 
    } 

    @Override 
    public void run() { 
     try { 
      BufferedReader reader = new BufferedReader(new InputStreamReader(sock.getInputStream())); 

      PrintWriter writer = new PrintWriter(sock.getOutputStream(), true); 

      writer.println("Welcome to the map service."); 

      String inputLine = null; 
      while ((inputLine = reader.readLine().trim()) != null) { 
       Commands command = Commands.parseCommand(inputLine); 

       writer.println(command.name()); 

       execute(command, inputLine); 
      } 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 

    private void execute(Commands command, String inputLine) { 

     switch (command) { 
      case PUT: 
       String[] args = inputLine.split(" "); 
       map.put(args[1], Integer.parseInt(args[2])); 
       break; 
      //handle the other commands accordingly 
      default: 
       // notify about an error 
       break; 

     // 
     // get [string] - this should return the int associated with this string 
     // 
     // keyset - return all keys 
     // 
     // values - return all values 
     // 
     // mappings - return all mappings 
     // 
     // bye - quit the client 
     // 
     // help - doesn't do anything yet, but will list all commands and their 
     // syntax 

     } 
    } 

} 
+0

這消除了錯誤,但現在它在完成輸入的命令後發送空白命令,導致返回的默認開關情況。 – aufty 2014-10-09 18:55:48

+0

是的,我一直在閱讀你的代碼。 Iam「着迷」寫在那裏的東西。給我一點時間。 – 2014-10-09 19:00:17

+0

看起來有更多的問題比我意識到的。由於某種原因,我的循環找到第一個空白始終返回1,導致cmd始終爲3個字符長 – aufty 2014-10-09 19:13:29