基于TCP/IP socket文件传输 外网传输数据丢失

destinyC 2012-11-20 11:39:05
各位好:
第一次写网络传输相关程序,目前在项目中遇到一个问题。在数据传输过程中,内网测试没有问题,但是在连接外网服务器时,Client接收到的数据和Server发送的数据会出现不同的情况(具体是在数据的结尾部分会有约596字节为空)。
后来我加入了对接收数据的MD5码校验,不同则再次请求上一次数据。但是这样很影响速率。
以下是部分代码:

//客户端数据解析(前4个字节是协议含解析MD5校验位,接着4字节是数据大小不包含MD5长度)
BOOL CDataSolver::DataAnalysis( PCHAR pDataAddr ,EPackageData& pPack ,BOOL& bNeedEncode )
{
if(pDataAddr == NULL)
return FALSE;
DWORD dwProtocol = 0;
memcpy(&dwProtocol ,pDataAddr ,sizeof(DWORD));
pPack.dwDataSize = 0;
pPack.dwProtocol = dwProtocol & (~PROT_ENCODE_MD5);
bNeedEncode = (dwProtocol & PROT_ENCODE_MD5) == PROT_ENCODE_MD5;
DWORD dwDataSize = 0;
switch (pPack.dwProtocol)
{
case 需要接收数据:
{
memcpy(&dwDataSize ,pDataAddr + sizeof(DWORD) ,sizeof(DWORD));
pPack.dwDataSize = dwDataSize;
dwDataSize = dwDataSize > MD_DATA_NORMAL_LENGTH ? 0 : dwDataSize;

if(bNeedEncode) //如果有MD5码,则拷贝MD5数据
{
pPack.pCodeAddr = new CHAR[MD_DATA_MD5_LENGTH + 1];
memcpy(pPack.pCodeAddr ,pDataAddr + MD_DATAHEAD_LENGTH ,MD_DATA_MD5_LENGTH);
pPack.pCodeAddr[MD_DATA_MD5_LENGTH] = '\0';
}

if(dwDataSize > 0)
{
pPack.pDataAddr = new CHAR[dwDataSize + 1];
DWORD dwLast = MD_DATAHEAD_LENGTH;
dwLast += bNeedEncode ? MD_DATA_MD5_LENGTH : 0;
memcpy(pPack.pDataAddr ,pDataAddr + dwLast,dwDataSize);
pPack.pDataAddr[dwDataSize] = '\0';
}
}
break;
}

return TRUE;
}




//服务端数据打包及传输
VOID CFunctionRuntime::SendData( EPackageData pPack ,SOCKET pSock)
{
DWORD dwDataSize = 0;
dwDataSize += sizeof(DWORD); //协议
dwDataSize += sizeof(DWORD); //数据长度
if(pPack.dwDataSize > 0)
{
dwDataSize += pPack.dwDataSize; //数据流长度
}

if( (pPack.dwProtocol & PROT_ENCODE_MD5) == PROT_ENCODE_MD5) //或运算,计算是否有MD5附加项
{
dwDataSize += MD_DATA_MD5_LENGTH; //MD5码长度
}

PCHAR pDataAddr = new CHAR[dwDataSize + 1];
memset(pDataAddr ,0 ,dwDataSize + 1);
memcpy(pDataAddr ,&pPack.dwProtocol ,sizeof(DWORD));
memcpy(&pDataAddr[4] ,&pPack.dwDataSize ,sizeof(DWORD)); //protocol + datasize 固定8个字节

if( (pPack.dwProtocol & PROT_ENCODE_MD5) == PROT_ENCODE_MD5
&& pPack.pCodeAddr)
{
memcpy(&pDataAddr[MD_DATAHEAD_LENGTH] ,pPack.pCodeAddr ,MD_DATA_MD5_LENGTH);
}

if(pPack,dwDataSize > 0 && pPack.pDataAddr)
{
DWORD dwLast = MD_DATAHEAD_LENGTH;
dwLast += ((pPack.dwProtocol & PROT_ENCODE_MD5) == PROT_ENCODE_MD5) ? MD_DATA_MD5_LENGTH : 0;
memcpy(&pDataAddr[dwLast] ,pPack.pDataAddr ,pPack.dwDataSize);
}

TcpCommAdapter::GetInstance()->SendData(pDataAddr ,dwDataSize ,pSock);
delete[] pDataAddr;
}

