我要做的是接收从客户端发送的大量字节(大约5MB数据)
以下是接收数据(byte [])的代码
byte[] receivedBytesRaw = new byte[4000];
//first, initialize network stream
NetworkStream stream = client.GetStream();
//The bytesNeeded is the size of bytes which is a protocol sent by the client side indicating the size of byte which will be sent
int bytesNeeded = 4000;
int bytesReceived = 0;
do
{
int bytesRead = stream.Read(receivedBytesRaw, bytesReceived, bytesNeeded - bytesReceived);
networkValidation.addBytesToList(receivedBytesRaw, ref receivedBytes);
bytesReceived += bytesRead;
} while (bytesReceived < bytesNeeded);
但现在我遇到了问题:
每次数据到达时,do while循环第一次循环,返回值(i)为26,然后再次循环,这次,当它转到" i = stream.Read(receivedBytesRaw, 0, receivedBytesRaw.Length);"
时,程序似乎在等待对于客户端发送数据并且没有响应,当我检查“receivedBytesRaw”时,数据不完整,只收到前13个字节,字节数组中的剩余空间保持为null,而stream.DataAvailable是假
为什么服务器端收到不完整的数据? 注意:当我尝试发送小数据(字符串)时,没关系
=============================================== ======================
被修改
以下是发送数据的客户端代码:
private int sendData(byte[] dataSend, string IP, int portNumber)
{
TcpClient clientSide = new TcpClient();
int result = -1;
try
{
clientSide.Connect(IP, portNumber);
}
catch (Exception ex)
{
return 2;
}
NetworkStream netStream = clientSide.GetStream();
if (netStream.CanWrite)
{
byte[] replyMsg = new byte[1024];
netStream.Write(dataSend, 0, dataSend.Length);
netStream.Flush();
result = 0;
}
else
{
result = 1;
}
return result;
}
答案 0 :(得分:1)
因为它是一个流,可以部分接收。你确定你总是收到大小为2048字节的软件包吗?
int i = 0;
int bytesNeeded = 200;
int bytesReceived = 0;
do
{
//read byte from client
int bytesRead = stream.Read(receivedBytesRaw, bytesReceived, bytesNeeded-bytesReceived);
bytesReceived += bytesRead;
// merge byte array to another byte array
} while (bytesReceived < bytesNeeded);
我认为你需要一个帧协议,尝试创建一个类似的协议,写下随后数据的大小。
示例:(伪)
void SendData(byte[] data)
{
// get the 4 bytes of a int value.
byte[] dataLength = BitConverter.GetBytes(data.Lenght);
// write the length to the stream.
stream.Write(dataLength, 0, dataLength.Length);
// write the data bytes.
stream.Write(data, 0, data.Length);
}
void Receive()
{
// read 4 bytes from the stream.
ReadBuffer(buffer, 4);
// convert those 4 bytes to an int.
int dataLength = BitConverter.ToInt32(buffer, 0);
// read bytes with dataLength as count.
ReadBuffer(buffer, dataLength);
}
// read until the right amount of bytes are read.
void ReadBuffer(byte[] buffer, int length)
{
int i = 0;
int bytesNeeded = length;
int bytesReceived = 0;
do
{
//read byte from client
int bytesRead = stream.Read(buffer, bytesReceived, bytesNeeded-bytesReceived);
bytesReceived += bytesRead;
// merge byte array to another byte array
} while (bytesReceived < bytesNeeded); // <- you should do this async.
}
这只是一个例子..
答案 1 :(得分:1)
您可以尝试的另一种解决方案是使用异步读取。 我创建了一个读取所有字节的类。如果读取完整文件不是问题,可以试试这个:
示例:
此示例显示您可以阅读简单的协议。 ReadPacket
处理长度+数据消息。因此发送方将首先发送一个包含后续数据长度的int值。
StartReading方法读取文件名和filedata。它将存储最多10mb的最大文件大小。但这最初并不是为接收文件而设计的。
const int MaxFileSize = 10 * 1024 * 1024;
private void Example()
{
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Connect("localhost", 12345);
StartReading(socket);
}
private void StartReading(Socket socket)
{
ReadPacket(socket, (filenameData) =>
{
if (filenameData.Count == 0)
{
// disconnected
return;
}
// parse the filename
string filename = Encoding.UTF8.GetString(filenameData.Array, filenameData.Offset, filenameData.Count);
Trace.WriteLine("Receiving file :" + filename);
ReadPacket(socket, (fileData) =>
{
if (fileData.Count == 0)
{
// disconnected
return;
}
Trace.WriteLine("Writing file :" + filename);
// write to the file
using (FileStream stream = new FileStream(filename, FileMode.Create, FileAccess.Write))
stream.Write(fileData.Array, fileData.Offset, fileData.Count);
// start waiting for another packet.
StartReading(socket);
});
});
}
private void ReadPacket(Socket socket, Action<ArraySegment<byte>> endRead)
{
// read header. (length of data) (4 bytes)
EasySocketReader.ReadFromSocket(socket, 4, (headerBufferSegment) =>
{
// if the ReadFromSocket returns 0, the socket is closed.
if (headerBufferSegment.Count == 0)
{
// disconnected;
endRead(new ArraySegment<byte>());
return;
}
// Get the length of the data that follows
int length = BitConverter.ToInt32(headerBufferSegment.Array, headerBufferSegment.Offset);
// Check the length
if (length > MaxFileSize)
{
// disconnect
endRead(new ArraySegment<byte>());
return;
}
// Read bytes specified in length.
EasySocketReader.ReadFromSocket(socket, length, (dataBufferSegment) =>
{
// if the ReadFromSocket returns 0, the socket is closed.
if (dataBufferSegment.Count == 0)
{
endRead(new ArraySegment<byte>());
return;
}
endRead(dataBufferSegment);
});
});
}
EasySocketReader
课程可以在我的博客上找到:http://csharp.vanlangen.biz/network-programming/async-sockets/asyncsocketreader/
可在此处找到原始的EasyPacketReader:http://csharp.vanlangen.biz/network-programming/async-sockets/easypacketreader/
对于发送部分,您可以使用以下内容:
private void SendFile(Socket socket, string filename)
{
byte[] filenameData = Encoding.UTF8.GetBytes(filename);
socket.Send(BitConverter.GetBytes(filenameData.Length));
socket.Send(filenameData);
int fileSize;
byte[] fileData;
using (FileStream stream = new FileStream(filename, FileMode.Open, FileAccess.Read))
{
fileSize = (int)stream.Length;
if (fileSize > MaxFileSize)
throw new ArgumentOutOfRangeException("File too big");
fileData = new byte[fileSize];
stream.Read(fileData, 0, fileSize);
}
socket.Send(BitConverter.GetBytes(fileSize));
socket.Send(fileData);
}