2012-05-06 34 views
0

我正在编写一个大型Java应用程序的服务器部分,用于通过TCP/IP使用Java套接字与客户端进行通信。客户端(用PHP编写)连接到服务器,以XML格式发送查询,然后服务器发回响应。查询响应可以在单个连接中重复多次。不能通过Java套接字发送消息而不关闭它

服务器端很简单。它应该允许多个客户端连接,所以有一个线程监听并为每个接受的连接产生一个会话。会话包含一个对象,该对象包含两个用于传输和接收的LinkedBlockingQueues,两个用于使用这些队列传输和接收消息的线程以及一个处理线程。

问题是,只有在套接字关闭后,任何消息才会被实际传输。响应消息没有问题地进入消息队列和PrintStream.println()方法,但wireshark仅在客户端关闭连接时报告传输。使用启用自动刷新或使用flush()创建PrintStream不起作用。关闭服务器端的套接字也不起作用,服务器仍然运行并接收消息。

此外,当前在客户端接收服务器端查询的实现工作正常,同样来自本地Linux虚拟机echo -e "test" | socat - TCP4:192.168.37.1:1337,但是当我telnet到服务器并尝试发送一些东西,然后服务器没有收到任何东西,直到我关闭telnet客户端,同样的问题,如上所述。

相关的服务器代码(整个应用程序太大粘贴的一切,我有很多其他人的代码工作):

package Logic.XMLInterfaceForClient; 

import java.io.BufferedReader; 
import java.io.IOException; 
import java.io.InputStreamReader; 
import java.io.PrintStream; 
import java.net.Socket; 
import java.util.HashSet; 
import java.util.concurrent.LinkedBlockingQueue; 

import Data.Config; 
import Logic.Log; 

public class ClientSession { 

    /** 
    * @author McMonster 
    * 
    */ 
    public class MessageTransmitter extends Thread { 

     private final Socket socket; 
     private final ClientSession parent; 

     private PrintStream out; 

     /** 
     * @param socket 
     * @param parent 
     */ 
     public MessageTransmitter(Socket socket, ClientSession parent) { 
      this.socket = socket; 
      this.parent = parent; 
     } 

     /* 
     * (non-Javadoc) 
     * 
     * @see java.lang.Runnable#run() 
     */ 
     @Override 
     public void run() { 
      try { 
       out = new PrintStream(socket.getOutputStream(), true); 

       while (!socket.isClosed()) { 
        try { 
         String msg = parent.transmit.take(); 
         // System.out.println(msg); 
         out.println(msg); 
         out.flush(); 
        } 
        catch(InterruptedException e) { 
         // INFO: purposefully left empty to suppress spurious 
         // wakeups 
        } 
       } 

      } 
      catch(IOException e) { 
       parent.fail(e); 
      } 

     } 

    } 

    /** 
    * @author McMonster 
    * 
    */ 
    public class MessageReceiver extends Thread { 

     private final Socket socket; 
     private final ClientSession parent; 

     private BufferedReader in; 

     /** 
     * @param socket 
     * @param parent 
     */ 
     public MessageReceiver(Socket socket, ClientSession parent) { 
      this.socket = socket; 
      this.parent = parent; 
     } 

     /* 
     * (non-Javadoc) 
     * 
     * @see java.lang.Runnable#run() 
     */ 
     @Override 
     public void run() { 
      try { 
       in = new BufferedReader(new InputStreamReader(socket.getInputStream())); 

       while (!socket.isClosed()) { 
        String message = ""; 
        String line; 

        while ((line = in.readLine()) != null) { 
         message = message + line + "\n"; 
        } 

        if(message != "") { 
         parent.receive.offer(message.toString()); 
        } 
       } 
      } 
      catch(IOException e) { 
       parent.fail(e); 
      } 

     } 
    } 

    public final LinkedBlockingQueue<String> transmit = new LinkedBlockingQueue<>(); 
    public final LinkedBlockingQueue<String> receive = new LinkedBlockingQueue<>(); 

    private final XMLQueryHandler xqh; 
    private final Socket socket; 

    private String user = null; 
    private HashSet<String> privileges = null; 

    /** 
    * @param socket 
    * @param config 
    * @throws IOException 
    * @throws IllegalArgumentException 
    */ 
    public ClientSession(Socket socket, Config config) 
      throws IOException, 
      IllegalArgumentException { 
     // to avoid client session without the client 
     if(socket == null) throw new IllegalArgumentException("Socket can't be null."); 

     this.socket = socket; 

     // we do not need to keep track of the two following threads since I/O 
     // operations are currently blocking, closing the sockets will cause 
     // them to shut down 
     new MessageReceiver(socket, this).start(); 
     new MessageTransmitter(socket, this).start(); 

     xqh = new XMLQueryHandler(config, this); 
     xqh.start(); 
    } 

    public void triggerTopologyRefresh() { 
     xqh.setRefresh(true); 
    } 

    public void closeSession() { 
     try { 
      xqh.setFinished(true); 
      socket.close(); 
     } 
     catch(IOException e) { 
      e.printStackTrace(); 
      Log.write(e.getMessage()); 
     } 
    } 

    /** 
    * Used for reporting failures in any of the session processing threads. 
    * Handles logging of what happened and shuts down all session threads. 
    * 
    * @param t 
    *   cause of the failure 
    */ 
    synchronized void fail(Throwable t) { 
     t.printStackTrace(); 
     Log.write(t.getMessage()); 
     closeSession(); 
    } 

    synchronized boolean userLogin(String login, HashSet<String> privileges) { 
     boolean success = false; 

     if(!privileges.isEmpty()) { 
      user = login; 
      this.privileges = privileges; 
      success = true; 
     } 

     return success; 
    } 

    public synchronized boolean isLoggedIn() { 
     return user != null; 
    } 

    /** 
    * @return the privileges 
    */ 
    public HashSet<String> getPrivileges() { 
     return privileges; 
    } 
} 

回答

0

我可以理解为什么没有消息在服务器接收直到插座关闭 - 这似乎是设计。 in.readLine()只有在流的结束时才会返回null,在TCP套接字流的情况下,这意味着套接字关闭。如果你希望你的readLine()循环在这之前返回,循环中的代码将不得不使用你在TCP之上使用的任何协议来定义消息来检测消息的结束。

+0

你说得对,我想这可能是所有这些都无法正常工作的原因。我将编写一些可接受的XML消息检测,看看它是否修复它。 – McMonster

+0

我已经在读取一行并检查null的地方添加了XML验证,现在它可以正常工作。问题是关闭连接后才收到查询,因此无法在同一连接中发送响应。感谢您的帮助。 – McMonster

1

根本没有任何关系,发送。如果你认为的值为直到流结束,你将不会得到流的结束,直到对端通过关闭套接字结束流。

这是一个重言式。

相关问题