user-0 提问: 为什么我用vc编写FTP程序在两台电脑之间传输压缩文件的时候文件损坏了

回复:
user: user-0
content: 问题解决了，还是我的经验不够啊，因为我在文件发送端发送完所有数据后就用closesocket（）马上关闭了套接字，这样做的后果就是接收端在接收到发送端套接字关闭的消息后，也就停止了数据的收发，关闭自己的套接字。如果此时还有数据在线路上传输，那这些数据就会丢失了，无法被正确接收。在同一台电脑上测试的时候没有发现问题是因为同一台电脑上传输数据是很快的，几乎没有时延，在接收端收到发送端套接字关闭的时候，数据也已经接收完毕，此时发送端关闭套接字也不会造成数据的丢失。当在两台电脑之间传数据时，问题就暴露出来了。后来 解决办法就是，发送端发送完数据后没有马上关闭套接字，在接收端接收完所有数据后，给发送端发送一个确认接收完毕的字符串，发送端在接收到这个字符串的时候再关闭自己的套接字。这样就解决了我所有的问题。另外，在实践中还发现，发送数据的时候不必设置延时，发送端可以一直用send（）循环发送数据直到数据发送完毕。不用担心发送过快的问题。因为受链路的限制，send函数会阻塞，也就是它会自己调整你发送数据的速率，这个是根据你发送端到接收端的的带宽来定的。这些流量控制和拥塞控制都是底层的tcp协议帮你做好了的。程序只管发送和接收，而不必考虑传输的问题。 我想说的就这么多，谢谢两位大虾的指点，也希望能给在研究文件传输的朋友们一点帮助，如果说的有什么不对的请见谅。

user: user-1
content: 引用 9 楼 hacker_lpy 的回复:[quote=引用 7 楼 zhao4zhong1 的回复:] Sleep(1000);//延时1000毫秒，保证不了发送和接收的同步。只能通过接收对方的应答的方法保证发送和接收的同步 if(SOCKET_ERROR==send(s,size,strlen(size)+1,0)) 那发送文件的时候要不要两边同步？我是说发送端直接用循环一次性把数据全部发送到接收端的缓冲区里，然后接收端再慢慢接收，从接收缓冲区中读取数据。这样接收到的数据会出错吗？[/quote] 接收端接收到一半断网了咋办？

user: user-1
content: 代码功能归根结底不是别人帮自己看或讲解或注释出来的；而是被自己静下心来花足够长的时间和精力亲自动手单步或设断点或对执行到某步获得的中间结果显示或写到日志文件中一步一步分析出来的。 提醒：再牛×的老师也无法代替学生自己领悟和上厕所！ 单步调试和设断点调试（VS IDE中编译连接通过以后，按F10或F11键单步执行，按Shift+F11退出当前函数；在某行按F9设断点后按F5执行停在该断点处。）是程序员必须掌握的技能之一。

user: user-0
content: 引用 6 楼 zhao4zhong1 的回复:2楼链接里面已经说的非常清楚了。 另外提醒： 不要把 fopen("...","...");fscanf,fprintf,fgets,fgetc,fclose //读时把\r\n替换成\n，写时把\n替换成\r\n;读到\x1a就设置EOF;读写的内容当字符看待 和 fopen("...","...b");fseek,fread,fwrite,fgetc,fclose  //不作以上替换，遇到\x1a仍继续读;读写的内容当字节看待 弄混了 那个链接里的内容看不大懂，具体出在什么问题上你可以说的简洁一点吗？我去查资料看看。另外你说的注意那个几个函数，难道跟读写有关？

user: user-0
content: 引用 7 楼 zhao4zhong1 的回复:Sleep(1000);//延时1000毫秒，保证不了发送和接收的同步。只能通过接收对方的应答的方法保证发送和接收的同步 if(SOCKET_ERROR==send(s,size,strlen(size)+1,0)) 那发送文件的时候要不要两边同步？我是说发送端直接用循环一次性把数据全部发送到接收端的缓冲区里，然后接收端再慢慢接收，从接收缓冲区中读取数据。这样接收到的数据会出错吗？

user: user-1
content: 你这个代码不支持超过2GB的文件传送。 参考 __int64 _telli64( int handle ); int _fileno( FILE *stream );

user: user-1
content: Sleep(1000);//延时1000毫秒，保证不了发送和接收的同步。只能通过接收对方的应答的方法保证发送和接收的同步 if(SOCKET_ERROR==send(s,size,strlen(size)+1,0))

