我正在为计算机科学课程制作客户端/服务器程序。
我们的想法是,我们有一个服务器程序,它接受控制台命令列表,执行它们,并通过输入/输出流返回响应。由于命令的格式化,我必须检查空格和数字并相应地拆分字符串(我已经完成了)。问题似乎在于从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.
答案 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
}
}
}