Android套接字持续读取直到特定字符串序列

3
我想从Socket读取数据,直到遇到特定的字符串序列,如<END>。问题是服务器有时会将数据分成块返回,这是因为文本(JSON)太长而无法一次性发送。我希望设计一种逻辑,使Socket不断附加一个字符串构建器,直到流结束时出现<END>,然后继续添加下一个消息。
InputStreamReader inr = new InputStreamReader(socket.getInputStream());

BufferedReader br = new BufferedReader(inr);

byte[] resultBuff = new byte[0];
byte[] buff = new byte[99999];
int k;

StringBuilder sb = new StringBuilder();

while ((k = in .read(buff, 0, buff.length)) > -1) {
 byte[] tbuff = new byte[resultBuff.length + k]; // temp buffer size = bytes already read + bytes last read
 System.arraycopy(resultBuff, 0, tbuff, 0, resultBuff.length); // copy previous bytes
 System.arraycopy(buff, 0, tbuff, resultBuff.length, k); // copy current lot
 resultBuff = tbuff; // call the temp buffer as your result buff
 System.out.println(resultBuff.length + " bytes read.");
 String s = new String(resultBuff);


 sb.append(s);

 if (s.endsWith(DELIMITER)) {

  String response = sb.toString().replace(DELIMITER, "").replace("\n", "").replace("\r", "");

  System.out.println(response);

  if (listener != null) {
   listener.onMessageReceived(params[0], response);

  } else {
   Log.e(TAG, "Response :: listener.onMessageReceived null ");
  }
  resultBuff = new byte[0];
  sb = new StringBuilder();
 } else {
  sb.append(s);

 }


}

这里的目标是让while循环持续运行,以便套接字可以在流中读取任何东西时保持读取状态。
1个回答

0
你可以像这样做。
String str = "";
byte[] b = new byte[1024];
for(int r = 0; (r = is.read(b))!=-1;){
    str += new String(b,0,r);
    if(str.contains(DELIMITER)){
        String message = str.substring(0,str.indexOf(DELIMITER));
        str = str.substring(str.indexOf(DELIMITER)+DELIMITER.length());
        //process message.
    }
}
if(!str.isEmpty()){
    //the JSON object was sent in a single chunk, porcess it
}

这段代码的作用是将从InputStream读取到的所有数据存储在str String中,当str包含DELIMITER时,它将从str中提取消息以便进行处理。如果缓冲区包含多个消息,则此操作将失败。您可以使用String[] messages = str.split(DELIMITER)来处理该问题。

更好的解决方案是使用Scanner,以下是一个示例:

Scanner sc = new Scanner(in);
sc.useDelimiter(DELIMITER);
while(sc.hasNext()){
    String message = sc.next();
    // process message.
}

两种解决方案都完全不起作用,特别是与扫描仪相关的部分。 - H.T
@H.T useDelimiter(...)接受一个正则表达式,如果你的DELIMITER包含特殊的正则表达式字符,你需要对它们进行转义。尝试使用sc.useDelimiter(Pattern.quote(DELIMITER)) - Titus
我的分隔符是字符串值<END>,不幸的是返回的消息为空。 - H.T
使用 useDelimiter("\s*<END>\s*") 解决了问题,但是长消息并没有被完全读取。这并没有解决问题。 - H.T
@H.T 如果服务器一次性发送消息并且发送后没有关闭连接,那么Scanner方法将会失败。我已经编辑了第一个示例以处理消息在单个块中发送的情况。 - Titus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接