免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 9955 | 回复: 10
打印 上一主题 下一主题

[C] Tcp传输大文件问题请教! [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2011-07-07 13:55 |只看该作者 |倒序浏览
本帖最后由 mikzh 于 2011-07-07 13:56 编辑

使用Windows作为客户端,Linux作为服务端;

代码纯 C 书写;

传送超过20K的文件时,并将文件写入到服务端同一文件中,总是会少一些字节。

经过抓包,在 Windows发送端的包,和Linux接收端的包是一样的。说明传输过程中没有丢包;

一直怀疑是否是文件发送/接收的速度太快,而Linux端写文件速度太慢导致的。

但是,就算是写得慢,Socket也会将未写完的字符存入缓存中, 之后慢慢写。

那么,消失的字节数哪里去了?

请高人指点一下。

谢谢!

附上代码:
说明:为了大家看得不那么乱,网络连接之类的代码省略了。

接收端:

  1. FILE * fp = fopen("xx.exe","ab+");
  2. while(1)
  3. {
  4.         recvInt = recv( new_fd, recv_buf, sizeof(file_info), 0 );
  5.         if(fp!=NULL)
  6.         {
  7.                 if (fwrite(recv_info.f_data, 1, recvInt , fp ) )
  8.                         fflush(fp);                        //此处是否会影响性能,每写入一点数据就更新一次缓存
  9.         }
  10. }
复制代码
发送端:

  1. if( (err = fopen_s(&sendFp,fPath,"rb") != 0 ))
  2.                 perror("Cannot open this file");
  3.                
  4. while(1)
  5. {

  6.         sendInt = fread( fData, 1, sizeof(fData), sendFp);               
  7.         memcpy(sendBuf,fData,sizeof(fData));
  8.         if( send(sockfd, sendBuf, nNumRead + 141, 0 ) == -1)
  9.         {
  10.                
  11.                 perror("[Send Error]");
  12.                 getchar();
  13.                 exit(1);
  14.         }
  15. }
复制代码

论坛徽章:
15
射手座
日期:2014-11-29 19:22:4915-16赛季CBA联赛之青岛
日期:2017-11-17 13:20:09黑曼巴
日期:2017-07-13 19:13:4715-16赛季CBA联赛之四川
日期:2017-02-07 21:08:572015年亚冠纪念徽章
日期:2015-11-06 12:31:58每日论坛发贴之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-07-12 22:20:002015亚冠之浦和红钻
日期:2015-07-08 10:10:132015亚冠之大阪钢巴
日期:2015-06-29 11:21:122015亚冠之广州恒大
日期:2015-05-22 21:55:412015年亚洲杯之伊朗
日期:2015-04-10 16:28:25
2 [报告]
发表于 2011-07-07 14:16 |只看该作者
使用Windows作为客户端,Linux作为服务端;

代码纯 C 书写;

传送超过20K的文件时,并将文件写入到服 ...
mikzh 发表于 2011-07-07 13:55



最后一包fdata里到底有多少字节要发?

论坛徽章:
0
3 [报告]
发表于 2011-07-07 14:22 |只看该作者
回复 2# yulihua49

写错了,应改成 fread的结果值: sendInt。

本意是读到多少发多少。

论坛徽章:
15
射手座
日期:2014-11-29 19:22:4915-16赛季CBA联赛之青岛
日期:2017-11-17 13:20:09黑曼巴
日期:2017-07-13 19:13:4715-16赛季CBA联赛之四川
日期:2017-02-07 21:08:572015年亚冠纪念徽章
日期:2015-11-06 12:31:58每日论坛发贴之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-07-12 22:20:002015亚冠之浦和红钻
日期:2015-07-08 10:10:132015亚冠之大阪钢巴
日期:2015-06-29 11:21:122015亚冠之广州恒大
日期:2015-05-22 21:55:412015年亚洲杯之伊朗
日期:2015-04-10 16:28:25
4 [报告]
发表于 2011-07-07 14:32 |只看该作者
回复  yulihua49

写错了,应改成 fread的结果值: sendInt。

本意是读到多少发多少。
mikzh 发表于 2011-07-07 14:22



    那么,对端读多少?

论坛徽章:
0
5 [报告]
发表于 2011-07-07 14:40 |只看该作者
回复 4# yulihua49


对端也是读这么多的。

我将发送buf定长了,长度为1024字节。


对端读到的,也是 recv实际得到的。

会不会这个有差异,发送的和recv的会不会有问题,导致数据不全?

论坛徽章:
15
射手座
日期:2014-11-29 19:22:4915-16赛季CBA联赛之青岛
日期:2017-11-17 13:20:09黑曼巴
日期:2017-07-13 19:13:4715-16赛季CBA联赛之四川
日期:2017-02-07 21:08:572015年亚冠纪念徽章
日期:2015-11-06 12:31:58每日论坛发贴之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-07-12 22:20:002015亚冠之浦和红钻
日期:2015-07-08 10:10:132015亚冠之大阪钢巴
日期:2015-06-29 11:21:122015亚冠之广州恒大
日期:2015-05-22 21:55:412015年亚洲杯之伊朗
日期:2015-04-10 16:28:25
6 [报告]
发表于 2011-07-07 15:00 |只看该作者
回复  yulihua49


对端也是读这么多的。

我将发送buf定长了,长度为1024字节。


对端读到的,也 ...
mikzh 发表于 2011-07-07 14:40



    要先发一个长度,好让对方知道读多少。读不够这个数,就再读。就不会丢了。

论坛徽章:
0
7 [报告]
发表于 2011-07-07 15:06 |只看该作者
回复 6# yulihua49

OK。我先试试。

我是将文件放在数据结构中发过去的

结构定义

{
unsigned int send_flag;
unsigned int file_size;
char file_name[32];
char file_path[64];
char send_buf[920];
}

这样,控制发送长度为 1024.
但是,刚才测试的时候,发现读取的时候有分片。

论坛徽章:
324
射手座
日期:2013-08-23 12:04:38射手座
日期:2013-08-23 16:18:12未羊
日期:2013-08-30 14:33:15水瓶座
日期:2013-09-02 16:44:31摩羯座
日期:2013-09-25 09:33:52双子座
日期:2013-09-26 12:21:10金牛座
日期:2013-10-14 09:08:49申猴
日期:2013-10-16 13:09:43子鼠
日期:2013-10-17 23:23:19射手座
日期:2013-10-18 13:00:27金牛座
日期:2013-10-18 15:47:57午马
日期:2013-10-18 21:43:38
8 [报告]
发表于 2011-07-07 15:10 |只看该作者
一次send不一定能把你想要发送的数据发送完成,检查下send的返回值

论坛徽章:
0
9 [报告]
发表于 2011-07-07 15:11 |只看该作者
回复 6# yulihua49


    有没有例子让我参考参考,谢谢!

论坛徽章:
15
射手座
日期:2014-11-29 19:22:4915-16赛季CBA联赛之青岛
日期:2017-11-17 13:20:09黑曼巴
日期:2017-07-13 19:13:4715-16赛季CBA联赛之四川
日期:2017-02-07 21:08:572015年亚冠纪念徽章
日期:2015-11-06 12:31:58每日论坛发贴之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-07-12 22:20:002015亚冠之浦和红钻
日期:2015-07-08 10:10:132015亚冠之大阪钢巴
日期:2015-06-29 11:21:122015亚冠之广州恒大
日期:2015-05-22 21:55:412015年亚洲杯之伊朗
日期:2015-04-10 16:28:25
10 [报告]
发表于 2011-07-07 16:01 |只看该作者
本帖最后由 yulihua49 于 2011-07-07 16:11 编辑
回复  yulihua49


    有没有例子让我参考参考,谢谢!
mikzh 发表于 2011-07-07 15:11

这是我的包头:
  1. #define HEADPACKLENGTH 48

  2. #define         PARANUM 9
  3. #define         PROTO_NUM   para[0]             /*协议号:
  4.                                         客户呼叫服务器时是调用号,
  5.                                         服务器返回时是事件号,1-65535 */
  6. #define         ERRNO1      para[1]             /*主错误码      */
  7. #define         ERRNO2      para[2]             /*辅助错误码    */
  8. #define         PKG_REC_NUM para[3]             /*数据记录数    */
  9. #define         PKG_LEN     para[4]             /*数据包长度    */
  10. #define         T_LEN       para[5]             /* 传输长度  */
  11. #define         O_NODE      para[6]             /*原结点地址*/
  12. #define         D_NODE      para[7]             /*目的结点描述*/
  13. #define         PKG_CRC     para[8]             /*数据包CRC */

  14. typedef struct {                /*协议头        */
  15.         u_int   para[PARANUM];
  16.         char    *data;
  17. } T_NetHead;
复制代码
9个整数共36字节。转化成BASE64,变成48字节。因此,我的包头是固定长度48字节。
接收端按固定长度48先收包头。
然后根据T_LEN收数据。
  1. int RecvNet(int s,char *buf,int n,int timeout)
  2. {
  3. int bcount,br,ret,num=0;
  4. struct timeval tmout;

  5.         if(!buf) return 0;
  6.         tmout.tv_sec=timeout;
  7.         tmout.tv_usec=0;
  8.         ret=setsockopt(s,SOL_SOCKET,SO_RCVTIMEO,(char *)&tmout,sizeof(tmout));

  9.         *buf=0;
  10.         if(n<=0) return 0;
  11.         bcount=0;
  12.         br=0;

  13.         num=0;
  14.         while(bcount<n){
  15.                 if((br=read(s,buf,n-bcount))>0){
  16.                         bcount+=br;
  17.                         buf+=br;
  18.                         continue;
  19.                 }
  20.                 if(br<0){
  21.                     if(errno==11) return TIMEOUTERR;
  22.                     ShowLog(1,"%s:br=%d,err=%d,%s",__FUNCTION__,br,errno,strerror(errno));
  23.                     return -1;
  24.                 }
  25.                 if(!br ) {
  26.                         if( ++num>100) break;
  27.                         usleep(5000);
  28.                         continue;
  29.                 } else num=0;
  30.         }
  31.         if(bcount<=0) {
  32.                 ShowLog(1,"%s:bcount=%d,err=%d,%s",__FUNCTION__,bcount,errno,strerror(errno));
  33.                 return -1;
  34.         }
  35.         return bcount;
  36. }
复制代码
参数n就是要收的数据。如果读的不够数,就不断的读,直到够数或超时。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP