【问题标题】:how to overcome "\n" when using .readlines() methode使用 .readlines() 方法时如何克服“\n”
【发布时间】:2019-10-17 18:15:30
【问题描述】:

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

readline() 方法不断循环,因为我的响应在每个响应的末尾都没有/n/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"

【问题讨论】:

  • 你用什么从套接字读取? BufferedReader?
  • Java SE 中没有“readlines()”方法。如果您真的是指readline(),那么有多种方法具有该名称。如果需要帮助,您需要提供更多背景信息。
  • 由于Socket 没有readLine() 方法,我假设您使用的是BufferedReader 或类似的方法。由于您无法影响该类将使用什么“行”分隔符,因此您要么必须使用另一个阅读器,要么自己动手。除此之外,您的消息的分隔符是什么?接收方如何检测到消息的结束?
  • @Thomas - "一行被认为是由换行符('\n')、回车符('\r')、回车符中的任何一个终止立即通过换行或到达文件结尾 (EOF)。"。唯一的解释是 OP 正在尝试使用 readline() 阅读,而他的“消息”根本不是面向行的。我们需要先看看他的代码,然后才能给他建议。

标签: java network-programming


【解决方案1】:

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

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

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

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

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

byte messageBuffer[] = new byte[500];

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

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

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

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

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"))之类的东西。

【讨论】:

  • 假设我知道收到的响应的长度,我该如何继续
  • @koutheir 我已经编辑了答案以包括阅读固定长度的响应。
【解决方案2】:

我假设你看到这个问题在做类似的事情

String hostName = args[0];
int portNumber = Integer.parseInt(args[1]);

try (
    Socket socket = new Socket(hostName, portNumber);
    BufferedReader in =
        new BufferedReader(
            new InputStreamReader(socket.getInputStream()));
    String line = in.readLine();
)
...

根据BufferedReader#readLine的Javadoc

一行被认为是由换行符('\n')、回车符('\r')、回车符后紧跟换行符或到达结尾处的任何一个终止 -文件外 (EOF)。

所以这个问题是预料之中的。 我建议开始使用行终止字符。如果您不能这样做,您可以使用BufferedReader#read 方法并根据您的规则手动解析收到的内容。

【讨论】:

  • Prokoiev,是的,但是 BufferedReader#read 方法返回一个简单的 int,我不知道他代表什么
  • 这就是正在发生的事情
  • @koutheir 它代表的是流中的下一个char,正如文档中明确指出的那样。
【解决方案3】:

您的问题似乎是您试图使用readline() 来读取非面向行的数据。如果流由一系列消息组成,并且您需要一次读取一条消息......它将无法正常工作。

你是做什么的?

这取决于实际消息结构是什么。例如:

  • 如果每条消息总是正好包含 N 个字符:

    StringBuilder sb = new StringBuilder(N);
    for (int i = 0; i < N; i++) {
        int ch = br.read();
        if (ch == -1) { 
             throw new IOException("truncated message");
        }
        sb.append((char) ch));
    }
    return sb.toString();
    
  • 如果每条消息都以大小开头:

    // read the size
    // read 'size' characters.
    
  • 如果每条消息都以字符 C(或流的结尾)终止

    StringBuilder sb = new StringBuilder();
    int ch;
    while((ch = br.read()) != C) {
       sb.append((char) ch));
    }
    return sb.toString();
    

等等。

【讨论】:

    猜你喜欢
    • 2022-01-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-31
    • 2011-04-29
    相关资源
    最近更新 更多