我设法使用NetworkStream
和套接字通过TCP发送二进制数据。
我唯一的问题是,当我发送较大的文件,如几百KB图像时,它们无法正确传输,图像的一半丢失。在服务器端我Socket.Send
传输数据。在客户端,我使用Socket.BeginReceive
一个1024
大小的缓冲区写入MemoryStream
,稍后我使用new Bitmap(Stream)
将MemoryStream
转换为图像可以在PictureBox
中显示。
我应该使用什么方法来避免数据丢失?
编辑:已发布的代码
listener = new TcpListener(myAddress, 86);
listener.Start();
TcpClient client = listener.AcceptTcpClient();
ns = client.GetStream();
byte[] buffer = new byte[1024];
while (fileTransfer)
{
ms = new MemoryStream();
do
{
int length = ns.Read(buffer, 0, buffer.Length);
ms.Write(buffer, 0, length);
// with this line added the data loss apparently disappears
System.Threading.Thread.Sleep(1);
} while (ns.DataAvailable);
UpdateData();
ms.Dispose();
System.Threading.Thread.Sleep(10);
}
ns.Dispose();
client.Close();
listener.Stop();
编辑:即使使用sleep方法,数据仍然有时会损坏。
答案 0 :(得分:1)
我建议你改变这个循环:
do
{
int length = ns.Read(buffer, 0, buffer.Length);
ms.Write(buffer, 0, length);
// with this line added the data loss apparently disappears
System.Threading.Thread.Sleep(1);
} while (ns.DataAvailable);
成:
do
{
int length = ns.Read(buffer, 0, buffer.Length);
ms.Write(buffer, 0, length);
} while (length > 0);
即,读取直到数据结束(即ns.Read
不返回数据)。 Read
阻塞,直到有一些数据或套接字关闭(或抛出一些异常)。我删除了无用的睡眠。
答案 1 :(得分:0)
最有可能(猜测)你没有正确地从客户端的流中读取。
您需要读取EndReceive()方法的结果以查看实际读取的数据量 - 它可能不是缓冲区的大小(在这种情况下为1024字节)
所以:
a)当调用BeginReceive时,你是否通过了回调?
b)如果是,是否正在读取结果并将适当数量的字节写入内存流?
即:
public void ReceiveCallback( IAsyncResult result)
{
var buffer = (byte[])result.AsyncState;
int bytesRead = socket.EndReceive();
memoryStream.Write (buffer, 0, bytesRead);//bytesRead may not be 1024!
}
答案 2 :(得分:0)
好的我通过在发送实际数据之前发送数据大小来解决它。它不起作用的原因我错误地认为转移是立竿见影的。这就是为什么接收器循环中的Sleep()方法有所不同但却没有解决问题的原因。我理解在这种情况下我不能依赖DataAvailable。即使检查接收数据的长度也不会起作用,因为客户端可能在循环结束后发送数据。检查文件大小(如果数据大于接收方的缓冲区)是我找到的最好的解决方案。