请教关于完成端口的数据接收问题

thb 2005-02-05 01:36:45
在用 BOOL GetQueuedCompletionStatus(
HANDLE CompletionPort,
LPDWORD lpNumberOfBytes,
PULONG_PTR lpCompletionKey,
LPOVERLAPPED* lpOverlapped,
DWORD dwMilliseconds
);
函数等待接收数据返回时,我看到有些程序例子是在lpCompletionKey参数中取得客户发送来的数据,
有些例子又是在lpOverlapped参数中取得数据,这是为什么,又如何设定在哪个参数中取得数据
...全文
给本帖投票
244 8 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
「已注销」 2005-04-14
  • 打赏
  • 举报
回复
lpCompletionKey参数:是你在createcompletionport函数建立关联时传递的,记录连接上来的socket数据自定义结构;
lpOverlapped参数:是你在进行数据收发时传递的,记录每次IO数据自定义结构。
nuaawenlin 2005-02-05
  • 打赏
  • 举报
回复
楼上正解,接受到的数据只与你给WSARecv()投递的接受缓冲区在哪个自定义的结构体中,
GetQueCompletionPort()只是判断完成端口的状态
shicheng521 2005-02-05
  • 打赏
  • 举报
回复
在你接受数据的时候,你指定的接受缓冲区在哪个参数里,就在那个参数中取接收到的数据
simonzone 2005-02-05
  • 打赏
  • 举报
回复
thb 2005-02-05
  • 打赏
  • 举报
回复
u p
VCSQLVB 2005-02-05
  • 打赏
  • 举报
回复
前一个取得XX,后一个取得YY。
JasonHeung 2005-02-05
  • 打赏
  • 举报
回复
//
//发送接收数据后处理
//
BOOL JhCpServer::IOActionFinish(PPER_IO_CONTEXT lpPerIoContext,int nFlags)
{
//
//nFlags == IO_READ_COMPLETION表示完成的上一次IO操作是WSARecv。
//
if (IO_READ_COMPLETION == nFlags)
{
//
//完成了WSARecv,添加数据到缓冲区
//
if (lpPerIoContext->dataLen > 0)
{
AddRecvData(lpPerIoContext->sClient,lpPerIoContext->wsaBuffer.buf,lpPerIoContext->dataLen);
}
//lpPerIoContext->ContinueAction = ContinueWrite;
//if (server)
//{
// SOCKETDATA sd;
// sd.s = lpPerIoContext->sClient;
// sd.pData = lpPerIoContext->wsaBuffer.buf;
// sd.DataLen = lpPerIoContext->dataLen;
// server->OnReceive(&sd);
//}
//

//
//转向发送
//
TrySend(lpPerIoContext);

return TRUE;
}

if (IO_WRITE_COMPLETION == nFlags)
{
//
//上一次IO操作WSASend数据发送完成,可以将后续操作标志设置为关闭则关闭连接
//如果不需要关闭而是要继续发送,将lpPerIoContext->IoOperation设置为
//IoWrite,如果要继续接收,将lpPerIoContext->IoOperation设置为
//IoRead,并初始化好BUFFER。
//
if (server && lpPerIoContext->dataLen > 0)//发送成功
{
server->OnSendSuccess(lpPerIoContext->sClient,lpPerIoContext->dataLen);
}

TrySend(lpPerIoContext);

return TRUE;
}
if (IO_ACCEPT_COMPLETION == nFlags)
{
//
//刚建立了一个连接,并且没有收发数据,,,,
//
lpPerIoContext->IoOperation = IoRead;
// ZeroMemory(&(lpPerIoContext->ol), sizeof(WSAOVERLAPPED));
// ZeroMemory(lpPerIoContext->szBuffer, BUFFER_SIZE);
// lpPerIoContext->wsaBuffer.len = BUFFER_SIZE;
// lpPerIoContext->wsaBuffer.buf = lpPerIoContext->szBuffer;

if (server)
{
server->OnConnect(lpPerIoContext->sClient);
}
return TRUE;
}

return FALSE;
}

