буферизованный считыватель не получает данные из сокета

Я пишу клиентское приложение, которое будет получать непрерывный поток данных через 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
}

Я создал пример серверного приложения, которое отправляет данные так, как (я думаю) сервер отправляет данные, и он подключается, получает и обрабатывает данные. Я могу нормально подключиться к серверу в своем приложении. Я также могу подключиться к серверу через telnet, написать строку аутентификации и получить поток данных с помощью telnet. Однако мое приложение просто зависает на readLine с сервером, и я не понимаю, почему.

Входящие данные (по крайней мере, через telnet) выглядят как непрерывный поток следующего:

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

Почему мое приложение зависает на строке чтения, я неправильно вывожу строку аутентификации? Я не получаю никаких ошибок...

ИЗМЕНИТЬ Мой образец кода сервера (который работает правильно)... опять же, это только имитация того, как, я думаю, работает реальный сервер, но Я могу подключиться к обоим в своем приложении, просто не получая данные с реального сервера.

  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();
}

person Ryan    schedule 15.06.2011    source источник
comment
Можете ли вы показать нам код сервера, связанный с проблемой?   -  person Coeffect    schedule 15.06.2011
comment
I can connect to the server fine in my application. Вы имеете в виду свой фиктивный образец сервера?   -  person leonbloy    schedule 15.06.2011
comment
Может быть, у вас должен быть другой поток, готовый прочитать ваши данные перед отправкой аутентификации? Я предполагаю, что сервер просто начинает заливать данные, как только получает пароль.   -  person toto2    schedule 15.06.2011
comment
Маннимарко, я могу показать образец сервера... У меня нет кода для сервера, к которому я подключаюсь. Leonbloy, я могу подключиться к обоим серверам.   -  person Ryan    schedule 15.06.2011


Ответы (3)


Во-первых, вы должны позвонить BufferedReader.ready() перед вызовом readLine(), так как ready() сообщит вам, можно ли читать.

PrintWriter не генерирует исключение ввода-вывода, поэтому запись могла завершиться неудачно без вашего ведома, поэтому читать нечего. Используйте PrintWriter.checkError(), чтобы увидеть, не пошло ли что-то не так во время записи.

Вы должны настроить потоки ввода и вывода на Socket одновременно, прежде чем что-либо записывать в трубу. Если ваш считыватель не готов, когда другой конец пытается записать, вы получите сломанный канал на сервере, и он больше не будет отправлять данные. Telnet настраивает чтение и запись до того, как вы что-либо запишете или прочитаете.

Вы можете использовать Wireshark, чтобы определить, действительно ли сервер отправляет данные.

person David Newcomb    schedule 15.06.2011
comment
bufferedreader.ready, похоже, помог, спасибо за подсказку об ошибке printwriter.checkerror, я добавляю это в свой код. - person Ryan; 15.06.2011
comment
@DavidNewcomb Почему я должен настраивать, скажем, BufferedReader из InputStream сокета, прежде чем что-то отправлять? Действительно ли он потребляет данные, которые поступают заранее? Как это работает с источниками данных, у которых всегда есть исходные данные? -- Я ожидаю, что любая оболочка Stream будет извлекать, но не потреблять исходные данные? - person class stacker; 10.01.2013
comment
С BufferedXxx вы не можете сказать, когда на самом деле произойдет чтение или запись. Коммуникационный канал — это канал, а в каналах должны работать читатели и писатели. Он не ест данные, вы получаете сломанный канал, если пытаетесь что-то написать, а прочитать нечего, точно так же, как ваше чтение заблокируется, если на другом конце никто не пишет. - person David Newcomb; 11.01.2013
comment
BufferedReader.ready() не имеет смысла ни здесь, ни в большинстве других случаев. Он не сообщает вам, что пришла полная строка, поэтому readLine() по-прежнему может блокироваться до тех пор, пока не появится признак конца строки. - person user207421; 10.05.2017
comment
@EJP, в данном случае это сработало, не так ли! Обычно, если вы читаете строки, вещь на другом конце пишет строки, поэтому система балансирует, поскольку возврат каретки на другом конце приводит к сбросу потока. Когда вы вызываете ready(), весьма вероятно, что вы получите целую строку. При чтении кода BufferedReader.readLine() считывает любые доступные данные неблокирующим образом, пока поток не закончится или не будет достигнута новая строка. Хотя кажется, что readLine блокирует, это не так, он выполняет внутреннюю проверку данных и их чтение. Это тонкая разница, но важная, когда речь идет об использовании ЦП. - person David Newcomb; 10.05.2017
comment
@EJP, BufferedReader специально предназначен для текста из потока ввода символов, поэтому, если вы используете его в двоичном потоке, вы заслуживаете всего, что получаете;) - person David Newcomb; 10.05.2017

BufferdReader.readLine() читает строки, т. е. последовательности символов, заканчивающиеся на \r или \r\n. Я предполагаю, что ваш сервер записывает свой вывод в одну строку. Ваш вывод telnet подтверждает это предположение. Просто используйте PrintWriter.println() на стороне сервера.

person AlexR    schedule 15.06.2011
comment
Или ему придется использовать read(char[] cbuf, int off, int len), если это длинный непрерывный поток. - person toto2; 15.06.2011

эта работа у меня с розеткой без флеша

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);

       }
person Bahgat Mashaly    schedule 06.04.2014