我正在编写我的第一个非平凡的Java应用程序,它使用:
这是一个IM程序。当我发送消息时,服务器不会输出它应该的内容。对不起,这个描述太糟糕了,但我不知道如何进一步缩小这个问题。
public class MachatServer {
//snip
public static void sendMessage(int targetId, int fromId, String message) {
ConnectedClient targetClient = getClient(targetId);
// Also runs
System.out.println("Sending message: " + message + "\n\nfrom " + fromId + " to " + targetId);
targetClient.addOutCommand("/message:" + fromId + ":" + message + "\n");
}
}
class ConnectedClient implements Runnable {
public void run() {
String contact;
contact = s.getInetAddress().toString();
System.out.println("Connected to " + contact);
try {
out.write("/connected" + "\n");
out.flush();
String command;
while(true) {
if(shouldExit) {
s.close();
break;
}
if(in.hasNextLine()) {
command = in.nextLine();
commandProcessor.addInCommand(command);
}
Thread.sleep(100);
}
} catch(Exception e) {
e.printStackTrace();
}
}
// snip
public void addOutCommand(String command) {
commandProcessor.addOutCommand(command);
//
// My guess is that the problem is with this method as the next line
// Does not print out.
//
//
System.out.println("" + thisId + " recieved to send: " + command);
}
}
class CommandProcessor implements Runnable {
// snip
public void run() {
String currentCommandIn;
String currentCommandOut;
while(true) {
try {
currentCommandIn = inQueue.poll();
if(currentCommandIn != null) {
System.out.println("Processing: " + currentCommandIn);
String[] commandArr = CommandParser.parseRecievedCommand(currentCommandIn);
if(commandArr[0].equalsIgnoreCase("message")) {
int target = Integer.parseInt(commandArr[1]);
String message = commandArr[2];
// This definetly runs
System.out.println("Message sending to: " + target);
MachatServer.sendMessage(target, this.conId, message);
} else if(commandArr[0].equalsIgnoreCase("quit")) {
// Tell the server to disconnect us.
MachatServer.disconnect(conId);
break;
}
currentCommandOut = outQueue.poll();
if(currentCommandOut != null) {
try {
out.write(currentCommandOut + "\n");
System.out.println(currentCommandOut + "sent");
out.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
} catch(Exception e) {
e.printStackTrace();
}
public synchronized void addOutCommand(String command) {
if(command != null) {
try {
outQueue.push(command);
} catch(Exception e) {
System.out.println(command);
e.printStackTrace();
}
// Does not print
System.out.println("Ready to send: " + command);
} else {
System.out.println("Null command recieved");
}
//snip
}
完整源代码位于my github,以防我错误地缩小了问题。
预期输出应该是当我telnet并发送“/ message:0:test”时,它应该将“/ message: myid :test”发送给ID为0的客户端。输出什么都没有。
答案 0 :(得分:3)
这可能不是一个完整的答案,但是您的代码有一些严重问题可能导致您的问题,所以您应该先解决这些问题。
首先,CommandProcessor.run
中的循环正忙着等待,即它不断运行。您应该使用阻止操作。此外,inQueue
和outQueue
可以从两个不同的线程访问,因此您需要在每次访问时进行同步。我建议使用实现java.util.concurrent.BlockingQueue
接口的东西来解决这两个问题。最后,在检查完整代码时,您似乎还需要同步对ConnedtedClient.shouldExit
字段的访问(我相信您可以使用`java.util.concurrent.atomic.AtomicBoolean作为替代,但我不是肯定)。
这可能是导致问题的原因:由于CommandProcessor.run
没有在任何事情上进行同步(或访问任何易变的东西),Java虚拟机可以假设外部没有任何内容可以修改它检查的任何内容,所以在理论上,当run
方法首先注意到inQueue
和outQueue
都是空的时,它可以将整个方法优化为空,因为它可以假设它是唯一的可以修改它们。但是我不知道这是否真的会在实践中发生,因为JVM需要对LinkedList
实现有很多了解,并注意到线程只是在循环中进行这两个检查。但最好是安全,因为这样你的代码就可以保证工作。
答案 1 :(得分:2)
字段outQueue
在CommandProcessor中未初始化,您注释掉了可以帮助您解决问题的printStackTrace()
。
答案 2 :(得分:-1)
问题可能是您发送的数据很短......
我的一位朋友在几年前遇到了类似的问题,结果发现数据被缓冲,直到有足够的数据发送......
这与优化网络流量有关...我相信当他最终解决它时,他提到了一种叫做“Nagle算法”的东西....
希望这可以提供一些帮助......