2016-03-04 2 views
1

У меня проблема с программированием сокетов на Java. Существует сервер, написанный на питоне, который я не должен изменять.Чтение всей строки из серверного сокета, который не был закрыт

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
s.connect((TCP_IP, TCP_PORT)) 
s.send('from server\nnewline\0') 
data = s.recv(BUFFER_SIZE) 
s.close() 

Теперь я хочу написать код на Java, который считывает строку с сервера. Что-то вроде этого:

public static String readStr(Socket client) throws IOException { 
     InputStreamReader inStream = new InputStreamReader(
       client.getInputStream()); 
     BufferedReader inBuff = new BufferedReader(inStream); 
     String answer = new String(); 
     String str = inBuff.readLine(); 
     while (str!=null) { 
      answer = answer.concat(str + "\n"); 
      str = inBuff.readLine(); 
     } 
     answer = answer.substring(0, answer.length() - 1); 
     System.out.println("answer:\n "+answer); 
     return answer; 
    } 

Но, кажется, что он блокирует на линии str = inBuff.readLine(); на последней строке сообщения. Я попробовал метод read(), но он тоже был заблокирован.

ответ

0

При разработке протокола по протоколу tcp наилучшим способом является включение какого-либо фрейммера. Это делается в текущем протоколе с использованием байта NUL.

При чтении данных из сокета вы должны сначала разделить его на блоки/кадры на некоторые операции, прежде чем разбирать отдельные блоки.

Грубый способ разделить пакеты на блоки читается до тех пор, пока вы не найдете байт NUL, а затем верните этот блок в виде массива байтов. (Это не самая эффективная реализация)

public byte[] readPacket(InputStream in) throws IOException { 
    ByteArrayOutputStream tempStr = new ByteArrayOutputStream(); 
    int read; 
    read=in.read(); 
    while(read > 0){ 
     tempStr.write(read); 
     read=in.read(); 
     } 
    if(read == -1) 
     throw new EOFException(); 
    return tempStr.toByteArray(); 
} 

Потому что теперь у вас есть соответствующие кадры для ваших данных, вы можете легко читать данные:

byte[] frame = readPacket(in); 
String[] lines = new String(frame, StandardCharsets.UTF8).split("\n"); 
// Do something with the lines 
0

Возможно, это связано с тем, что последняя строка, отправленная сервером, не заканчивается, и метод readLine() возвращается только тогда, когда он достигает конца строки. Поскольку вы меняете код сервера. Я рекомендую использовать другой метод для чтения из потока. Вы также можете использовать класс InputStreamReader.

+0

Я использовал класс nputStreamReader. какой другой метод вы рекомендуете? @ user6015630 – user63835

+0

Вы можете использовать read (char [] cbuf, int off, int len) в BufferedReader – user6015630

0

Помимо уже упоминалось противоречивое сообщение/line end - один раз с \n, второй с \0, на сервере нет обнаружения конца сообщения. Таким образом, сервер будет зацикливаться до тех пор, пока сокет не будет закрыт (или закрыт для записи) на стороне клиента. И поскольку у вас есть эта линия перед закрытием гнезда:

data = s.recv(BUFFER_SIZE) 

Другими словами, клиент ждет ответа от сервера. Но сервер застрял навсегда, прочитав сообщение от клиента в цикле.

Так что вам нужно либо закрыть сокет до этого recv, либо отправить сообщение (например, пустую строку) и обнаружить на сервере и в конечном итоге выйти из цикла.