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

2025-11-21 07:01:25

1、socket实现大文件传输有个缺点,由于传输过程是通过字节缓存发送,接受也是读写字节,导致整个传输过程效率不高,我尝试了一个169MB的视频文件传输,虽然传完了,但是耗时将近1小时,所以socket在文件传输上还是比较低效的,不建议使用socket进行大文件传送。

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

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

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

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

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

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

//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);//发送文件文件名和长度发过去

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

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

 byte[] Filebuffer = new byte[1024 * 1024 * 5];//定义5MB的缓存空间(1024字节(b)=1千字节(kb))

 int readLength = 0;  //定义读取的长度

 bool firstRead = true;//定义首次读取的状态

 long sentFileLength = 0;//定义发送的长度

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

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

7、 while (readLength> 0 && sentFileLength < fileLength)

                {

                    sentFileLength += readLength;//计算已读取文件大小

                    //第一次发送的字节流上加个前缀1

                    if (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();//关闭文件流

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

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

9、 if (buffer[0] == 1)//1对应文件信息

                        {

                            SaveFileDialog sfDialog = new SaveFileDialog();//创建SaveFileDialog实例

                            string spath = @"C:\Users\admin\Desktop";//制定存储路径

                            string savePath = Path.Combine(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("保存成功!!!!");

                        }

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

声明:本网站引用、摘录或转载内容仅供网站访问者交流或参考,不代表本站立场,如存在版权或非法内容,请联系站长删除,联系邮箱:site.kefu@qq.com。
猜你喜欢