tcp传输文件,急求答案~

悍匪笑哈哈 2014-06-15 07:46:36
写了个tcp阻塞接发文件的代码。
在接收完close(文件描述符)时,系统有时会崩溃!
就算不崩溃,接收的文件大小没问题,但打开显示文件损坏,不知道是什么地方出了问题。
大家帮我分析分析。
...全文
199 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
悍匪笑哈哈 2014-06-16
  • 打赏
  • 举报
回复
是接收端,写文件时的fclose会崩溃
悍匪笑哈哈 2014-06-16
  • 打赏
  • 举报
回复
多谢各位,换成memcpy传输文件没有损坏了。 但是还有一个问题,fclose有时会崩溃,不晓得为什么,希望各位再帮个忙
robertbo 2014-06-16
  • 打赏
  • 举报
回复
不知道你的STMSG是什么结构,二进制流的拷贝要用memcpy。 你可以试着单步调节定位问题,传输一个内容全是字节写好的数字的文件,比如,111111112222222233333333,看看接收后存下来的文件内容是怎样的,可以帮助定位错误
赵4老师 2014-06-16
  • 打赏
  • 举报
回复
不知道有多少前人掉在TCP Socket send(人多)send(病少)send(财富) recv(人多病)recv(少财富) 陷阱里面啊! http://bbs.csdn.net/topics/380167545
zilaishuichina 2014-06-16
  • 打赏
  • 举报
回复
引用 3 楼 zilaishuichina 的回复:

STMSG msgbody;
msgbody.MsgType = 'b';
msgbody.iMsgSize = ilen;
strncpy(msgbody.szMsgBody, p, 1 + 4 + ilen); //此处长度lz计算的不对,导致实际文件内容每次都要少拷贝5个字节。

看错了, 不是这个问题。 主要是strncpy 要换成memcpy
羽飞 2014-06-16
  • 打赏
  • 举报
回复
strncpy(msgbody.szMsgBody, p, ilen); 发送文件的时候也不应该用strncpy,这个函数是复制字符串的,如果遇到'\0'就结束了,发送二进制文件就会有问题
zilaishuichina 2014-06-16
  • 打赏
  • 举报
回复
拷贝内存最好用memcpy
zilaishuichina 2014-06-16
  • 打赏
  • 举报
回复
另外 strncpy 这个函数是用来拷贝字符串的, 遇到'\0'(对应的数值就是0)就会结束,后面的内容就复制不了了。 也就是说除非你的文件就是一个文本文件,里面都是正常字符或者是汉字。否则你不能保证你的文件内容里面不包含'\0'这个字符的。
zilaishuichina 2014-06-16
  • 打赏
  • 举报
回复

STMSG msgbody;
msgbody.MsgType = 'b';
msgbody.iMsgSize = ilen;
strncpy(msgbody.szMsgBody, p, 1 + 4 + ilen); //此处长度lz计算的不对,导致实际文件内容每次都要少拷贝5个字节。

悍匪笑哈哈 2014-06-16
  • 打赏
  • 举报
回复
顶下,在线等~。 主要是文件传输大小没问题,但文件损坏,不知道为什么
xiaoyu_code 2014-06-16
  • 打赏
  • 举报
回复
赵老师说的对,要组包...核对大小
赵4老师 2014-06-16
  • 打赏
  • 举报
回复
引用 14 楼 zhouxhmoon 的回复:
[quote=引用 13 楼 zhao4zhong1 的回复:] Windows: 崩溃的时候在弹出的对话框按相应按钮进入调试,按Alt+7键查看Call Stack里面从上到下列出的对应从里层到外层的函数调用历史。双击某一行可将光标定位到此次调用的源代码或汇编指令处。 Lunix: 进程意外退出会在当前目录下产生‘core’文件或形如‘core.数字’的文件比如‘core.1234’ 使用命令 gdb 运行程序名 core或core.数字 进入gdb然后使用bt命令 可以查看进程意外退出前函数调用的堆栈,内容为从上到下列出对应从里层到外层的函数调用历史。 如果进程意外退出不产生core文件,参考“ulimit -c core文件最大块大小”命令
大都是在fclose处。[/quote] 在f=fopen(...)返回时记住f的值,看在fclose时f的值变没变,如果变了,在f上设置数据改变断点,重新运行一次;如果没变,检查磁盘空间是否满了,写文件对应的盘是否已拔出……
悍匪笑哈哈 2014-06-16
  • 打赏
  • 举报
回复
引用 13 楼 zhao4zhong1 的回复:
Windows: 崩溃的时候在弹出的对话框按相应按钮进入调试,按Alt+7键查看Call Stack里面从上到下列出的对应从里层到外层的函数调用历史。双击某一行可将光标定位到此次调用的源代码或汇编指令处。 Lunix: 进程意外退出会在当前目录下产生‘core’文件或形如‘core.数字’的文件比如‘core.1234’ 使用命令 gdb 运行程序名 core或core.数字 进入gdb然后使用bt命令 可以查看进程意外退出前函数调用的堆栈,内容为从上到下列出对应从里层到外层的函数调用历史。 如果进程意外退出不产生core文件,参考“ulimit -c core文件最大块大小”命令
大都是在fclose处。
赵4老师 2014-06-16
  • 打赏
  • 举报
