首页 > 解决方案 > 使用 .readlines() 方法时如何克服“\n”

问题描述

我正在使用一个套接字,并且我收到来自服务器的响应,它是一个字符串

该方法readline()不断循环,因为我的响应没有一个/nor/r在每个响应的末尾。所以我的程序卡在了那条线上。

我如何接收响应,换句话说,如何告诉readline()方法传输结束而没有响应/n/r在响应结束时?我不能使用 read() 方法,因为它返回一个 int。这是接收代码

// Get the return message from the server
InputStream is = socket.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);


// lecture de message

String message = br.readLine();

and this is the response that iam suposed to get "162143045875965485214752310109013112500019900008080807812345612345678912500007412589600000000000000000000000000000000000000000000000000000000000000000000000000000000"

标签: javanetwork-programming

解决方案


TCP 是一种流协议,这意味着只要套接字连接,字节就会无休止地来自套接字。因此,数据不会分成单独的消息。因此,从 TCP 套接字读取与从二进制文件读取非常相似——您不能只“逐行”读取,因为它只是一个有开始和结束的数据块。

如果输入不包含分隔符,例如\n消息之间的(或其他字符或字节序列),则必须有其他方法来确定要读取的字节数。有几种方法可以解决这个问题,具体取决于协议。例如,在 HTTP 中,响应通常具有Content-Length标头,以便读者知道此响应何时结束以及下一个响应何时开始。

如果您正在实现自己的协议,一种简单的方法是在每条消息前面加上int指定的字节数。在这种情况下,读者所要做的就是读取int,从套接字读取适当数量的字节,解析消息,然后读取下一个int......

另一种方法是使用固定大小的消息,并且每次都简单地读取固定数量的字节。第三种方法是使用分隔符,例如\n协议有效负载中未出现的其他字节序列。

如果您知道要读取的字节数,请首先创建一个缓冲区来写入消息。假设我们要准确读取 500 个字节。分配消息缓冲区:

byte messageBuffer[] = new byte[500];

现在我们需要从套接字读取,直到满足两个条件之一:

  • 消息缓冲区中有 500 个字节
  • 或者套接字关闭

read方便的是,每次调用InputStream套接字时,我们都会得到我们已经读取的字节数,或者-1流是否已经结束。因此,我们可以读入我们的消息缓冲区,直到我们用 500 个字节填充它,或者我们-1read()调用中获取。

我们最终得到一个这样的循环:

int bytesToRead = 500;
InputStream in = socket.getInputStream();
byte messageBuffer[] = new byte[bytesToRead];
for (int readOffset = 0, readBytes = 0; (readBytes = in.read(messageBuffer, readOffset, messageBuffer.length - readOffset)) != -1
        && readOffset < bytesToRead;) {
    readOffset += readBytes;
}

或者,如果您愿意,可以这样:

int readBytes = 0;
int readOffset = 0;
while (true) {
    readBytes = in.read(messageBuffer, readOffset, messageBuffer.length - readOffset);
    if (readBytes == -1) {
        break;
    }
    readOffset += readBytes;
}

注意我没有测试过这段代码。

一旦您将足够的字节读入缓冲区,如果您想从中String提取,只需使用new String(messageBuffer)或类似的东西,new String(messageBuffer, Charset.forName("UTF-8"))如果您想指定一个非默认字符集。


推荐阅读