Java网络代码不发送

时间:2009-10-17 16:57:33

标签: java multithreading network-programming

我正在编写我的第一个非平凡的Java应用程序,它使用:

  • 联网
  • 一个GUI
  • 线程

这是一个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的客户端。输出什么都没有。

3 个答案:

答案 0 :(得分:3)

这可能不是一个完整的答案,但是您的代码有一些严重问题可能导致您的问题,所以您应该先解决这些问题。

首先,CommandProcessor.run中的循环正忙着等待,即它不断运行。您应该使用阻止操作。此外,inQueueoutQueue可以从两个不同的线程访问,因此您需要在每次访问时进行同步。我建议使用实现java.util.concurrent.BlockingQueue接口的东西来解决这两个问题。最后,在检查完整代码时,您似乎还需要同步对ConnedtedClient.shouldExit字段的访问(我相信您可以使用`java.util.concurrent.atomic.AtomicBoolean作为替代,但我不是肯定)。

这可能是导致问题的原因:由于CommandProcessor.run没有在任何事情上进行同步(或访问任何易变的东西),Java虚拟机可以假设外部没有任何内容可以修改它检查的任何内容,所以在理论上,当run方法首先注意到inQueueoutQueue都是空的时,它可以将整个方法优化为空,因为它可以假设它是唯一的可以修改它们。但是我不知道这是否真的会在实践中发生,因为JVM需要对LinkedList实现有很多了解,并注意到线程只是在循环中进行这两个检查。但最好是安全,因为这样你的代码就可以保证工作。

答案 1 :(得分:2)

字段outQueue在CommandProcessor中未初始化,您注释掉了可以帮助您解决问题的printStackTrace()

答案 2 :(得分:-1)

问题可能是您发送的数据很短......

我的一位朋友在几年前遇到了类似的问题,结果发现数据被缓冲,直到有足够的数据发送......

这与优化网络流量有关...我相信当他最终解决它时,他提到了一种叫做“Nagle算法”的东西....

希望这可以提供一些帮助......