回复
Windows: 崩溃的时候在弹出的对话框按相应按钮进入调试,按Alt+7键查看Call Stack里面从上到下列出的对应从里层到外层的函数调用历史。双击某一行可将光标定位到此次调用的源代码或汇编指令处。 Lunix: 进程意外退出会在当前目录下产生‘core’文件或形如‘core.数字’的文件比如‘core.1234’ 使用命令 gdb 运行程序名 core或core.数字 进入gdb然后使用bt命令 可以查看进程意外退出前函数调用的堆栈,内容为从上到下列出对应从里层到外层的函数调用历史。 如果进程意外退出不产生core文件,参考“ulimit -c core文件最大块大小”命令
悍匪笑哈哈 2014-06-16
  • 打赏
  • 举报
回复
自己顶下,基本就是在fwrite和fclose这块有问题。
悍匪笑哈哈 2014-06-15
  • 打赏
  • 举报
回复
发送端: #pragma pack(push, 1) struct STMSG { //开始接收文件 'a' 1 //接收文件体 'b' 1+4+bodysize //结束接收文件 'c' 1 //普通信息 'd' 1+4+bodysize char MsgType; UINT iMsgSize; char szMsgBody[BUF]; }; #pragma pack(pop) int CAbmSocket::SendMsg(const char* buf, int len) { STMSG msg; msg.MsgType = 'd'; msg.iMsgSize = len; strncpy(msg.szMsgBody, buf, len); len += 5; if(send(m_sock, (char*)&msg, len, 0) != len) { return SOCKET_SEND_ERR; } return SOCKSUCCESS; } int CAbmSocket::SendFile(const char* path) { int iRet = SOCKSUCCESS; char *p = NULL; // FILE *pf = NULL; CFile f; p = new char[BUF]; // pf = fopen(path, "rb"); int count = 0; if(/*pf*/f.Open(path, CFile::modeRead | CFile::typeBinary)) { struct _stat FileInfo; _stat(path, &FileInfo); STMSG msghead; msghead.MsgType = 'a'; send(m_sock, (char*)&msghead, 1, 0); while(1) { // int ilen = fread(p, 1, BUF, pf); int ilen = f.Read(p, BUF); STMSG msgbody; msgbody.MsgType = 'b'; msgbody.iMsgSize = ilen; strncpy(msgbody.szMsgBody, p, ilen); count += ilen; ilen += 5; send(m_sock, (char*)&msgbody, ilen, 0); if(count == FileInfo.st_size) { break; } } STMSG msgend; msgend.MsgType = 'c'; send(m_sock, (char*)&msgend, 1, 0); } else { iRet = OPEN_FILE_ERR; } f.Close(); // if(NULL != pf) // { // fclose(pf); // } if(NULL != p) { delete[] p; } return iRet; } 接收端: int CAbmSocket::RecvMsg(char* buf, int len) { /******************************************************************************** 1.n> 0, ok 2.n== 0, socket对方节点正常shutdown 3.n==-1, error SOCKET_ERROR ********************************************************************************/ memset(buf, 0, len); char type; int size = 0; if(recv(m_sock, &type, sizeof(char), 0) <= 0) { return FAILURE; } if(type == 'd' || type == 'b') { if(recv(m_sock, (char*)&size, sizeof(int), 0) <= 0) { return FAILURE; } if(size > 0) { int iGetLen = 0; iGetLen = recv(m_sock, buf, size, 0); if(iGetLen <= 0) { return FAILURE; } else { return iGetLen; } } } if(type == 'c') { return ENDFILE; } if(type == 'a') { return BEGINFILE; } return SUCCESS; } int CAbmSocket::RecvFile(const char *path) { int iRet = FAILURE; char *p = NULL; // FILE *pf = NULL; CFile f; p = new char[BUF]; // pf = fopen(path, "wb"); if(/*pf*/f.Open(path, CFile::modeWrite | CFile::typeBinary)) { while(1) { int iLen = RecvMsg(p, BUF); if(iLen == BEGINFILE) { continue; } else if(iLen == ENDFILE) { iRet = SUCCESS; break; } else if(iLen < 0) { //接收失败 or 连接断开 break; } else if(iLen = 0) { AfxMessageBox("ilen = 0"); f.Write(p, iLen); } else { f.Write(p, iLen); // fwrite(p, 1, iLen, pf); //pf << p // fflush(pf); //fflush用于输出流,把缓冲中未曾写入文件的内容写入文件 } } } else { iRet = OPEN_FILE_ERR; } f.Close(); // if(NULL != pf) // { // fclose(pf); // } if(NULL != p) { delete[] p; } return iRet; }

64,654

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

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