DWORD TcpCommAdapter::SendData( PCHAR pDataAddr ,DWORD dwDataSize ,SOCKET pSock )
{
DWORD dwSendSize = 0;
CGlobalInstance::GetInstance()->GlobalLock();
DWORD dwRemainSize = dwDataSize;
if(pDataAddr && IsServerAlive())
{
//while (dwRemainSize > 0)
//{
// dwSendSize = send(pSock ,pDataAddr ,dwRemainSize ,0);
// if(dwSendSize == 0 || dwSendSize == SOCKET_ERROR)
// {
// break;
// }
// dwRemainSize -= dwSendSize;
// pDataAddr += dwSendSize;
//}
//INT nSize = 0;
//setsockopt(pSock ,SOL_SOCKET ,SO_SNDBUF ,(CHAR*)&nSize ,sizeof(nSize));
dwSendSize = send(pSock ,pDataAddr ,dwRemainSize ,0);
}
CGlobalInstance::GetInstance()->GlobalUnlock();
return dwDataSize ;//== dwDataSize - dwRemainSize ? SD_SOCKET_SEND_SUCCESS : SD_SOCKET_SEND_ERR;
}
...全文
354 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
cook_fish 2014-08-22
  • 打赏
  • 举报
回复
楼主,请问你tcp传输数据在外网能够正常收发吗?我这边发一个数据出去,server端只收了一小部分,就不去收了,不知道怎么回事,求指导。
destinyC 2012-11-20
  • 打赏
  • 举报
回复
再顶一下。。
destinyC 2012-11-20
  • 打赏
  • 举报
回复
Client数据分析代码也在上面,应该是没问题,我也是按照Server打包的格式逆解析出来的。因为在内网测试的时候没有出现这个问题,所以很是奇怪。
winginsky 2012-11-20
  • 打赏
  • 举报
回复
应该不会出现这种情况,你Client组包时是否有问题?
destinyC 2012-11-20
  • 打赏
  • 举报
回复
自己顶一下。
xumaojun 2012-11-20
  • 打赏
  • 举报
回复
TCP传输本来就是基于字节流的,怎么又沾包呢?发送了多少字节就接收多少字节呀
destinyC 2012-11-20
  • 打赏
  • 举报
回复
TO 5楼: 我的协议格式是:DWORD协议(含MD5校验位)+DWORD有效数据长度+32字节MD5校验码+2046字节最大有效数据。所以收发正确的话,应该不会有数据长度错误的问题。不过谢谢你的提醒。
destinyC 2012-11-20
  • 打赏
  • 举报
回复
我好像找到问题了: 我发送的包大小是最大不超过:DWORD+DWORD+32+2046 字节。貌似出现粘包了。我一直以为长度低于4K多字节传输时不会被拆包。然后我把传输包大小改成最大不超过:DWORD+DWORD+32+1024之后低于电信MTU的1.4K多之后传输就正常了。 不过很明显传输速率降得很厉害,看来这块需要重写一下处理粘包了。唉,学艺不精。谢谢3L关心了。
  • 打赏
  • 举报
