900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > C#实战027:socket实现大文件传输

C#实战027:socket实现大文件传输

时间:2020-02-29 05:33:16

相关推荐

C#实战027:socket实现大文件传输

前面写了一个单文件传输的,后来发现当传送的文件大于设置的缓存空间时,文件就会出现丢包的现象,导致文件无法使用,所以为了适应大文件的传输,这里我将代码进行了下修改,实现大文件传输。

不过socket实现大文件传输有个缺点,由于传输过程是通过字节缓存发送,接受也是读写字节,导致整个传输过程效率不高,我尝试了一个169MB的视频文件传输,虽然传完了,但是耗时将近1小时。

因为计算机缓存有限,所以不可能开启太大的缓存来缓存数据的,所以当我们要发送文件较大的文件时我们就要进行分段处理,分段读取,分段发送保存。大家可以看到我们的两个窗口都是同步的,一遍在读取中,一遍就在写入中。如此反复的使用同一块缓存进行数据传递。

首先我们先进行循环读取文件信息,这里有个重要的就是做好标记,之前写C#实战026:socket实现单文件传输时就有提到,通过在第一个字节做标记来区分我们传送的信息是什么信息,这个规则自己定义,只要客户端和服务端同步即可

这里我们把0定义成信息发送,1定义成文件发送,2定义成文件头信息发送

首先我们先需要把我们要发送的文件信息抛给服务器,这里主要需要文件的文件名和文件大小,这里我们只要在用文件流读取文件的时候将这些数据提取出来即可:

//1. 第一步:发送一个文件,表示文件名和长度,让客户端知道文件大小string fileName = Path.GetFileName(filePath);//提取文件名Console.WriteLine("发送的文件名是:" + fileName);//查看获取文件名是否正确long fileLength = fsRead.Length;//获取文件长度Console.WriteLine("发送的文件长度为:"+fileLength);//查看文件长度是否正确string totalMsg = string.Format("{0}-{1}", fileName, fileLength);//将文件名和文件长度存入一条数据中byte[] buffer = Encoding.UTF8.GetBytes(totalMsg); //将字符串转换成字节数组byte[] newBuffer = new byte[buffer.Length + 1];//新建字节数组,增加一个字节空间newBuffer[0] = 2;//将第一个字节标记成2,代表为文件头信息Buffer.BlockCopy(buffer, 0, newBuffer, 1, buffer.Length);//偏移复制字节数组socketClient.Send(newBuffer);//发送文件文件名和长度发过去

既然是循环写入,我们就要记录当前文件的数据大小和已读取的数据信息,这样循环才有终点,定义一个5M缓存区。

byte[] Filebuffer = new byte[1024 * 1024 * 5];//定义5MB的缓存空间(1024字节(b)=1千字节(kb))int readLength = 0; //定义读取的长度bool firstRead = true;//定义首次读取的状态long sentFileLength = 0;//定义发送的长度

接下里解释对文件进行分包发送了,这里唯一要注意的就是第一次发送的时候要为文件价格标记,也就是第一个数据包前加标记,这样服务端才好去识别该数据是什么数据,然后做对应的处理。

while (readLength> 0 && sentFileLength < fileLength){sentFileLength += readLength;//计算已读取文件大小//第一次发送的字节流上加个前缀1if (firstRead){byte[] firstBuffer = new byte[readLength + 1];//这个操作同样也是用来标记文件的firstBuffer[0] = 1;//将第一个字节标记成1,代表为文件Buffer.BlockCopy(buffer, 0, firstBuffer, 1, readLength);//偏移复制字节数组socketClient.Send(firstBuffer, 0, readLength + 1, SocketFlags.None);Console.WriteLine("第一次读取数据成功,在前面添加一个标记");//发送文件数据包firstRead = false;//切换状态,避免再次进入continue;}socketClient.Send(buffer, 0, readLength, SocketFlags.None);//继续发送剩下的数据包Console.WriteLine("{0}: 已发送数据:{1}/{2}", socketClient.RemoteEndPoint, sentFileLength, fileLength);//查看发送进度}fsRead.Close();//关闭文件流Console.WriteLine("发送完成");//提示发送完毕

接下来在可以在服务端来接受数据了,同样在处理数据的时候要把第一次数据分开,因为第一组数据中添加一个标记符,所以我们在写数据的时候要截取标记后面的数据。

if (buffer[0] == 1)//1对应文件信息{SaveFileDialog sfDialog = new SaveFileDialog();//创建SaveFileDialog实例string spath = @"C:\Users\admin\Desktop";//制定存储路径string savePath = bine(spath, recStr);//获取存储路径及文件名int rec = 0;//定义获取接受数据的长度初始值long recFileLength = 0;bool firstWrite = true;using (FileStream fs = new FileStream(savePath, FileMode.Create, FileAccess.Write)){while (recFileLength < fileLength)//判断读取文件长度是否小于总文件长度{if (firstWrite)//第一次写入时{fs.Write(buffer, 1, firstRcv - 1);//截取字节数据写入文件中fs.Flush();//清空缓存信息recFileLength += firstRcv - 1;//记录已获取的数据大小firstWrite = false;//切换状态}else{rec = socketServer.Receive(buffer);//继续接收文件并存入缓存fs.Write(buffer, 0, rec);//将缓存中的数据写入文件中fs.Flush();//清空缓存信息recFileLength += rec;//继续记录已获取的数据大小}Console.WriteLine("{0}: 已接收数据:{1}/{2}", socketServer.RemoteEndPoint, recFileLength, fileLength);//查看已接受数据进度}fs.Close();}Console.WriteLine("保存成功!!!!");}

我把源码传在CSDN了,有兴趣的可以下载:Socket传输大文件(发送与接收源码)

首发百度经验 : C#实战027:socket实现大文件传输

欢迎关注本人的公众号:编程手札,文章也会在公众号更新

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。