WSARecv/Send好像与Recv Send不太一样啊?DWORD WINAPI ServerWorkerProc(LPVOID lParam)
{
CIocpModeSvr* pSvr=(CIocpModeSvr*)lParam;
HANDLE CompletionPort=pSvr->CompletionPort;
DWORD ByteTransferred;
LPPER_HANDLE_DATA PerHandleData;
PPER_IO_OPERATION_DATA PerIoData;
DWORD RecvByte;
while(true)
{
bool bSuccess=GetQueuedCompletionStatus(CompletionPort,
&ByteTransferred,
(LPDWORD)&PerHandleData,
(LPOVERLAPPED* )&PerIoData,
INFINITE);
//退出信号到达,退出线程
if(ByteTransferred==-1 && PerIoData==NULL)
{
return 1L;
}
//客户机已经断开连接或者连接出现错误
if(ByteTransferred==0 && 
   (PerIoData->OperType==RECV_POSTED || PerIoData->OperType==SEND_POSTED))
{
//将该客户端数据删除
int arrSize=0;
bool bFind=false;
::EnterCriticalSection(&pSvr->cInfoSection);
while(arrSize<pSvr->ClientInfo.GetSize())
{
PER_HANDLE_DATA pPerHandleData=pSvr->ClientInfo.GetAt(arrSize);
if((pPerHandleData.IpAddr==PerHandleData->IpAddr) &&
   (pPerHandleData.sClient==PerHandleData->sClient))
{
bFind=true;
pSvr->ClientInfo.RemoveAt(arrSize);
break;
}
arrSize++;
}
::LeaveCriticalSection(&pSvr->cInfoSection);
if(bFind)
{
//记录退出日志
CString LogStr;
in_addr in_A;
in_A.S_un.S_addr=PerHandleData->IpAddr;
LogStr.Format("Ip: %s,Socket : %d Disconneted",inet_ntoa(in_A),PerHandleData->sClient);
pSvr->WriteLogString(LogStr);
TRACE("\nSocket : %d Disconneted",PerHandleData->sClient);
//调用回调函数,通知上层该客户端已经断开
pSvr->m_pProcessRecvData(PerHandleData->IpAddr,
PerHandleData->sClient,
NULL,
0);
//关闭套接口
closesocket(PerHandleData->sClient);
GlobalFree(PerHandleData);
GlobalFree(PerIoData);
}
continue;
}
//为读操作完成,处理数据
if(PerIoData->OperType==RECV_POSTED)
{
//调用回调函数,处理数据
pSvr->m_pProcessRecvData(PerHandleData->IpAddr,
                     PerHandleData->sClient,
 PerIoData->RecvBuf,
 ByteTransferred);
//将源数据置空
memset(PerIoData->RecvBuf,0,BUFFER_SIZE);
ByteTransferred=0;
//重置IO操作数据
unsigned long Flag=0;
ZeroMemory(&(PerIoData->OverLapped),sizeof(OVERLAPPED));

PerIoData->RecvDataBuf.buf=PerIoData->RecvBuf;
PerIoData->RecvDataBuf.len=BUFFER_SIZE;
PerIoData->OperType=RECV_POSTED;
//提交另一个Recv请求
WSARecv(PerHandleData->sClient,
&(PerIoData->RecvDataBuf),
1,
&RecvByte,
&Flag,
&(PerIoData->OverLapped),
NULL);
}
//发送完成,置空缓冲区,释放缓冲区
if(PerIoData->OperType==SEND_POSTED)
{
memset(PerIoData,0,sizeof(PER_IO_OPERATION_DATA));
GlobalFree(PerIoData);
ByteTransferred=0;
}
}
return 0L;
}
上面的 "提交另一个Recv请求"  WSARecv到底是是干什么用的?事实上在IOCP里面GetQueuedCompletionStatus(CompletionPort,&ByteTransferred,(LPDWORD)&PerHandleData,(LPOVERLAPPED* )&PerIoData,INFINITE)本身已经可以捕获数据了,为什么还要WSARecv呢?

解决方案 »

  1.   

    WSARecv可以当Recv用,但他自己有自己的特色,就用与异步传输。
    Send发送完然后用Recv跟在后面接收这时程序就会停在Recv这里不往下运行。
    用WSARecv接收时可以跟个事件句柄,在参数Overlapped里,当你调用WSARecv时程序会继续往下运行,有数据传输过来时系统会自动触发事件句柄。
      

  2.   

    GetQueuedCompletionStatus不是已经收到数据了吗?还要WSARecv干嘛?
    而且请再看一下:
    WSARecv(PerHandleData->sClient,&(PerIoData->RecvDataBuf),1,&RecvByte,&Flag,&(PerIoData->OverLapped),NULL);
    第三个参数:也就是那个WSABUF的长度,居然为1,这有什么用?
      

  3.   

    int WSARecv
    (
      SOCKET s,
      LPWSABUF lpBuffers,
      DWORD dwBufferCount,
      LPDWORD lpNumberOfBytesRecvd,
      LPDWORD lpFlags,
      LPWSAOVERLAPPED lpOverlapped,  
      LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
    );
    lpBuffers,lpOverlapped这两个参数分别是干什么用的?
      

  4.   

    不好意思,看走眼了,刚对照MSDN看了下,dwBufferCount是buf数组的个数,而不是buf内的的字节数,ft!!在重叠情况下,获取重叠数据常用WSAGetOverlappedResult(),我不明白这是为什么呀?WSARecv不是已经把重叠事件与buf关联在一起了吗?也就是一但有事件发生,WSAWaitForMultipleEvents就会返回,按照重叠io模式的意思,这时buf内应该有数据了才对呀,干嘛还要个WSAGetOverlappedResult,它不是多余的吗?
      

  5.   

    楼主可以查看MSDN啊
    lpBuffers 
    [in, out] Pointer to an array of WSABUF structures. Each WSABUF structure contains a pointer to a buffer and the length of the buffer. 他是一个指向WSABUF结构的数组,每个WSABUF结构包含一个指向长度为buffer的BUFFER他应该是一个接受套接字内容的一个指针性的数组结构BUF吧 。不知道理解是否正确。
    学习中~有错的地方请多多指点
      

  6.   

    查考windows网络编程2 一书所说一个重叠的I/O请求最终完成后,应用程序要负责获取获取重叠I/O操作的结果。一个重叠请求操作最终完成之后,在事件通知方法中,,
    Winsock会更改与WSAOVERLAPPED结构关联的事件对象的事件传信状态。讲未传信改为已传信。由于已经有一个事件对象分配给WSAOVERLAPPED结构,所以只需简单的调用WSAWaitForMultipleEvents函数,便可判断出重叠I/O调用将在什么时候完成。确定完成之后,接着需要调用WSAGetOverlappedResult函数,判断这个重叠调用到底是成功还是失败。