【问题标题】:Reading from Socket从套接字读取
【发布时间】:2011-10-29 12:32:44
【问题描述】:

我在让这个简单的类工作时遇到问题。它基本上连接到 IMAP 服务器并读取横幅。但是在阅读了所有字符之后,它有点悬。在调试器中,我可以单步执行 while 循环并查看正在读取所有字符并最终退出循环。但是最后一个 System.out.println 语句永远不会到达。

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.Socket;


public class TestClient
{

    /**

        @param args

     */
    public static void main( String[] args ) throws Exception
    {

        Socket socket = new Socket( "imap.1and1.com", 143 );

        DataOutputStream os = new DataOutputStream( socket.getOutputStream() );
        BufferedReader reader = new BufferedReader( new InputStreamReader( socket.getInputStream() ) );

        StringBuilder sb = new StringBuilder();
        char ch = (char) reader.read();
        while ( ch != -1 ) {
            sb.append( ch );
            ch = (char) reader.read();

        }

        System.out.println( sb.toString() ); /// <--- never prints anything and program just hangs..
    }

}

【问题讨论】:

    标签: java sockets bufferedreader


    【解决方案1】:

    如果没有要读取的数据,read 函数会阻塞,只有在 readStream 关​​闭或套接字连接断开时才会出现。您应该做的是创建一个协议,在完全读取数据后断开连接。即你应该跳出循环

    • 在所有数据都已完成后以某种方式断开连接 已读取(为此您必须确定所有数据已被读取)

    • 如果您已经阅读了一些之前同意的内容,请自行退出循环 “消息结束”字符串..

    还有一件事,由于 read() 阻塞,等待更多数据,建议你应该在后台线程中读取..

    【讨论】:

    • 在线路协议类型的服务器应用程序(例如:POP/IMAP)中,没有预定义的字符来指示特定命令结果的结束。在这种情况下该怎么办?顺便说一句,在我上面的例子中做 readline 是可行的。但我期待的不仅仅是单行,而且将 readLine 放入循环中也会阻塞。
    • 那么您正在使用 BufferedReader..检查是否有任何选项可以告诉读取函数在没有数据要读取时不要阻塞..
    【解决方案2】:

    好的,这就是我为解决我的特定问题所做的。请注意,使用 ready() 或 available() 方法并不总是可靠的。特别是如果服务器要发送数据,暂停然后发送更多数据。就我而言,它可以工作,因为我不希望服务器在响应过程中停止并再次重新启动。

    代码显然没有针对实际使用进行优化。

    import java.io.BufferedReader;
    import java.io.InputStreamReader;
    import java.net.Socket;
    
    /**
            @author Mir Shafiqul Islam &lt;mislam@mirislam.comt&gt;
    
     */
    public class TestClient
    {
    
        /**
    
            @param args
    
         */
        public static void main( String[] args ) throws Exception
        {
            // Open the socket
            Socket socket = new Socket( "localhost", 25143 );
            // Get a buffered reader
            BufferedReader reader = new BufferedReader( new InputStreamReader( socket.getInputStream() ) );
            // At this point it is too early to read. So it most likely return false
            System.out.println( "Buffer Reader ready? " + reader.ready()); 
            // StringBuilder to hold the response
            StringBuilder sb = new StringBuilder();
            // Indicator to show if we have started to receive data or not
            boolean dataStreamStarted = false;
            // How many times we went to sleep waiting for data
            int sleepCounter = 0;
            // How many times (max) we will sleep before bailing out
            int sleepMaxCounter = 50;
            // Sleep max counter after data started
            int sleepMaxDataCounter = 3;
            // How long to sleep for each cycle
            int sleepTime = 50;
            // Start time
            long startTime = System.currentTimeMillis();
            // This is a tight loop. Not sure what it will do to CPU
            while( true ) {
                if ( reader.ready() )
                {
                    sb.append( (char) reader.read() );
                    // Once started we do not expect server to stop in the middle and restart
                    dataStreamStarted = true; 
                } else {
                    Thread.sleep( sleepTime );
                    if ( dataStreamStarted && (sleepCounter >= sleepMaxDataCounter) ) {
                        System.out.println( "Reached max sleep time of " + (sleepMaxDataCounter*sleepTime) + " ms after data started" );
                        break;
                    } else {
                        if (sleepCounter >= sleepMaxCounter) {
                            System.out.println( "Reached max sleep time of " + (sleepMaxCounter*sleepTime) + " ms. Bailing out" );
                            // Reached max timeout waiting for data. Bail..
                            break;
                        }
                    }
                    sleepCounter++;
                }
    
            }
            long endTime = System.currentTimeMillis();
    
            System.out.println( sb.toString() );
            System.out.println( "Time " + (endTime-startTime));
        }
    
    }
    

    【讨论】:

      猜你喜欢
      • 2019-04-02
      • 2013-10-12
      • 1970-01-01
      • 2012-03-08
      • 2011-03-05
      • 2014-06-07
      • 2013-11-14
      • 2013-09-27
      相关资源
      最近更新 更多