SOCKET 传输大文件应该怎么做?

筑台封神 2014-05-29 04:04:31
小弟第一次发帖,请大牛们多多捧场!
现在公司要我做一个C语言的SOCKET通信(TCP),要求是千兆网最低50M每秒的传输速度!(S-send ;C -recv)
小弟试着写了一下,遇到了以下问题:
1,不建立C/S端的缓冲,直接传输,只能传输小文件,遇到大文件就会出错
出现1的问题,是因为发端太快,造成丢包
2,基于1,我想到虽然是流传输,是不是也可以像UDP那样自己自己定义一个校验机制,就是将一个文件切块,然后每一个块加上长度,这样,在传输到C端之后,必须得到C端的确认(也就是C recv的和块中定义的长度一致),才发下一个块。
2的方法,是能解决传输大文件的问题,但是速度慢,达不到要求!
3,基于2的问题,我想到,是不是可以在S端自己定义一个缓冲区:
定义缓冲用了两种方法,一是维护一个链表,动态的定义。二是直接划分出一块内存,静态的缓冲!
目前正在用3的思路在写代码。
想问问各位大牛们,有什么好的建议!!

欢迎大牛们们发言!
小弟在此谢过!
...全文
1105 21 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
21 条回复
切换为时间正序
请发表友善的回复…
发表回复
筑台封神 2014-06-11
  • 打赏
  • 举报
回复
谢谢各位大牛的回答,因为最近有事,所以结贴晚了,小弟拜谢! 另外:代码已经实现了,速度也能达到70+!
赵4老师 2014-05-30
  • 打赏
  • 举报
回复
在文件大小相同的前提下: 读刚读过的文件比头次读没读过的文件快 读转速快的硬盘上的文件比读转速慢的硬盘上的文件快 读没有磁盘碎片的文件比读有磁盘碎片的文件快 读文件不处理比边读边处理快 单线程从头到尾一次读文件比多线程分别读文件各部分快(非固态硬盘上) 读固态硬盘上的文件比读普通硬盘上的文件快
mujiok2003 2014-05-30
  • 打赏
  • 举报
回复
引用 20 楼 mujiok2003 的回复:
[quote=引用 17 楼 u013093541 的回复:]
[quote=引用 13 楼 mujiok2003 的回复:]
个人觉得单线程non-blocking IO+ synchronous I/O multiplexing(select/poll/epoll...) 更好。


牛哥,能说仔细下么?
[/quote]

其实没有必要弄搞那么复杂,直接用send/recv就好了, 只要网络足够通畅, 轻松达到。 我在我的笔记本(10Gbps的网卡)上轻松上90MB/s。 [/quote]

上图:
mujiok2003 2014-05-30
  • 打赏
  • 举报
回复
引用 17 楼 u013093541 的回复:
[quote=引用 13 楼 mujiok2003 的回复:] 个人觉得单线程non-blocking IO+ synchronous I/O multiplexing(select/poll/epoll...) 更好。
牛哥,能说仔细下么? [/quote] 其实没有必要弄搞那么复杂,直接用send/recv就好了, 只要网络足够通畅, 轻松达到。 我在我的笔记本(10Gbps的网卡)上轻松上90MB/s。
mujiok2003 2014-05-30
  • 打赏
  • 举报
回复
个人觉得单线程non-blocking IO+ synchronous I/O multiplexing(select/poll/epoll...) 更好。
mujiok2003 2014-05-30
  • 打赏
  • 举报
回复
引用 11 楼 u013093541 的回复:
昨天有去做测试,发现,并不是IO的问题造成整体的传输慢!还会代码存在问题 我按照自己3的思路去完成代码,也就是在Server端,我分了两个线程,一个线程用于读取文件,并将读到的buf加入到一个动态链表尾部,另一个线程从此链表头取数据,进行send操作,并且对send的返回值进行校验,如果send的返回值和预期的发送字节数不同,则采用断点重传的方式,继续传输。在Client端口,也是用类似的服务端的机制,维护一个链表,进行读取。 需要说明的是:我维护的这个链表是由深度的,并通过深度来调节两个线程对链表的操作。
这个思路是可行的的, 注意两个问题: 1. 防止文件IO过快, 导致你的队列(链表)迅速膨胀。 2. 队列(或链表)要有同步机制, 尽量减小临界区。
筑台封神 2014-05-30
  • 打赏
  • 举报
回复
昨天有去做测试,发现,并不是IO的问题造成整体的传输慢!还会代码存在问题 我按照自己3的思路去完成代码,也就是在Server端,我分了两个线程,一个线程用于读取文件,并将读到的buf加入到一个动态链表尾部,另一个线程从此链表头取数据,进行send操作,并且对send的返回值进行校验,如果send的返回值和预期的发送字节数不同,则采用断点重传的方式,继续传输。在Client端口,也是用类似的服务端的机制,维护一个链表,进行读取。 需要说明的是:我维护的这个链表是由深度的,并通过深度来调节两个线程对链表的操作。
xiaoxiaokun888 2014-05-30
  • 打赏
  • 举报
回复
每秒50M能达到预期效果吗? 有结果回复下
赵4老师 2014-05-30
  • 打赏
  • 举报
回复
引用 16 楼 u013093541 的回复:
[quote=引用 14 楼 zhao4zhong1 的回复:] 在文件大小相同的前提下: 读刚读过的文件比头次读没读过的文件快 读转速快的硬盘上的文件比读转速慢的硬盘上的文件快 读没有磁盘碎片的文件比读有磁盘碎片的文件快 读文件不处理比边读边处理快 单线程从头到尾一次读文件比多线程分别读文件各部分快(非固态硬盘上) 读固态硬盘上的文件比读普通硬盘上的文件快
赵老师,您说的这句“ 单线程从头到尾一次读文件比多线程分别读文件各部分快(非固态硬盘上)”只是针对的读取文件是么?那在我传输的过程中,采用多线程应该是比单线程传输要快一些吧? 谢谢指教![/quote] 是的。
筑台封神 2014-05-30
  • 打赏
  • 举报
