Java 套接字提前结束流

Posted

技术标签:

【中文标题】Java 套接字提前结束流【英文标题】:Java socket giving premature end of stream 【发布时间】:2011-02-02 16:21:44 【问题描述】:

我正在设置一个连接到 XMPP 服务器的彗星服务器。以下是它的下降方式:

客户端与 Comet 服务器连接,并且打开了一个套接字连接:

try 
        radio = new Socket("server", 5222);
        out = new PrintWriter(radio.getOutputStream(), true);
        in = new BufferedReader(new InputStreamReader(radio.getInputStream()));
     catch (UnknownHostException e) 
        System.out.println("Unknown host: "+e);
        error = e.toString();
     catch(IOException e) 
        System.out.println("IO error: "+e);
        error = e.toString();
    

接下来,启动一个线程,等待来自套接字的数据:

public void run() 
        System.out.println("Thread started.");
        String data;
        String error;
        Client remote;
        Client client;
        while(!done) 
            data = this.output();
            remote = bayeux.getClient(remoteId);
            client = bayeux.getClient(clientId);
            if(data!=null) 
                Map<String, Object> packet = new HashMap<String, Object>();
                packet.put("xml", data);
                remote.deliver(client, "/radio/from", packet, null);
            
            error = this.error();
            if(error!=null) 
                Map<String, Object> packet = new HashMap<String, Object>();
                packet.put("details", error);
                remote.deliver(client, "/radio/error", packet, null);
            
            /* try  
                Thread.sleep(500); 
              
            catch (InterruptedException e ) 
                System.out.println("Interrupted!");  */
        

        try 
            in.close();
            out.close();
            radio.close();
         catch(IOException e) 
            System.out.println("Error disconnecting: "+e);
            error = e.toString();
        
        System.out.println("Thread stopped.");
    

    public String output() 
        try 
            String data = in.readLine();
            System.out.println("From: "+data);
            if(data==null) 
                System.out.println("End of stream!");
                try 
                    Thread.currentThread().sleep(1000);
                 catch (InterruptedException e) 
                    e.printStackTrace();
                
                //error = "End of stream.";
                //this.disconnect();
            
            return data;
         catch (IOException e) 
            error = e.toString();
            System.out.println("IO error! "+e);
        
        return null;
    

从客户端接收到的任何输入都会转发到 XMPP 服务器:

    public void input(String xml) 
        System.out.println("To: "+xml);
        out.println(xml);
    

所以这就是问题所在。客户端打开连接并将正确的 XML 发送到 XMPP 服务器以启动流。 in.readLine(); 应该挂起,直到收到来自服务器的响应。收到后,in.readLine(); 开始一遍又一遍地返回 null。这不应该发生;它应该挂起,直到它接收到数据。服务器似乎不太可能对我关闭,它没有发送&lt;/stream:stream&gt; 来表示 XMPP 流的结束。关于可能是什么问题的任何想法?

感谢您的帮助!

【问题讨论】:

你说服务器关闭连接的可能性不大,但为了安全起见,你真的检查过 readLine() 返回 null 后 radio.isConnected() 返回什么吗? 很遗憾您没有只使用 BOSH (xmpp.org/extensions/xep-0206.html),或者您可以为客户端、服务器或两者使用现成的东西。 【参考方案1】:

请记住,XMPP 连接可以并且会给您提供不完整的节,或者在一次读取中提供多个节。如果您的 COMET 连接期望您传递的内容是格式良好的 XML,那么您将遇到问题。同样,XMPP 不是换行符终止的,所以我不确定您为什么期望 readLine() 非常有用。

接下来,您是否在同一线程上的两个不同套接字上进行同步 I/O?听起来像是陷入僵局的秘诀。如果你坚持走这条路(而不仅仅是使用BOSH),我强烈建议你使用 NIO,而不是你的 sleep hack。

【讨论】:

我会给 NIO 一个机会,尽管我在某处读到现代 linux 系统(我认为提到了 POSIX)线程套接字实际上比 NIO 更有效。但我认为一些重新编码会很好,代码有点糟糕 XD 对 readLine 的良好调用对 XML 没有用处,这是一件愚蠢的事情。

以上是关于Java 套接字提前结束流的主要内容,如果未能解决你的问题,请参考以下文章

YAML语法字符

用于 UDP NAT 打孔的 PHP 和 Java...?

Linux网络套接字编程

Linux网络套接字编程

Linux网络套接字编程

Linux网络编程之套接字 -- UDP