我是初学IOCP,有好些问题还不明白,问题如下:
1.在listen到新的连接后,需要再次调用CreateIoCompletionPort,之后还要要提请一次收或发的操作,我不明白这一步是否必需,那到底是用WSARecv还是WSASend。2.假设客户端连上后发出了2次int型数据,那这两次数据是是如何被接收下来的?是被CreateIoCompletionPort后发起的WSARecv接收还是在GetQueuedCompletionStatus之后再调用WSARecv接收?3.在许多程序的完成键结构中都定义了操作类型参数(opType),表明是Recv还是Send,可是我不明白系统怎么会知道在GetQueuedCompletionStatus后就会自动认得opType是表明操作的参数,并给其赋与相应的值。
1.在listen到新的连接后,需要再次调用CreateIoCompletionPort,之后还要要提请一次收或发的操作,我不明白这一步是否必需,那到底是用WSARecv还是WSASend。2.假设客户端连上后发出了2次int型数据,那这两次数据是是如何被接收下来的?是被CreateIoCompletionPort后发起的WSARecv接收还是在GetQueuedCompletionStatus之后再调用WSARecv接收?3.在许多程序的完成键结构中都定义了操作类型参数(opType),表明是Recv还是Send,可是我不明白系统怎么会知道在GetQueuedCompletionStatus后就会自动认得opType是表明操作的参数,并给其赋与相应的值。
解决方案 »
- 小小鸟弱问:怎么用DIB或者GDI+读取JPG图片并获得像素数据数组啊?
- 在有些计算机上运行,读取位置 0x00000004 时发生访问冲突
- WM_SYSCOMMAND消息屏蔽WM_CLOSE消息?
- 关于SetWindowText的问题
- mfc写的activex,和脚本语言互动出现了问题,请高手帮忙。对接口技术还是似懂非懂啊。
- 用SDK+C++模式寫的XP Menu,誰想看看!
- 请问各位大哥,MPI能与VC数据库连接吗?谢谢啦!(高分求助)
- UDP如何广播?
- CString的数字怎样***转换成***int??(2)int的又怎样be CString******
- 请问如何在cnshare里面发布免费软件?
- 怎样通过CRecordSet将数据库里的数据全部删除(在线等)
- 求机械工业出版社出版的《Visual C++ MFC 扩展编程实例》光盘。
1、调用一次收或者发的操作是用OVERLAP方式进行,所以可以立即退出接收,至于接收或者发送的过程就交给系统了,当接收或者发送完成自然会唤醒一个线程(该线程已经调用了GetQueuedCompletionStatus函数)。如果不知道对方什么时候要发下一包数据就调用WSARecv,这样当对方发送数据时自然有一个线程会响应
2、第一包数据肯定是被第一次发起的WSARecv接收下来的,但是一次WSARecv不能保证数据全部接收,一般对于数据流还要定义数据格式,然后通过检查接收数据的格式来看有没有接收完,没有接收完在GetQueuedCompletionStatus后继续接收
3、opType是自定义的,你在WSASend或WSARecv之前赋值,系统并不管,在发送和接收的IO操作完成之后完成端口都会唤醒一个线程,它并不区分是发送还是接收,所以需要你自己通过这个值来区分上次是调用了WSARecv还是WSASend。
2、如果第 1 步用 PostQueuedCompletionStatus() 的话就不存在这个问题,当然是 GetQueuedCompletionStatus 后的 WSARecv()。
3、同意楼上的。
PostQueuedCompletionStatus好像是在停止完成端口时才使用的啊?
(DWORD)hUser, 0))
{
InterlockedDecrement(&m_nCurrentUsers);
closesocket(sock); // 无法分配完成端口,将新创建的放入空闲列表
EnterCriticalSection(&m_FreeLocker);
hUser->socket = INVALID_SOCKET;
hUser->pNextIOCP = m_FreeLister;
m_FreeLister = hUser;
LeaveCriticalSection(&m_FreeLocker); return;
} // 添加到用户列表
EnterCriticalSection(&m_UsedLocker);
if (m_UsedLister != NULL) {
m_UsedLister->pPrevIOCP = hUser;
}
hUser->pNextIOCP = m_UsedLister;
hUser->pPrevIOCP = NULL;
m_UsedLister = hUser;
LeaveCriticalSection(&m_UsedLocker); // 通知线程池
POVERLAPPEDPLUS pOverlap = CreateOverlappedPlus(IOAccept);
if (pOverlap == NULL) { OnFDClose(hUser, NULL); return; }
BOOL bSuccess = PostQueuedCompletionStatus(m_hIOPort, 0,
(DWORD)hUser, &pOverlap->m_ol);
if ((!bSuccess && GetLastError( ) != ERROR_IO_PENDING)) {
OnFDClose(hUser, NULL);
DestroyOverlappedPlus(pOverlap);
return;
}
WSABUF DataBuf;
CHAR Buffer[DATA_BUFSIZE];
这两个有什么区别和用处吗?ZeroMemory(&(PerIoData->Overlapped),sizeof(OVERLAPPED));
PerIoData->DataBuf.len = DATA_BUFFER_LEN;
PerIoData->DataBuf.buf = PerIoData->Buffer;//不明白这一句,PerIoData->Buffer中是什
//么?
PerIoData->OperationType = RECV_POSTED;WSARecv(PerHandleData->Socket,
&(PerIoData->DataBuf),1,&RecvBytes,
&Flags,&(PerIoData->Overlapped),NULL);
int cmd = 120;
int ID=100;
int port=110;
m_pClientSocket->Send(&cmd,sizeof(int));
m_pClientSocket->Send(&ID,sizeof(int));
m_pClientSocket->Send(&port,sizeof(int));那server端的接收应该怎么写呢?
while(1)
{
GetQueuedCompletionStatus(CompletionPort, &BytesTransferred,
(LPDWORD)&PerHandleData, (LPOVERLAPPED *) &PerIoData, INFINITE); ......if(PerIoData->OpType == otRecv){
//怎么把剩下的2个接收下来?是调用两次WSARecv吗?我试了,好像不对!
}
}
AfxMessageBox(PerIoData->DataBuf.buf);
PerIoData->BytesRECV = BytesTransferred; Flags = 0;
ZeroMemory(&(PerIoData->Overlapped),sizeof(OVERLAPPED));
PerIoData->DataBuf.len = DATA_BUFSIZE;
PerIoData->DataBuf.buf = PerIoData->Buffer;
PerIoData->OpType = otRecv; WSARecv(PerHandleData->Socket,&(PerIoData->DataBuf),1,&RecvBytes,
&Flags,&(PerIoData->Overlapped),NULL);}
不会吧,不可能每次都是这样啊?
if(PerIoData->OpType == otRecv){
char* c=PerIoData->DataBuf.buf;
CIOCPtestApp *pApp = (CIOCPtestApp*)AfxGetApp();
::SendMessage(pApp->m_DlghWnd,WM_RECV_DATA,0,(LPARAM)c);
PerIoData->BytesRECV = BytesTransferred; Flags = 0;
ZeroMemory(&(PerIoData->Overlapped),sizeof(OVERLAPPED));
PerIoData->DataBuf.len = DATA_BUFSIZE;
PerIoData->DataBuf.buf = PerIoData->Buffer;
PerIoData->OpType = otRecv;
WSARecv(PerHandleData->Socket,&(PerIoData->DataBuf),1,&RecvBytes,
&Flags,&(PerIoData->Overlapped),NULL);}
为什么不管client发几个数据包,server只能收到前2个数据包,后面都收不到?
[email protected]
不过这个问题我已经解决了,确实如你所说后两个数据被一次收了下来。我现在的解决办法如下:
if(PerIoData->OpType == otRecv)
{
char* c=PerIoData->Buffer;
CIOCPtestApp *pApp = (CIOCPtestApp*)AfxGetApp();
PerIoData->BytesRECV = BytesTransferred; int i=0;
while(BytesTransferred>0){//将收到的数据全部处理掉
CopyMemory(c,PerIoData->Buffer+4*i,4);
::SendMessage(pApp->m_DlghWnd,WM_RECV_DATA,0,(LPARAM)c);
BytesTransferred -= 4;
i++;
}
Flags = 0;
ZeroMemory(&(PerIoData->Overlapped),sizeof(OVERLAPPED));
PerIoData->DataBuf.len = DATA_BUFSIZE;
PerIoData->DataBuf.buf = PerIoData->Buffer;
PerIoData->OpType = otRecv; if(WSARecv(PerHandleData->Socket,&(PerIoData->DataBuf),1,&RecvBytes,
&Flags,&(PerIoData->Overlapped),NULL) == SOCKET_ERROR)
{
if(WSAGetLastError() != ERROR_IO_PENDING){
CString s;
s.Format("WSARecv() failed with error %d\n", WSAGetLastError());
AfxMessageBox(s);
return 0;
}
}
}不过这样给我的处理带来一些不便,另外我发现这样在接收int型的数据时有问题,数字太大了接收时就不对了,超过256,接收端就等于cmd%256?怎么解决啊?
... int val;
int i=0;
while(BytesTransferred>0){//将收到的数据全部处理掉
val = *(int*)(PerIoData->Buffer + 4 * i);
// 不要用 SendMessage,改为用 PostMessage
// ::SendMessage(pApp->m_DlghWnd,WM_RECV_DATA,0,(LPARAM)c);
::PostMessage(pApp->m_DlghWnd, WM_RECV_DATA, 0, (LPARAM)val);
BytesTransferred -= 4;
i++;
}
...// 显示时
CString str;
str.Format("%d", lParam);
ListBox_AddString(str);