我有一个数据传输程序,服务端采用overlapped模型接收数据,客户端采用tcp协议发送数据,客户端和服务端数据都必须入到本地数据库中,客户端硬件定时采集数据后先入本地库,再向服务端发送,服务端收到数据后入本地库.客户端如果本次发送数据不成功,先保存在文件中,下次采集到数据后再发送。共有8个客户端发送数据,每次发送数据约1M(我在发送时作了处理,把这1M数据分成多次发送,每次数据量不大于1k),服务端一般都可以收到数据,但是有时候服务端收不到某个客户端某时段的数据,后来的数据却可以收到,而那一段时间的数据却永远收不到了.可是,由于我在客户端程序中对发送不成功的数据保存了,下一段时间应该重新发送,服务端在以后的某个时段中应该可以收到,而实际上这些数据却永远收不到了,这是怎么回事,如果我的程序有错,错误可能在什么地方,如果我的程序没有错误,又可能是什么问题.
既然收不到,肯定是数据掉了.
recv这函数不保证你一次就收到你想要的长度.
if (0 != Error || 0 == BytesTransferred )//套接字io错误或者客户端已发出了关闭连接的信息 则必须关闭套接字
{
closesocket(SI->Socket);
GlobalFree(SI);
return;
}
...处理接收到的数据的代码
//重新投递接收请求
Flags = 0;
ZeroMemory(&(SI->Overlapped), sizeof(WSAOVERLAPPED));//overlapped结构清空
//定义接收缓冲区,及其长度
SI->DataBuf.len = DATA_BUFSIZE;
SI->DataBuf.buf = SI->Buffer; if (WSARecv(SI->Socket, &(SI->DataBuf), 1, &RecvBytes, &Flags,
&(SI->Overlapped), WorkerRoutine) == SOCKET_ERROR)
{
if (WSAGetLastError() != WSA_IO_PENDING )
{
closesocket(SI->Socket);
GlobalFree(SI);
return;
}
}workThread代码大致如下(处理接收的线程)
EventArray[0] = (WSAEVENT) lpParameter; while(TRUE)
{
//等候客户端连接信号同时也处理workroutine的返回
while(TRUE)
{
//等待EVENTARRAY中某个事件的完成,或者某个告警IO的完成
Index = WSAWaitForMultipleEvents(1, EventArray, FALSE, WSA_INFINITE, TRUE); if (Index == WSA_WAIT_FAILED)//出现错误
{
return FALSE;
} if (Index != WAIT_IO_COMPLETION)//如果不是由完成例程来处理,表明他是一个客户端的连接请求
{
break;
}
} //结束接收事件
WSAResetEvent(EventArray[Index - WSA_WAIT_EVENT_0]); //创建一个新的客户端socket信息
if ((SocketInfo = (LPSOCKET_INFORMATION) GlobalAlloc(GPTR,
sizeof(SOCKET_INFORMATION))) == NULL)//内存不足
{
return FALSE;
} // 填充客户端socket的详细信息
SocketInfo->Socket = AcceptSocket;
SocketInfo->ClientAddr=ClientAddr;
ZeroMemory(&(SocketInfo->Overlapped), sizeof(WSAOVERLAPPED));
SocketInfo->BytesRECV = 0;
SocketInfo->Buffer2Size = 0;
SocketInfo->DataBuf.len = DATA_BUFSIZE;
SocketInfo->DataBuf.buf = SocketInfo->Buffer; Flags = 0;
//向完成例程投递一个接收请求
if (WSARecv(SocketInfo->Socket, &(SocketInfo->DataBuf), 1, &RecvBytes, &Flags,
&(SocketInfo->Overlapped), WorkerRoutine) == SOCKET_ERROR)
{
//返回错误WSA_IO_PENDING表明重叠io初始化已经完成
if (WSAGetLastError() != WSA_IO_PENDING)
{
closesocket(SocketInfo->Socket);
GlobalFree(SocketInfo);
continue;
}
} }
还有,可以自己做一个发送队列,然后把要发送的数据填入队列的一端,而只在另一端取数据send.对于recv,建立一个recv队列,把接收到的数据存入接受缓冲队列的一端,而只在另一端取数据。这样的模型可能更加直观