java - HashMap InputStream/Scanner 服务器问题

标签 java inputstream java.util.scanner

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

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

应该接受的命令:

put [string] [int] - this should store a string (key) and int (value) in the HashMap

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

教授给了我们服务器的大部分代码,但我认为其中可能存在错误,因为我一直在 Scanner 上遇到异常。请参阅下面的服务器代码:

    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.

最佳答案

您的代码已损坏,因为它试图两次解析同一行:

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)并尝试拆分各个部分以使其更容易掌握。即使您将其标记为已解决,也请提供反馈:

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

        }
    }

}

关于java - HashMap InputStream/Scanner 服务器问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26285483/

相关文章:

java - 是否可以在 JTextfield 上虚拟地抛出 KeyEvent?

java - 扫描仪不会扫描负数

java - 在服务器上运行但在 devbox 上不运行的 spring mvc 应用程序出现 404 错误

java - 如何将类对象写入bin文件

Linux机器中的Java进程InputStream

Java 扫描器输入循环

java - 如何在java中找到五个最接近零的输入数字

java - 即使存在主类,Java也无法找到主类

java - RSA 如何将 key 分发给发送者和接收者?

java - JAVE (Java Audio Video Encoder) 库异常仅在 Linux (CentOS 7)