//
//试图发送
//
void JhCpServer::TrySend(PPER_IO_CONTEXT lpPerIoContext)
{
//取得最近一个 发送数据包
ZeroMemory(&(lpPerIoContext->ol), sizeof(WSAOVERLAPPED));
ZeroMemory(lpPerIoContext->szBuffer, BUFFER_SIZE);
if (lpPerIoContext->sendBuf == NULL)//转向继续接收
{
lpPerIoContext->IoOperation = IoRead;
}
else//转向发送
{
EnterCriticalSection(&lpPerIoContext->sendCriticalSection);
if (lpPerIoContext->sendBuf->SendOffset + lpPerIoContext->dataLen >= lpPerIoContext->sendBuf->GetDataLen())//该数据包是否已经发送完
{
SendData* nextData = lpPerIoContext->sendBuf;
lpPerIoContext->sendBuf = (SendData*)nextData->next;
Del(nextData);
}
else
{
lpPerIoContext->sendBuf->SendOffset += lpPerIoContext->dataLen;
}
if (lpPerIoContext->sendBuf != NULL)
{
lpPerIoContext->dataLen = min(BUFFER_SIZE,lpPerIoContext->sendBuf->GetDataLen() - lpPerIoContext->sendBuf->SendOffset);
memcpy(lpPerIoContext->szBuffer,lpPerIoContext->sendBuf->GetData() + lpPerIoContext->sendBuf->SendOffset,lpPerIoContext->dataLen);
lpPerIoContext->wsaBuffer.len = lpPerIoContext->dataLen;
lpPerIoContext->IoOperation = IoWrite;
}
else//没有了,转向接收
{
lpPerIoContext->IoOperation = IoRead;
lpPerIoContext->dataLen = 0;
lpPerIoContext->wsaBuffer.len = BUFFER_SIZE;
}
LeaveCriticalSection(&lpPerIoContext->sendCriticalSection);
}
}

//
//执行发送或者接收数据
//
BOOL JhCpServer::IOAction( PPER_IO_CONTEXT lpPerIoContext)
{
int nResult;
DWORD dwFlags = 0,dwSend = 0;
//
//发送数据且发送数据长度大于0
//
if (IoWrite == lpPerIoContext->IoOperation && lpPerIoContext->dataLen > 0)
{
nResult = WSASend(lpPerIoContext->sClient,
&(lpPerIoContext->wsaBuffer),
1,
&dwSend,
0,
&(lpPerIoContext->ol),
NULL
);
if((SOCKET_ERROR == nResult) && (ERROR_IO_PENDING != WSAGetLastError()))
{
TRACE( "WSASend() failed:%d " ,WSAGetLastError() );
if (server) server->OnSendFail(lpPerIoContext->sClient,WSAGetLastError());

ReleaseClient(lpPerIoContext);

return FALSE;
}
else
{
TRACE("Send data %d %d bytes success.\n ",lpPerIoContext->dataLen,dwSend);
}
}

//
//读取数据
//
if (IoRead == lpPerIoContext->IoOperation)
{
lpPerIoContext->dataLen = 0;
lpPerIoContext->wsaBuffer.len = BUFFER_SIZE;
nResult = WSARecv(lpPerIoContext->sClient,
&(lpPerIoContext->wsaBuffer),
1,
&lpPerIoContext->dataLen,
&dwFlags,
&(lpPerIoContext->ol),
NULL
);

if((SOCKET_ERROR==nResult) && (ERROR_IO_PENDING != WSAGetLastError()))
{
TRACE( "WSARecv() failed:%d " , WSAGetLastError() );
if (server) server->OnReceiveFail( lpPerIoContext->sClient,WSAGetLastError());

ReleaseClient(lpPerIoContext);

return FALSE;
}
else
{
TRACE("Receive data %d bytes.\n",lpPerIoContext->dataLen);
}

}

//
//关闭客户连接
//
if (IoEnd == lpPerIoContext->IoOperation)
{
ReleaseClient(lpPerIoContext);//释放资源
InsertToLookaside(lpPerIoContext,NULL);//插入到空闲链表中备用
}

return TRUE;
}
JasonHeung 2005-02-05
  • 打赏
  • 举报
