C# 套接字编程:如何从缓冲区读取指定数量的字节?
TCP是基于流的协议。要将该流转换为我的消息,我将每个消息的大小与消息本身一起发送。在服务器端,我首先读取消息的前两个字节,其大小为。然后我创建一个字节数组,大小等于刚刚读取的大小。然后我将字节读入该数组。但由于某些原因,正在读取的字节数超过了指定的字节数。如何读取与指定的字节数完全相同的字节数 这是我的密码:C# 套接字编程:如何从缓冲区读取指定数量的字节?,c#,sockets,C#,Sockets,TCP是基于流的协议。要将该流转换为我的消息,我将每个消息的大小与消息本身一起发送。在服务器端,我首先读取消息的前两个字节,其大小为。然后我创建一个字节数组,大小等于刚刚读取的大小。然后我将字节读入该数组。但由于某些原因,正在读取的字节数超过了指定的字节数。如何读取与指定的字节数完全相同的字节数 这是我的密码: while (true) { data = null; length = null; size = new byte[2]; handler.Rece
while (true)
{
data = null;
length = null;
size = new byte[2];
handler.Receive(size);
length += Encoding.ASCII.GetString(size, 0, 2);
System.Console.WriteLine("Size: " + Int32.Parse(length));
bufferSize = Int32.Parse(length) + 2;
bytes = new byte[bufferSize];
handler.Receive(bytes);
data += Encoding.ASCII.GetString(bytes, 0, bufferSize);
System.Console.WriteLine("Data: " + data);
}
这是我在Windows PC上运行的服务器,用C#编写。我的客户端运行在用Java编写的android手机上。要接收特定数量的字节,请使用该方法
Socket.Receive(Byte[], Int32, Int32, SocketFlags)
而不是Socket.Receive(字节[])
。参见规格
我猜你想要像这样的东西
int len = Socket.Receive(bytes, 0, bufferSize, SocketFlags.None);
data += Encoding.ASCII.GetString(bytes, 0, len);
System.Console.WriteLine("Data: " + data);
要接收特定数量的字节,请使用
Socket.Receive(Byte[], Int32, Int32, SocketFlags)
而不是Socket.Receive(字节[])
。参见规格
我猜你想要像这样的东西
int len = Socket.Receive(bytes, 0, bufferSize, SocketFlags.None);
data += Encoding.ASCII.GetString(bytes, 0, len);
System.Console.WriteLine("Data: " + data);
现在还不清楚为什么要在传输的大小上增加两个字节——您已经考虑了在上次接收期间存储长度的两个额外字节。所以我要去掉
+2
您还需要尊重问题中已经陈述的事实——TCP是字节序列,而不是消息序列。因此,您永远无法保证对Receive
的调用是检索整个“消息”还是仅检索一条消息的一部分(或者,可能是多条消息的一部分)。因此,您需要确保尊重Receive
的返回值
我们可能会将您的代码重新编写为:
while (true)
{
data = null;
length = null;
size = ReceiveExactly(handler,2);
length = Encoding.ASCII.GetString(size, 0, 2); //Why +=?
bufferSize = Int32.Parse(length); //Why + 2?
System.Console.WriteLine("Size: " + bufferSize);
bytes = ReceiveExactly(handler,bufferSize);
data += Encoding.ASCII.GetString(bytes, 0, bufferSize);
System.Console.WriteLine("Data: " + data);
}
其中,ReceiveExactly
的定义如下:
private byte[] ReceiveExactly(Socket handler, int length)
{
var buffer = new byte[length];
var receivedLength = 0;
while(receivedLength < length)
{
var nextLength = handler.Receive(buffer,receivedLength,length-receivedLength);
if(nextLength==0)
{
//Throw an exception? Something else?
//The socket's never going to receive more data
}
receivedLength += nextLength;
}
return buffer;
}
private byte[]receivejustice(套接字处理程序,int-length)
{
var buffer=新字节[长度];
var receivedLength=0;
while(接收长度<长度)
{
var nextLength=handler.Receive(缓冲区、接收长度、接收长度);
如果(nextLength==0)
{
//抛出一个异常?其他什么?
//套接字永远不会接收更多的数据
}
接收长度+=下一个长度;
}
返回缓冲区;
}
不清楚您为什么要在已传输的大小上添加两个字节-您已经考虑了在上次接收期间存储长度的两个额外字节。所以我要去掉+2
您还需要尊重问题中已经陈述的事实——TCP是字节序列,而不是消息序列。因此,您永远无法保证对Receive
的调用是检索整个“消息”还是仅检索一条消息的一部分(或者,可能是多条消息的一部分)。因此,您需要确保尊重Receive
的返回值
我们可能会将您的代码重新编写为:
while (true)
{
data = null;
length = null;
size = ReceiveExactly(handler,2);
length = Encoding.ASCII.GetString(size, 0, 2); //Why +=?
bufferSize = Int32.Parse(length); //Why + 2?
System.Console.WriteLine("Size: " + bufferSize);
bytes = ReceiveExactly(handler,bufferSize);
data += Encoding.ASCII.GetString(bytes, 0, bufferSize);
System.Console.WriteLine("Data: " + data);
}
其中,ReceiveExactly
的定义如下:
private byte[] ReceiveExactly(Socket handler, int length)
{
var buffer = new byte[length];
var receivedLength = 0;
while(receivedLength < length)
{
var nextLength = handler.Receive(buffer,receivedLength,length-receivedLength);
if(nextLength==0)
{
//Throw an exception? Something else?
//The socket's never going to receive more data
}
receivedLength += nextLength;
}
return buffer;
}
private byte[]receivejustice(套接字处理程序,int-length)
{
var buffer=新字节[长度];
var receivedLength=0;
while(接收长度<长度)
{
var nextLength=handler.Receive(缓冲区、接收长度、接收长度);
如果(nextLength==0)
{
//抛出一个异常?其他什么?
//套接字永远不会接收更多的数据
}
接收长度+=下一个长度;
}
返回缓冲区;
}
a)为什么使用length+=…
而不是length=…
?b) 为什么bufferSize=Int32.Parse(length)+2中的+2
代码>?c) 您希望长度为2个ascii字符。客户端是否以2字节的形式发送它们?或者可能是一个4字节的整数?a)我猜length+=…
与length=…
相同,因为每次length都被设置为null。b) 它用于处理从客户端发送的换行符。length
必须是int
而不是string
。也许你来自python
或javascript
世界。length
是string
。在使用asint
之前,我将其解析为int
。为什么在这里使用字符串?为什么不直接使用BitConverter
将长度转换为字节[]
?以ASCII格式发送长度意味着每条消息最多只能发送99字节。从理论上讲,这两个字节可以对最大为65535字节的消息进行编码。a)为什么要使用length+=…
而不是length=…
?b) 为什么bufferSize=Int32.Parse(length)+2中的+2
代码>?c) 您希望长度为2个ascii字符。客户端是否以2字节的形式发送它们?或者可能是一个4字节的整数?a)我猜length+=…
与length=…
相同,因为每次length都被设置为null。b) 它用于处理从客户端发送的换行符。length
必须是int
而不是string
。也许你来自python
或javascript
世界。length
是string
。在使用asint
之前,我将其解析为int
。为什么在这里使用字符串?为什么不直接使用BitConverter
将长度转换为字节[]
?以ASCII格式发送长度意味着每条消息最多只能发送99字节。从理论上讲,这两个字节可以对最大为65535字节的消息进行编码。前两个字节的大小与原始消息的其余部分相同。我将这些字节转换为字符串,然后将其解析为int。然后我创建一个如此大的缓冲区,以便在下一个接收调用中读取原始消息。前两个字节的大小与原始消息的其余部分相同。我将这些字节转换为字符串,然后将其解析为int。然后我创建一个如此大的缓冲区,以便在下一个接收调用中读取原始消息。