首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C++ >

关于SOCKET传输结构体的有关问题,望高手指教

2012-04-13 
关于SOCKET传输结构体的问题,望高手指教!我做了一个关于SOCKET传输结构体的程序,用MFC开发的,有一个服务器

关于SOCKET传输结构体的问题,望高手指教!
我做了一个关于SOCKET传输结构体的程序,用MFC开发的,有一个服务器端(S)和一个客户端(C)。

在S和C里都定义了一个结构体
struct SendCCData
{
int macdata[1024];//具体数据
};

在S端定时发送数据给C端

在CLH_SystemDlg类里定义了保护变量long Data[1024];

在BOOL CLH_SystemDlg::OnInitDialog()
{
  for(int i=0;i<1040;i++)
  {
Data[i]=10;
  }

  Data[3]=430;
  Data[888]=234;
  kks=3000;
}

void CLH_SystemDlg::OnTimer(UINT nIDEvent) 
{
  Data[0]=kks--;
for(int i=0;i<1024;i++)
scdata.macdata[i]=Data[i];
char recvstr[4097];
memcpy(recvstr,&scdata,4096);
recvstr[4096]='\0';
  send(Client,recvstr,sizeof(SendCCData)+1,0); 
}  

在客户端的OnInitDialog()
client = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(client == INVALID_SOCKET)
{
MessageBox(L" 创建套接字失败",L"提示",MB_OK);
return 0;
}

sockaddr_in servAddr; 
servAddr.sin_family = AF_INET;
servAddr.sin_port = htons(4567);
servAddr.sin_addr.S_un.S_addr = inet_addr("192.168.0.123");


if(::connect(client, (sockaddr*)&servAddr, sizeof(servAddr)) == -1)
{
MessageBox(L" 与主机连接失败",L"提示",MB_OK);
return 0;
}
::WSAAsyncSelect(client,this->m_hWnd, WM_SOCKET, FD_READ);

处理这个WM_SOCKET消息的函数是
LRESULT CLH_SystemDlg::AccpSocket(WPARAM wParam, LPARAM lParam)

{
SOCKET s = wParam;
// 查看是否出错
if(WSAGETSELECTERROR(lParam))
{
::closesocket(s);
return 0;
}
// 处理发生的事件
switch(WSAGETSELECTEVENT(lParam))
{
case FD_READ:// 监听中的套接字检测到有连接进入
{
char recvstr[4097];//用于接收服务器端发送来的数据
int nRecv = ::recv(client,recvstr,4097,0);
  memcpy(&scdata,recvstr,4096);//scdata在客户端类的私有变量里定义了 SendCCData scdata


int &jsn=Data[0];
jsn=sizeof(long);
for(int i=0;i<1040;i++)
Data[i]=scdata.macdata[i];


现在问题就是如果客户端和服务器端都在自己电脑上运行,一点问题都没有,接受到的数据都是对的
而如果客户端放在别的电脑上运行,那么在客户端第一次接受到数据的时候Data[0]=3000;这个是对的,但是在以后接收数据的时候就不对了Data[0]=10了。数据接收发生了偏移。在服务器端发送的Data[888]=234;而在客户端收到Data[523]=234,而在Data[659]到Data[1023]都不对了,都是-822155.也就是接收到的数据偏移了365。
请大侠解答一下,为什么会这样啊?


[解决办法]
因为你接收数组比发送数组不一样大
在本机网卡可能loopback,能发一次,收一次
别的电脑,很可能发几次,才调用了一次recv,没收完的下次继续收,而且从data[0]那个地方开始写
[解决办法]
你还是4个字节4个字节的发吧 ,调试一下看是不是你发出去的就是data[0] = 10;
[解决办法]
你接收函数那儿不是有nRecv,表示收到的字节数
超过发送数1025就把前1025*n个取出来,剩下的nRecv-n*1025再memmov到最前面去
下次再从recvstr+nRecv-n*1025的位置收4097-(nRecv-n*1025)个字节
[解决办法]
你在处理消息之前使用了WSAAsyncSelect这个函数,它会将套接字自动设置为非阻塞模式。

在非阻塞模式下,WINSOCK接口会根据缓冲区和数据包的实际情况自由的对数据包进行组合和分割发送,也就是当客户端连续多次发送包时,多个数据包可能会组合在一起进行了发送,也就是出现了"粘连"情况,也可能会发生单个数据包被分割的情况,这样接受到的只是包的一部分,需要重复接受多次才能得到一个完整的包。

当你使用recv接收数据的时候,可能系统接收缓冲区里有大于4096字节的数据,也有可能有小于4096字节的数据,这时候你去接收数据,可能接收到的数据不足4096字节。

int nRecv = ::recv(client,recvstr,4097,0);你在这句话里没有做判断接收到的数据是否够4096字节,如果有一次不够4096字节,没有继续接收数据就做拷贝了,那么下一次接收的时候就会出现偏移,这是肯定的啦。
nRecv 表示接收到的字节数,每次接收完都要去判断一下,才不会影响以后的数据。

热点排行