我正在使用套接字,并且收到来自服务器的响应,该响应是 string 。
方法 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();
这是iam要求获得的响应“ 162143045875965485214752310109013112500019900008080807812345612345678912500007412589600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000”
答案 0 :(得分:1)
TCP是一种流协议,这意味着只要连接了套接字,字节就无休止地来自套接字。因此,数据不会分为单独的消息。因此,从TCP套接字读取数据与从二进制文件读取数据非常相似-您不能只逐行读取数据,因为它们都是带有开始和结束位置的数据块。
如果输入在消息之间不包含定界符,例如\n
(或某些其他字符或字节序列),则必须采用其他方法确定要读取多少个字节。取决于协议,有几种解决方法。例如,在HTTP中,响应通常具有Content-Length
头,以便读者知道此响应何时结束以及下一个响应开始。
如果要实现自己的协议,一种简单的方法是为每个消息添加一个int
前缀,指定其包含的字节数。在这种情况下,读者所要做的就是读取int
,从套接字读取适当数量的字节,解析消息,然后读取下一个int
...
另一种方法是使用固定大小的消息,并且每次仅读取固定数量的字节。第三种方法是使用定界符,例如\n
或其他未出现在协议有效负载中的字节序列。
如果知道要读取的字节数,请首先创建一个缓冲区以将消息写入其中。假设我们要精确读取500个字节。分配消息缓冲区:
byte messageBuffer[] = new byte[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"))
之类的字元即可非默认字符集。
答案 1 :(得分:0)
我认为您在执行类似操作时遇到此问题
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();
)
...
根据Javadoc for BufferedReader#readLine
行被认为由换行符('\ n'),回车符('\ r'),回车符后紧跟换行符或到达末尾中的任何一条来终止。文件(EOF)。
因此预期会出现此问题。
我建议开始使用行终止符。如果无法执行此操作,则可以使用BufferedReader#read
方法并根据规则手动解析收到的内容。
答案 2 :(得分:0)
您的问题似乎是您正在尝试使用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();
以此类推。