回复
正常情况下是不会这样的。 可以在你的数据前加一个数据包头,先接收固定长度的包头,从包头中得到数据长度,再接收数据。
《Windows Sockets网络编程》是WindowsSockets网络编程领域公认的经典著作,由Windows Sockets2.0规范解释小组负责人亲自执笔,权威性毋庸置疑。它结合大量示例,对WindowsSockets规范进行了深刻地解读,系统讲解了WindowsSockets网络编程及其相关的概念、原理、主要命令、操作模式,以及开发技巧和可能的陷阱,从程序员的角度给出了大量的建议和最佳实践,是学习WindowsSockets网络编程不可多得的参考书。   全书分为三部分:第一部分(第1~6章),提供了翔实的背景知识和框架方面的概念,借助于此框架,读者可理解WinSock的具体细节,包括WindowsSockets概述、OSI网络参考模型、TCP/IP协议簇中的协议和可用的服务、WinSock网络应用程序的框架及其工作机制、WinSock的三种操作模式、socket通信机制等;第二部分(第7~12章),以FTP客户端实例为基础介绍了函数实例库,还介绍了客户端程序、服务器程序和DLL中间构件及它们的相应函数,并涵盖socket命令和选项及移植BSDSockets相关事项等;第三部分(第13~17章),介绍了应用程序调试技术和工具,针对应用编程中的陷阱的建议和措施,WinSockAPI的多种操作系统平台,WinSock规范的可选功能和WinSock规范2.0中的所有新功能。 译者序 序 前言 第1章 Windows Sockets概述 1.1 什么是Windows Sockets 1.2 Windows Sockets的发展历史 1.3 Windows Sockets的优势 1.3.1 Windows Sockets是一个开放的标准 1.3.2 Windows Sockets提供源代码可移植性 1.3.3 Windows Sockets支持动态链接 1.3.4 Windows Sockets的优点 1.4 Windows Sockets的前景 1.5 结论 第2章 Windows Sockets的概念 2.1 OSI网络模型 2.2 WinSock网络模型 2.2.1 信息与数据 2.2.2 应用协议 2.3 WinSock中的OSI层次 2.3.1 应用层 2.3.2 表示层 2.3.3 会话层 2.3.4 传输层 2.3.5 网络层 2.3.6 数据链路层 2.3.7 物理层 2.4 模块化的层次框 2.5 服务和协议 2.6 协议和API 第3章 TCP/IP协议服务 3.1 什么是TCP/IP 3.2 TCP/IP的发展历史 3.3 传输服务 3.3.1 无连接的服务:UDP 3.3.2 面向连接的服务:TCP 3.3.3 传输协议的选择:UDP与TCP的对比 3.4 网络服务 3.4.1 IP服务 3.4.2 ICMP服务 3.5 支持协议和服务 3.5.1 域名服务 3.5.2 地址解析协议 3.5.3 其他支持协议 3.6 TCP/IP的发展前景 第4章 网络应用程序工作机制 4.1 客户端-服务器模型 4.2 网络程序概览 4.3 socket的打开 4.4 socket的命名 4.4.1 sockaddr结构 4.4.2 sockaddr_in结构 4.4.3 端口号 4.4.4 本地IP地址 4.4.5 什么是socket名称 4.4.6 客户端socket名称是可选的 4.5 与另一个socket建立关联 4.5.1 服务器如何准备建立关联 4.5.2 客户端如何发起一个关联 4.5.3 服务器如何完成一个关联 4.6 socket之间的发送与接收 4.6.1 在“已连接的”socket上发送数据 4.6.2 在“无连接的”socket上发送数据 4.6.3 接收数据 4.6.4 socket解复用器中的关联 4.7 socket的关闭 4.7.1 closesocket 4.7.2 shutdown 4.8 客户端和服务器概览 第5章 操作模式 5.1 什么是操作模式 5.1.1 不挂机,等待:阻塞 5.1.2 挂机后再拨:非阻塞 5.1.3 请求对方回拨:异步 5.2 阻塞模式 5.2.1 阻塞socket 5.2.2 阻塞函数 5.2.3 伪阻塞的问题 5.2.4 阻塞钩子函数 5.2.5 阻塞情境 5.2.6 撤销阻塞操作 5.2.7 阻塞操作中的超时 5.2.8 无最少接收限制值 5.2.9 代码示例 5.3 非阻塞模式 5.3.1 怎样使socket成为非阻塞的 5.3.2 成功与失败不是绝对的 5.3.3 探询而非阻塞 5.3.4 显式地避让 5.3.5 代码示例 5.4 异步模式 5.4.1 认识异步函数 5.4.2 撤销异步操作 5.4.3 代码示例 5.4.4 AU_T

18,356

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 网络编程
c++c语言开发语言 技术论坛(原bbs)
社区管理员
  • 网络编程
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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