在Java中读取tcp流的最有效方法
我不得不修改一些客户端代码,因为通信协议没有正确定义 我假设来自服务器的tcp消息将以新行终止,所以我使用reader.readLine()读取数据 现在我被告知情况并非如此,而是消息的前4个字符是消息长度,然后我必须阅读消息的其余部分 做这件事最有效、最明智的方法是什么 我的总体想法如下:在Java中读取tcp流的最有效方法,java,tcp,Java,Tcp,我不得不修改一些客户端代码,因为通信协议没有正确定义 我假设来自服务器的tcp消息将以新行终止,所以我使用reader.readLine()读取数据 现在我被告知情况并非如此,而是消息的前4个字符是消息长度,然后我必须阅读消息的其余部分 做这件事最有效、最明智的方法是什么 我的总体想法如下: 创建一个4字符数组 读入前4个字符 确定消息长度 创建消息长度的新数组 读入新数组 下面是一个代码示例(读取器是在别处创建的BufferedReader): 我知道如何做到这一点,但我必须担心字符缓冲区没有
如果你和C或C++开发人员交谈,他们可能会使用“char”作为“字节”的同义词。 编辑:好的,根据评论:
我将创建一个方法,该方法接受一个读取器
和一个计数,并反复调用read()
,直到它读取了正确数量的数据,或者抛出了一个异常。大概是这样的:
public static String readFully(Reader reader, int length) throws IOException
{
char[] buffer = new char[length];
int totalRead = 0;
while (totalRead < length)
{
int read = reader.read(buffer, totalRead, length-totalRead);
if (read == -1)
{
throw new IOException("Insufficient data");
}
totalRead += read;
}
return new String(buffer);
}
您应该检查当他们希望发送少于1000(或超过9999)个字符时会发生什么情况,尽管…Java中的字符用于文本数据。你确定协议真的这样定义了消息的长度吗?更可能是前四个字节代表32位长度
如果你和C或C++开发人员交谈,他们可能会使用“char”作为“字节”的同义词。 编辑:好的,根据评论:
我将创建一个方法,该方法接受一个读取器
和一个计数,并反复调用read()
,直到它读取了正确数量的数据,或者抛出了一个异常。大概是这样的:
public static String readFully(Reader reader, int length) throws IOException
{
char[] buffer = new char[length];
int totalRead = 0;
while (totalRead < length)
{
int read = reader.read(buffer, totalRead, length-totalRead);
if (read == -1)
{
throw new IOException("Insufficient data");
}
totalRead += read;
}
return new String(buffer);
}
您应该检查当他们想发送少于1000(或超过9999)个字符时会发生什么…呃。。。Java中的
char
不是16位的Unicode吗?我认为你做得不对,用字符来表示从网络中输出的字节。您可能应该考虑改用java.nio
包中的
之类的东西
如果您知道单个消息的最大大小,那么就不能阻止您创建单个缓冲区,将四个字节读入缓冲区,将它们解析为int
左右,然后以该大小重新读取,覆盖缓冲区的内容
更新:上述假设协议是二进制的,并且
char
的使用是“C-ism”。如果协议实际上是文本,并且初始的4个字符长度是一个填充整数(在某些情况下,我猜是10?),比如“0047”或“6212”,那么其他方法可能更好,不必从字节到字符。呃。。。Java中的char
不是16位的Unicode吗?我认为你做得不对,用字符来表示从网络中输出的字节。您可能应该考虑改用java.nio
包中的
之类的东西
如果您知道单个消息的最大大小,那么就不能阻止您创建单个缓冲区,将四个字节读入缓冲区,将它们解析为int
左右,然后以该大小重新读取,覆盖缓冲区的内容
更新:上述假设协议是二进制的,并且
char
的使用是“C-ism”。如果协议实际上是文本,并且初始的4个字符长度是一个填充整数(在某些情况下,我猜是10?),比如“0047”或“6212”,那么其他方法可能更好,为了不必从字节到字符。关于问题的一部分,即一旦确定了需要读取一定数量的字符,以下习语在java.io.Readers中很常见:
int lengthToRead = getRequiredReadLength(); // Left as exercise to reader :-)
char[] content = new char[lengthToRead]
int from = 0;
while (lengthToRead > 0)
{
try
{
int nRead = reader.read(context, from, lengthToRead);
if (nRead == -1)
{
// End of stream reached before expected number of characters
// read so handle this appropriately - probably throw an exception
}
lengthToRead -= nRead;
from += nRead;
}
catch (IOException e)
{
// Handle exception
}
}
由于read
调用保证返回一个非零结果(调用阻塞直到某些数据可用,到达流的末尾(返回-1)或引发异常),因此此while循环确保只要流能够提供字符,您就可以读取所需的任意多个字符
一般来说,当一次从读卡器中请求多个字符时,应该知道不能保证实际提供了多个字符,并且应该始终检查返回值以查看发生了什么。否则,您将不可避免地在某个时刻遇到bug,流的某些部分将“消失”。关于问题的一部分,即一旦确定了需要读取一定数量的字符,以下习语在java.io.Readers中很常见:
int lengthToRead = getRequiredReadLength(); // Left as exercise to reader :-)
char[] content = new char[lengthToRead]
int from = 0;
while (lengthToRead > 0)
{
try
{
int nRead = reader.read(context, from, lengthToRead);
if (nRead == -1)
{
// End of stream reached before expected number of characters
// read so handle this appropriately - probably throw an exception
}
lengthToRead -= nRead;
from += nRead;
}
catch (IOException e)
{
// Handle exception
}
}
由于read
调用保证返回一个非零结果(调用阻塞直到某些数据可用,到达流的末尾(返回-1)或引发异常),因此此while循环确保只要流能够提供字符,您就可以读取所需的任意多个字符
一般来说,当一次从读卡器中请求多个字符时,应该知道不能保证实际提供了多个字符,并且应该始终检查返回值以查看发生了什么。否则,您将不可避免地在某个时刻出现错误,流的某些部分将“消失”。协议是基于16位Java“char”还是8位C“char”?它在另一端作为字符串读取,前4个字符是长度。我假设它们是16位Java字符。我会给服务器端工作的人发电子邮件