user: user-1
content: 2楼链接里面已经说的非常清楚了。 另外提醒： 不要把 fopen("...","...");fscanf,fprintf,fgets,fgetc,fclose //读时把\r\n替换成\n，写时把\n替换成\r\n;读到\x1a就设置EOF;读写的内容当字符看待 和 fopen("...","...b");fseek,fread,fwrite,fgetc,fclose  //不作以上替换，遇到\x1a仍继续读;读写的内容当字节看待 弄混了

user: user-0
content: 引用 3 楼 zhao4zhong1 的回复:推荐使用WinHex软件查看硬盘或文件或内存中的原始字节内容。  不要把 fopen("...","...");fscanf,fprintf,fgets,fgetc,fclose //读时把\r\n替换成\n，写时把\n替换成\r\n;读到\x1a就设置EOF;读写的内容当字符看待 和 fopen("...","...b");fseek,fread,fwrite,fgetc,fclose  //不作以上替换，遇到\x1a仍继续读;读写的内容当字节看待 弄混了  我发送文件的代码是这样的  void sendfile(SOCKET s,char *path) { FILE *pt; long filesize; int byte; char *filename=NULL,senbuff[M],size[32];  if((pt=fopen(path,"rb"))==NULL) {   printf("打开文件时出现错误"); exit(1); } //send the filename  filename=getfilename(path); if(SOCKET_ERROR==send(s,filename,strlen(filename)+1,0))//发送字符窜的时候要格外注意，strlen函数返回的大小不包含字符窜结束符，因此需要加1 { printf("发送文件名时出现错误\n"); exit(1); } //send the length of file  fseek(pt,0L,SEEK_END);//文件指针移到尾再用ftell函数读出从头到尾的字节数，则为文件大小 filesize=ftell(pt); fseek(pt,0L,SEEK_SET);//再把文件指针移到开头  printf("传输的文件大小为:%ld\n",filesize); sprintf(size,"%ld",filesize); if(SOCKET_ERROR==send(s,size,32,0)) { printf("发送文件大小时出现错误\n"); exit(1); } printf("文件正在传输……\n"); while(1) { Sleep(1000);//延时1000毫秒，保证发送和接收的同步 byte=fread(senbuff,1,M,pt); if(byte<=0) break; if(SOCKET_ERROR==send(s,senbuff,byte,0)) {printf("网络连接中断\n"); exit(1); } } printf("文件传输完毕\n"); fclose(pt); closesocket(s); return; } 能看出是什么问题吗？

user: user-0
content: 引用 1 楼 user-2 的回复:能单步跟踪一下传输过程是最好的，或者把每次发送的日志打印出来，看看是不是发送的数据有问题。 或者对比一下两个文件的字节数，如果不一致就是传输的时候漏发了一部分。 传一个内容是数字的txt文件试试，看看传过去后是那部分没法送成功。  我没有试过单步跟踪。另外接收到的压缩文件大小跟发送的大小一样，只是在我解压的时候就提示压缩文件损坏 了，解压不了。还有我试过了能正常传输文本文件，发送的文本文件和接收到的文本文件是一样的。还有一个现象就是我在同一台电脑测试的时候又可以正常解压不会出错，在两台电脑间传送就会损坏  问题是不是出在发送大二进制文件的时候因为要多次调用send，每次调用的时候都要有一个延时，等到接受端接受完毕后才进行第二次发送？是不是要保证发送和接收的同步，遵守一发一收的规则？还有，在发送大文件的时候一定要先进行分块再发送出去吗？我刚接触文件传输的东西，还不大懂，谢谢大神的解答

user: user-1
content: 推荐使用WinHex软件查看硬盘或文件或内存中的原始字节内容。  不要把 fopen("...","...");fscanf,fprintf,fgets,fgetc,fclose //读时把\r\n替换成\n，写时把\n替换成\r\n;读到\x1a就设置EOF;读写的内容当字符看待 和 fopen("...","...b");fseek,fread,fwrite,fgetc,fclose  //不作以上替换，遇到\x1a仍继续读;读写的内容当字节看待 弄混了

user: user-1
content: 不知道有多少前人掉在TCP Socket send(人多)send(病少)send(财富) recv(人多病)recv(少财富) 陷阱里面啊！ http://bbs.csdn.net/topics/380167545

user: user-2
content: 能单步跟踪一下传输过程是最好的，或者把每次发送的日志打印出来，看看是不是发送的数据有问题。 或者对比一下两个文件的字节数，如果不一致就是传输的时候漏发了一部分。 传一个内容是数字的txt文件试试，看看传过去后是那部分没法送成功。