java - 使用 .readlines() 方法时如何克服“\n”
问题描述
我正在使用一个套接字,并且我收到来自服务器的响应,它是一个字符串。
该方法readline()
不断循环,因为我的响应没有一个/n
or/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"
解决方案
TCP 是一种流协议,这意味着只要套接字连接,字节就会无休止地来自套接字。因此,数据不会分成单独的消息。因此,从 TCP 套接字读取与从二进制文件读取非常相似——您不能只“逐行”读取,因为它只是一个有开始和结束的数据块。
如果输入不包含分隔符,例如\n
消息之间的(或其他字符或字节序列),则必须有其他方法来确定要读取的字节数。有几种方法可以解决这个问题,具体取决于协议。例如,在 HTTP 中,响应通常具有Content-Length
标头,以便读者知道此响应何时结束以及下一个响应何时开始。
如果您正在实现自己的协议,一种简单的方法是在每条消息前面加上int
指定的字节数。在这种情况下,读者所要做的就是读取int
,从套接字读取适当数量的字节,解析消息,然后读取下一个int
......
另一种方法是使用固定大小的消息,并且每次都简单地读取固定数量的字节。第三种方法是使用分隔符,例如\n
协议有效负载中未出现的其他字节序列。
如果您知道要读取的字节数,请首先创建一个缓冲区来写入消息。假设我们要准确读取 500 个字节。分配消息缓冲区:
byte messageBuffer[] = new byte[500];
现在我们需要从套接字读取,直到满足两个条件之一:
- 消息缓冲区中有 500 个字节
- 或者套接字关闭
read
方便的是,每次调用InputStream
套接字时,我们都会得到我们已经读取的字节数,或者-1
流是否已经结束。因此,我们可以读入我们的消息缓冲区,直到我们用 500 个字节填充它,或者我们-1
从read()
调用中获取。
我们最终得到一个这样的循环:
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"))
如果您想指定一个非默认字符集。
推荐阅读
- angular - 如何将 fromEvent (Angular rxjs) 与多个元素一起使用?
- snowflake-cloud-data-platform - 将 .bak(SQL Server 备份文件)加载到 Snowflake
- angular - Angular - 在 Jest/Spectator 单元测试中找不到组件工厂
- java - HTTP 身份验证 - Java Http 客户端缺少通过 curl 存在的标头
- apache - Apache 服务器未启动
- node.js - 通过docker运行应用程序时出现角度构建错误
- database - java.sql.SQLException:ORA-01652:无法在表空间 TEMP 中将临时段扩展 128(即使在扩展之后)
- r - 修改 R 中“get()”引用的对象
- css - 如何使 sass 文件全局化,而不是在每个文件中导入它并膨胀包大小?
- amazon-web-services - 带有 ALB 的 ECS 背后的 Gitlab