缓冲读取器未从套接字接收数据

Posted

技术标签:

【中文标题】缓冲读取器未从套接字接收数据【英文标题】:buffered reader not receiving data from socket 【发布时间】:2011-09-15 15:17:57 【问题描述】:

我正在编写一个客户端应用程序,它将通过 tcp/ip 接收连续的数据流。我遇到的问题是缓冲的读取器对象没有接收任何数据并且挂在 readline 方法上。

服务器的工作方式是您连接到它,然后发送身份验证信息以接收数据。我的代码要点如下

socket = new Socket(strHost, port);
authenticate();
inStream = new BufferedReader(new InputStreamReader(socket.getInputStream()));
process(inStream);

authenticate()
      
  PrintWriter pwriter = new PrintWriter(socket.getOutputStream(), true);
  pwriter.println(authString);


process(BufferedReader bufferedReader)

   while((line = bufferedReader.readLine()) != null)
      dostuff

我创建了一个示例服务器应用程序,它以(我认为)服务器发送数据的方式发送数据,它连接、接收和处理数据。我可以在我的应用程序中很好地连接到服务器。我还可以远程登录到服务器并写入身份验证字符串并使用远程登录接收大量数据。然而,我的应用程序只是挂在服务器的 readLine 上,我不知道为什么。

传入的数据(至少通过 telnet)看起来像以下内容的连续流:

 data;data;data;data;data
 data;data;data;data;data

为什么我的应用程序挂在 readline 上,我没有正确输出身份验证行吗?我没有收到任何错误...

编辑 我的示例服务器代码(工作正常)...再次,这只是模仿 我认为真实服务器的运行方式,但我可以在我的应用程序中连接到两者只是没有从真实服务器接收数据。

  public static void main(String[] args) throws IOException
  
  ServerSocket serverSocket = null;

  try
  
     serverSocket = new ServerSocket(1987);
  
  catch (IOException e)
  
     System.out.println("Couldn't listen on port: 1987");
     System.exit(-1);
  

  Socket clientSocket = null;
  try
  
     clientSocket = serverSocket.accept();
  
  catch (IOException e) 
     System.out.println("Accept failed: 1987");
     System.exit(-1);
  

  PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
  BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
  String something;

  while ((something = in.readLine()) != null)
  
     while(true)
     
        out.println(message);
     
  



  out.close();
  in.close();
  clientSocket.close();
  serverSocket.close();

【问题讨论】:

你能告诉我们与问题相关的服务器代码吗? I can connect to the server fine in my application. 你的意思是你的虚拟样本服务器? 也许您应该在发送身份验证之前准备好另一个线程来读取您的数据?我假设服务器一得到密码就开始泛滥数据。 Mannimarco,我可以展示示例服务器...我没有连接到服务器的代码。 Leonbloy,我可以很好地连接到两台服务器。 【参考方案1】:

首先你应该在调用readLine()之前调用BufferedReader.ready(),因为ready()会告诉你是否可以阅读。

PrintWriter 不会抛出 I/O 异常,因此写入可能在您不知情的情况下失败,这就是为什么没有什么可读取的原因。使用PrintWriter.checkError() 查看写入过程中是否有任何问题。

在将任何内容写入管道之前,您应该同时在Socket 上设置输入和输出流。如果您的阅读器在另一端尝试写入时尚未准备好,您将在服务器中获得一个损坏的管道,并且它不会再发送任何数据。 Telnet 在您写入或读取任何内容之前设置读取和写入。

您可以使用Wireshark 来判断服务器是否真的在发送数据。

【讨论】:

bufferedreader.ready 似乎可以解决问题,感谢有关 printwriter.checkerror 的提示,我也将其添加到我的代码中。 @DavidNewcomb 为什么我应该在发送之前从套接字的 InputStream 设置一个 BufferedReader?它真的会吃掉事先到达的数据吗?这如何与始终具有可用初始数据的数据源一起工作? -- 我希望任何 Stream 包装器都能获取,但不吃初始数据? 使用 BufferedXxx 你不能说读或写什么时候会真正发生。通信通道是一个管道,管道必须让阅读器和编写器一起工作。它不吃数据,如果你尝试写一些东西并且没有什么可以读取它,你会得到一个损坏的管道,就像如果另一端没有人在写,你的读取会阻塞一样。 BufferedReader.ready() 在这里和大多数其他用途都是毫无意义的。它不会告诉你一条完整的线路已经到达,所以readLine() 仍然有可能在线路终结符到达之前阻塞。 @EJP,它在这种情况下有效,不是吗!通常,如果您正在读取行,则另一端的事情是写行,因此系统会平衡,因为另一端的回车会强制流刷新。当您调用 ready() 时,您很可能会得到一整行。从读取代码 BufferedReader.readLine() 以非阻塞方式读取任何可用数据,直到流结束或到达新行。虽然 readLine 似乎不会阻止它,但它会在内部循环检查数据并读取它。这是一个微妙的区别,但在谈论 CPU 使用率时很重要。【参考方案2】:

我的作品 带插座不带冲水

void start_listen()
   
       String    result1="";
       char[] incoming = new char[1024];
       while (!s.isClosed())
       
           try 

           int lenght  =  input.read(incoming);
               result1 = String.copyValueOf(incoming,0,lenght);


           
           catch (IOException e)
           
               e.printStackTrace();
           
           Log.d("ddddddddddd",result1);

       

【讨论】:

【参考方案3】:

BufferdReader.readLine() 读取行,即以\r\r\n 结尾的字符序列。我猜您的服务器将其输出写入一行。您的 telnet 输出证明了这一假设。只需在服务器端使用PrintWriter.println()

【讨论】:

如果是长连续流,他将不得不使用read(char[] cbuf, int off, int len)

以上是关于缓冲读取器未从套接字接收数据的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Linux 中创建原始套接字而不缓冲接收数据包?是不是可以?

unix 套接字数据报:服务器接收到无效字符

如何获取刚刚从套接字接收到的缓冲区的长度?

matlab串口接收数据的问题

C SOCKS5 代理接口未从代理服务器接收任何内容。

如何在 Winsock 中查找当前使用的 UDP 接收缓冲区大小