回复
引用 13 楼 mujiok2003 的回复:
个人觉得单线程non-blocking IO+ synchronous I/O multiplexing(select/poll/epoll...) 更好。
牛哥,能说仔细下么?
筑台封神 2014-05-30
  • 打赏
  • 举报
回复
引用 14 楼 zhao4zhong1 的回复:
在文件大小相同的前提下: 读刚读过的文件比头次读没读过的文件快 读转速快的硬盘上的文件比读转速慢的硬盘上的文件快 读没有磁盘碎片的文件比读有磁盘碎片的文件快 读文件不处理比边读边处理快 单线程从头到尾一次读文件比多线程分别读文件各部分快(非固态硬盘上) 读固态硬盘上的文件比读普通硬盘上的文件快
赵老师,您说的这句“ 单线程从头到尾一次读文件比多线程分别读文件各部分快(非固态硬盘上)”只是针对的读取文件是么?那在我传输的过程中,采用多线程应该是比单线程传输要快一些吧? 谢谢指教!
筑台封神 2014-05-30
  • 打赏
  • 举报
回复
引用 12 楼 mujiok2003 的回复:
[quote=引用 11 楼 u013093541 的回复:] 昨天有去做测试,发现,并不是IO的问题造成整体的传输慢!还会代码存在问题 我按照自己3的思路去完成代码,也就是在Server端,我分了两个线程,一个线程用于读取文件,并将读到的buf加入到一个动态链表尾部,另一个线程从此链表头取数据,进行send操作,并且对send的返回值进行校验,如果send的返回值和预期的发送字节数不同,则采用断点重传的方式,继续传输。在Client端口,也是用类似的服务端的机制,维护一个链表,进行读取。 需要说明的是:我维护的这个链表是由深度的,并通过深度来调节两个线程对链表的操作。
这个思路是可行的的, 注意两个问题: 1. 防止文件IO过快, 导致你的队列(链表)迅速膨胀。 2. 队列(或链表)要有同步机制, 尽量减小临界区。 [/quote] 小弟想请问一下,我现在维护一个链表,确实会使得链表的长度在某一个时刻徒增,那么应该如何设置链表的深度(文件200M)同时,发送的块大小是要一个一个的试?还是怎样才能或得更好的传输速度? 第二个问题,您说的同步机制,我理解,但是说减小临界区是什么意思?是说对临界数据的选择尽量使得其数据量小么? 谢谢!
yy21yeyu 2014-05-29
  • 打赏
  • 举报
回复
引用 4 楼 zhao4zhong1 的回复:
不知道有多少前人掉在TCP Socket send(人多)send(病少)send(财富) recv(人多病)recv(少财富) 陷阱里面啊! http://bbs.csdn.net/topics/380167545
好熟悉的回复,我以前发帖子你也是这样的回复
mujiok2003 2014-05-29
  • 打赏
  • 举报
回复
引用 1 楼 zilaishuichina 的回复:
文件切块,是没有错的。发送端接受端开缓存,也是没有错的 至于lz说的速度慢,可能不是慢在网络IO上: 1:可能是慢在磁盘IO上,也就是你文件内容可能是一边读一边发的,lz可以尝试把文件内容全部读入内存,然后直接对内存中的文件数据分块发送。或者lz可以先做下测试,把你读取文件的代码先去掉,直接malloc分配50M,随便填点数据,然后发送这块内存。如果不慢了,证明是读文件的问题。如果还慢,只能说是你网络代码效率的问题了,比如可以选择换用IOCP模型在做尝试 2:可能是慢在频繁的申请释放内存上,lz可以考虑使用内存池,给你提供的这个内存池你可以看最后的测试效果,效率相差2个数量级
文件IO速度一般比socket IO快,试试scatter read, gather write, 目的是减少系统调用次数。
mujiok2003 2014-05-29
  • 打赏
  • 举报
回复
引用
出现1的问题,是因为发端太快,造成丢包
TCP不会丢包。
不要做咸鱼 2014-05-29
  • 打赏
  • 举报
回复
引用 6 楼 u013093541 的回复:
谢谢,各位大牛,小弟现在就去改代码,今天加个班,明天再向各位求教!
解决问题要紧,先别关IOCP一类的了,不然干完需要一段时间了
筑台封神 2014-05-29
  • 打赏
  • 举报
回复
谢谢,各位大牛,小弟现在就去改代码,今天加个班,明天再向各位求教!
赵4老师 2014-05-29
  • 打赏
  • 举报
回复
超过2GB的文件可能需要用到_lseeki64函数。
赵4老师 2014-05-29
  • 打赏
  • 举报
回复
不知道有多少前人掉在TCP Socket send(人多)send(病少)send(财富) recv(人多病)recv(少财富) 陷阱里面啊! http://bbs.csdn.net/topics/380167545
不要做咸鱼 2014-05-29
  • 打赏
  • 举报
回复
千兆网卡直接send recv 应该也不会出问题吧,而且速度也应该不会慢,是不是你忘了处理粘包的问题呢? 楼上说的文件分块传输也是可以考虑的,通过多线程发送,接收完毕之后再将文件合并, IOCP有一个transmitfile 你可以试一下 希望可以帮到你
加载更多回复(2)

70,024

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