回复
DWORD __stdcall CompletionRoutine(LPVOID Param)
{
CompletionPortModel* pCP = (CompletionPortModel*)Param;
DWORD dwNumberBytes;
PPER_HANDLE_CONTEXT lpHandleContext = NULL;
LPWSAOVERLAPPED lpOverlapped = NULL;
int nResult;
BOOL bSuccess;
EnterCriticalSection(&pCP->m_CPCriSection);
++ pCP->CPThreadCount;
LeaveCriticalSection(&pCP->m_CPCriSection);
TRACE("第%d个完成端口处理线程启动。\n",pCP->CPThreadCount);

while (pCP->CPThreadRun == 1)
{
bSuccess = GetQueuedCompletionStatus(pCP->m_hCOP,&dwNumberBytes,(PULONG_PTR )&lpHandleContext,&lpOverlapped,1000);//INFINITE);

PPER_IO_CONTEXT lpPerIoContext = (PPER_IO_CONTEXT)lpOverlapped;
if (FALSE == bSuccess && pCP->CPThreadRun == 1)
{

#ifndef _DEBUG
TRACE( "GetQueuedCompletionStatus() failed: %d" , GetLastError());
#endif
if (lpPerIoContext)
{
pCP->ReleaseClient(lpPerIoContext);

pCP->InsertToLookaside(lpPerIoContext, NULL);
}
if (lpHandleContext)
{
lpHandleContext->pNext = NULL;
pCP->InsertToLookaside(NULL, lpHandleContext);
}

continue;
}
if (pCP->CPThreadRun == 1)
{
if (NULL == lpHandleContext)
{
//
//PostQueuedCompletionStatus发过来一个空的单句柄数据,表示线程要退出了。
//
TRACE("第%d个完成端口处理线程退出:PostQueuedCompletionStatus发过来一个空的单句柄数据,表示线程要退出了\n",pCP->CPThreadCount);
--pCP->CPThreadCount;
return 0;
}


#ifdef _DEBUG
// TRACE( "recv buffer data: %s %d\n", lpPerIoContext->szBuffer,lpPerIoContext->dataLen);
#endif

if(IoAccept != lpPerIoContext->IoOperation && 0 == dwNumberBytes)//非连接消息且收发数据长度为0,则关闭连接
{
pCP->OnClientClose(lpPerIoContext->unId);
pCP->ReleaseClient(lpPerIoContext);
pCP->InsertToLookaside(lpPerIoContext, NULL);

lpHandleContext->pNext = NULL;
pCP->InsertToLookaside(NULL, lpHandleContext);

continue;
}

HANDLE hResult;
PPER_HANDLE_CONTEXT lpNewperHandleContext = NULL;

switch(lpPerIoContext->IoOperation)
{
case IoAccept :
if (dwNumberBytes > 0)
{
//
//第一次连接成功并且收到了数据,将这个结点从链表中解除
//
EnterCriticalSection(&pCP->m_ListCriSection);
pCP->ReleaseNode(lpPerIoContext);
LeaveCriticalSection(&pCP->m_ListCriSection);
}
//将客户连接和服务器监听连接关联,即在客户连接中设置服务器监听连接
nResult = setsockopt(lpPerIoContext->sClient,
SOL_SOCKET,
SO_UPDATE_ACCEPT_CONTEXT,
(char *)&pCP->m_ListenSocket,
sizeof(pCP->m_ListenSocket)
);
if(SOCKET_ERROR == nResult)
{
TRACE( "SO_UPDATE_ACCEPT_CONTEXT failed to update accept socket\n" );
pCP->ReleaseClient(lpPerIoContext);
pCP->InsertToLookaside(lpPerIoContext, NULL);

continue;
}

//获取一个空闲的节点
lpNewperHandleContext = pCP->GetHandleFromLookaside();//获取一个空闲节点
if (NULL == lpNewperHandleContext)//无且创建失败
{
TRACE( "HeapAlloc() for lpNewperHandlecontext failed\n" );
pCP->ReleaseClient(lpPerIoContext);
pCP->InsertToLookaside(lpPerIoContext, NULL);

continue;
}

lpNewperHandleContext->pNext = NULL;

//
//将新建立的套接字关联到完成端口
//
hResult = CreateIoCompletionPort(
(HANDLE)lpPerIoContext->sClient,\
pCP->m_hCOP,
(DWORD_PTR)lpNewperHandleContext,
0
);
if (NULL == hResult)
{
TRACE( "将新建立的套接字关联到完成端口时,CreateIoCompletionPort() failed:%d ", GetLastError());

pCP->ReleaseClient(lpPerIoContext);
pCP->InsertToLookaside(lpPerIoContext, NULL);
lpNewperHandleContext->pNext = NULL;
pCP->InsertToLookaside(NULL, lpNewperHandleContext);

continue;
}
//保留完成键
pCP->AddClient(lpPerIoContext);

int flags;
if (dwNumberBytes > 0)//同时收到数据
{
lpPerIoContext->dataLen = dwNumberBytes;
flags = IO_READ_COMPLETION;
}
else//如果连接成功但是没有收到数据
{
lpPerIoContext->dataLen = 0;
flags = IO_ACCEPT_COMPLETION;
}
pCP->IOActionFinish(lpPerIoContext,flags );
bSuccess = pCP->IOAction(lpPerIoContext);
if (FALSE == bSuccess)
{
continue;
}
break;//end of case IoAccept

case IoRead:
pCP->IOActionFinish(lpPerIoContext, IO_READ_COMPLETION);
bSuccess = pCP->IOAction(lpPerIoContext);
if (FALSE == bSuccess)
{
continue;
}

break;//end of case IoRead

case IoWrite:
pCP->IOActionFinish(lpPerIoContext, IO_WRITE_COMPLETION);
bSuccess = pCP->IOAction(lpPerIoContext);
if (FALSE == bSuccess)
{
continue;
}

break;

default:
continue;
break;
}
}
}

TRACE("第%d个完成端口处理线程退出。\n",pCP->CPThreadCount);
EnterCriticalSection(&pCP->m_CPCriSection);
--pCP->CPThreadCount;
LeaveCriticalSection(&pCP->m_CPCriSection);
return 0;

}//end of CompletionRoutine()

18,363

社区成员

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

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

手机看
关注公众号

关注公众号

客服 返回
顶部