HashMap InputStream / Scanner服务器问题

时间:2014-10-09 18:24:43

标签: java inputstream java.util.scanner

我正在为计算机科学课程制作客户端/服务器程序。

我们的想法是,我们有一个服务器程序,它接受控制台命令列表,执行它们,并通过输入/输出流返回响应。由于命令的格式化,我必须检查空格和数字并相应地拆分字符串(我已经完成了)。问题似乎在于从InputStream中检索命令。

应该接受的命令:

  

put [string] [int]    - 这应该在HashMap中存储一个字符串(key)和int(value)

     

获取[string]    - 这应返回与此字符串相关联的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.

1 个答案:

答案 0 :(得分: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,您可以跳过:

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

        }
    }

}