我正在为计算机科学类(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/