重叠I/O模型中的疑问,熟悉的朋友请进来看看!

tangmasi 2003-08-20 05:14:51
使用这个模型的一般化方式是先调用I/O请求,如WSARecv()和WSASend(),然后WaitForMultipleObject()等待事件完成的通知,响应通知完成处理后再进行下一次的I/O调用。

现在我的I/O调用是由用户驱动的,就是说只有在用户发出请求时才调用WSARecv()WSASend()。改怎样使用这个模型才合理。

请大家帮忙看看。多谢了。
...全文
90 31 打赏 收藏 转发到动态 举报
写回复
用AI写文章
31 条回复
切换为时间正序
请发表友善的回复…
发表回复
xiaohyy 2003-08-24
  • 打赏
  • 举报
回复
我有以一点不明白,大家都说重叠模型的效率高,到底高在什么地方??给我的感觉好像是16位时代的产物,当时没有多线程机制。

我理解的很肤浅,大家多多指教哈。活活
tangmasi 2003-08-24
  • 打赏
  • 举报
回复
噢。楼上的辛苦了。我希望找个人给我解释一下原理。倒不是需要具体的代码。不管怎么说,我还是会看看,谢谢啦。
zhouyong0371 2003-08-24
  • 打赏
  • 举报
回复
bool PeerSendDataS(SOCKET socket,char *data,DWORD len,DWORD *retlen,WSAEVENT hSendEvent,DWORD time)
{
DWORD left,idx,thisret;
left=len;
idx=0;
int oflag=0;
while(left>0)
{
if(!PeerSendData(socket,&data[idx],left,&thisret,hSendEvent,time))
{
*retlen=0;
return false;
}
WSAResetEvent(hSendEvent);
left-=thisret;
idx+=thisret;
if(thisret==0)
{
oflag++;
if(oflag>5)
break;
}
}
*retlen=idx;
return (idx==len)?true:false;
}

//重叠模式发送数据
bool PeerSendData(SOCKET socket,char *data,DWORD len,DWORD *retlen,WSAEVENT hSendEvent,DWORD time)
{
WSABUF DataBuf;
WSAEVENT hEvents[2];
WSAOVERLAPPED SendOverLapp;
DWORD flag;

hEvents[0]=hExitEvent; //程序的结束事件
hEvents[1]=hSendEvent; //Socket事件
DataBuf.buf=data;
DataBuf.len=len;
memset(&SendOverLapp,0,sizeof(WSAOVERLAPPED));
SendOverLapp.hEvent=hSendEvent;
flag=0;
/////////////////////////////////////
int ret;
if((ret=WSASend(socket,&DataBuf,1,retlen,flag,&SendOverLapp,NULL))==0)
return true;
else if((ret==SOCKET_ERROR)&&(WSAGetLastError()==WSA_IO_PENDING))
{
DWORD EventCaused=WSAWaitForMultipleEvents(2,hEvents,FALSE,time,FALSE);
WSAResetEvent(hSendEvent);
if(EventCaused == WSA_WAIT_FAILED || EventCaused == WAIT_OBJECT_0)
{
if(EventCaused == WAIT_OBJECT_0)
SetLastError(PEER_FUNERROR);
return false;
}
flag=0;
return WSAGetOverlappedResult(socket,&SendOverLapp,retlen,false,&flag)?
true:false;
}
else
return false;
}

zhouyong0371 2003-08-24
  • 打赏
  • 举报
回复
bool PeerRecvDataS(SOCKET socket,char *data,DWORD len,DWORD *retlen,WSAEVENT hRecvEvent,DWORD time)
{
DWORD left,idx,thisret;
left=len;
idx=0;
int oflag=0;
while(left>0)
{
if(!PeerRecvData(socket,&data[idx],left,&thisret,hRecvEvent,time))
{
*retlen=0;
return false;
}
WSAResetEvent(hRecvEvent);
left-=thisret;
idx+=thisret;
if(thisret==0)
{
oflag++;
if(oflag>5)
break;
}
}
*retlen=idx;
return (idx==len)?true:false;
}

//重叠模式接受数据
bool PeerRecvData(SOCKET socket,char *data,DWORD len,DWORD *retlen,WSAEVENT hRecvEvent,DWORD time)
{
WSABUF DataBuf;
WSAEVENT hEvents[2];
WSAOVERLAPPED RecvOverLapp;
DWORD flag;

hEvents[0]=hExitEvent; //程序的结束事件
hEvents[1]=hRecvEvent; //Socket事件
DataBuf.buf=data;
DataBuf.len=len;
memset(&RecvOverLapp,0,sizeof(WSAOVERLAPPED));
RecvOverLapp.hEvent=hRecvEvent;
flag=0;
/////////////////////////////////////
int ret;
if((ret=WSARecv(socket,&DataBuf,1,retlen,&flag,&RecvOverLapp,NULL))==0)
return true;
else if((ret==SOCKET_ERROR)&&(WSAGetLastError()==WSA_IO_PENDING))
{
DWORD EventCaused=WSAWaitForMultipleEvents(2,hEvents,FALSE,time,FALSE);
WSAResetEvent(hRecvEvent);
if(EventCaused == WSA_WAIT_FAILED || EventCaused == WAIT_OBJECT_0)
{
if(EventCaused == WAIT_OBJECT_0)
SetLastError(PEER_FUNERROR);
return false;
}
flag=0;
return WSAGetOverlappedResult(socket,&RecvOverLapp,retlen,false,&flag)?
true:false;
}
else
return false;
}

zhouyong0371 2003-08-24
  • 打赏
  • 举报
回复
bool PeerRecvDataS(SOCKET socket,char *data,DWORD len,DWORD *retlen,WSAEVENT hRecvEvent,DWORD time)
{
DWORD left,idx,thisret;
left=len;
idx=0;
int oflag=0;
while(left>0)
{
if(!PeerRecvData(socket,&data[idx],left,&thisret,hRecvEvent,time))
{
*retlen=0;
return false;
}
WSAResetEvent(hRecvEvent);
left-=thisret;
idx+=thisret;
if(thisret==0)
{
oflag++;
if(oflag>5)
break;
}
}
*retlen=idx;
return (idx==len)?true:false;
}

//重叠模式接受数据
bool PeerRecvData(SOCKET socket,char *data,DWORD len,DWORD *retlen,WSAEVENT hRecvEvent,DWORD time)
{
WSABUF DataBuf;
WSAEVENT hEvents[2];
WSAOVERLAPPED RecvOverLapp;
DWORD flag;

hEvents[0]=hExitEvent; //程序的结束事件
hEvents[1]=hRecvEvent; //Socket事件
DataBuf.buf=data;
DataBuf.len=len;
memset(&RecvOverLapp,0,sizeof(WSAOVERLAPPED));
RecvOverLapp.hEvent=hRecvEvent;
flag=0;
/////////////////////////////////////
int ret;
if((ret=WSARecv(socket,&DataBuf,1,retlen,&flag,&RecvOverLapp,NULL))==0)
return true;
else if((ret==SOCKET_ERROR)&&(WSAGetLastError()==WSA_IO_PENDING))
{
DWORD EventCaused=WSAWaitForMultipleEvents(2,hEvents,FALSE,time,FALSE);
WSAResetEvent(hRecvEvent);
if(EventCaused == WSA_WAIT_FAILED || EventCaused == WAIT_OBJECT_0)
{
if(EventCaused == WAIT_OBJECT_0)
SetLastError(PEER_FUNERROR);
return false;
}
flag=0;
return WSAGetOverlappedResult(socket,&RecvOverLapp,retlen,false,&flag)?
true:false;
}
else
return false;
}

farfh 2003-08-24
  • 打赏
  • 举报
回复
大概不是效率的问题吧?我也不清楚,只是有一点是肯定的,所有的操作都在一个地方等待完成。所有的发送和接收操作都没有阻塞的问题。比如你用select,就没这个好处。其他嘛,俺倒没发现有任何好处^_^(我也编程新手,刚毕业,呵呵)
joinrry 2003-08-22
  • 打赏
  • 举报
回复
tangmasi(汤玛斯) 应该是理解错误。

WaitForMultipleObject(),是等待网络事件或者系统消息事件。
协议缓冲里面有数据的时候会触发。

而所谓的异步或者阻塞。是说所谓的socket操作同步问题。如:
Recv()、Send()、Close()、Accept()等等
farfh 2003-08-22
  • 打赏
  • 举报
回复
那就只有等WSAWaitForMultipleEvents返回了,如果你一直在等的话,多半也不成,最好设置一个等待时间,或者另开一个线程对该套节字进行操作(不过我觉得没必要),我不知道能否将多个操作叠加到一个套节字上,不过我想应该是成的(完成端口可以)。
一般说来,一个套节字应该非常清楚的知道自己首先应该RECV还是SEND,一般服务器都是直接RECV,如果你RECV超时,你可以认为网络延时了,至于怎么处理,那就不好说了。一般说来,服务器和客户的通信都定义有自己的一套规则吧?没有道理出现你说的那中RECV超时又需要SEND的情况,如果出现了这种情况,多半是你设计上有问题,否则RECV要么出错,要么就成功。至于系统是否能够正确接收到该套节字的消息,最好你另外开线程检测了。
tangmasi 2003-08-22
  • 打赏
  • 举报
回复
to farfh(慕容长风):
刚好你在。呵呵,多谢了。

WaitForMultipleObject()操作只是检查该操作是否完成。比如ACCEPT后你WSARECV一次,则该操作被记录,当有数据到达时候WaitForMultipleObject将会返回,大概就是这个意思吧。

我也差不多是这样理解的。如果始终没有数据到达,这个时候WSAWaitForMultipleEvents()是不是就始终不会返回或者报告这个套接字的状态呢?
我如果现在想使用这个套接字来发送数据怎么办?
tangmasi 2003-08-22
  • 打赏
  • 举报
回复
我记错了,前面说的WaitForMultipleObject()实际上应该是WSAWaitForMultipleEvents()。
tangmasi 2003-08-22
  • 打赏
  • 举报
回复
joinrry(骑着小猪去流浪) 说得好,似乎有点点醒我了。给分算你一份。

WaitForMultipleObject()用法可能真的是我理解错了。我再看看去。

或者谁能帮忙把这个模型解释清楚。
farfh 2003-08-22
  • 打赏
  • 举报
回复
WSAWaitForMultipleObject可以自定义超时,用法如下:
index=WSAWaitForMultipleEvents(1,
&pThis->m_hListenEvent,
FALSE,
60000,//waitting for 1 minute
FALSE);
详细用法可以看看MSDN,俺一时也说不清楚^_^
farfh 2003-08-22
  • 打赏
  • 举报
回复
看这么多人讨论,我今天早上就去翻了一下重叠IO的一点资料,大概了解了一下。
我就来说一下流程,楼主可以去实验一下,呵呵,我随便讲的,没做过哈,不对别丢我鸡蛋。
对于LISTEN后的套节子而言,首先ACCEPT,如果成功,则返回套节字,而WSARECV和WSASEND只是将发送和接收消息发送到重叠IO的队列里面去,也就是说,该操作也是永远不会超时的,只有失败和成功的可能。WaitForMultipleObject()操作只是检查该操作是否完成。比如ACCEPT后你WSARECV一次,则该操作被记录,当有数据到达时候WaitForMultipleObject将会返回,大概就是这个意思吧。WSASEND应该也是同样的道理。
楼主可以自行实验一下,看看偶说的是否正确,:)
另外建议楼主使用重叠IO的时候使用回调函数来处理,这样的话,应该说比使用WaitForMultipleObject来得容易和好处理一些。
phalcon 2003-08-22
  • 打赏
  • 举报
回复
mark
xiaohyy 2003-08-22
  • 打赏
  • 举报
回复
mark
tangmasi 2003-08-21
  • 打赏
  • 举报
回复
但是重叠I/O好像不是这样的啊。它应该是先调用如WSARecv(),然后WaitForMultipleObject()等待事件完成的通知。如果另一端没有数据发送的话,WaitForMultipleObject()就一直不会返回。
fang_jb 2003-08-21
  • 打赏
  • 举报
回复
同意smch(Ashes Of Time)的
用WSAAsyncSelect来做才是正确的,因为你的server端是被动的,所以监视这个端口上的读写连接退出事件是必要的
tangmasi 2003-08-21
  • 打赏
  • 举报
回复
to smch:
谢谢你了。只是我现在是在使用overlapped i/o模型,并且也打算使用该模型来做服务器管理多个套接字。看看书和例子似乎很明白,但实际使用的时候却又有些迷惑了,我使用WSARecv()万一收不到任何东西它是不是只有等到超时才会返回,超时时间自己能设定吗?
smch 2003-08-21
  • 打赏
  • 举报
回复
异步方式不是你一直recv.而是有数据可以接收的时候Windows通过自定义消息通知你的程序。你再去接收。就如我上面的代码。

如果你一次没有接收完,操作系统还会继续发消息。
smch 2003-08-21
  • 打赏
  • 举报
回复
farfh(慕容长风) 说的对。永远不会超时的。
重叠I/O和异步/同步不是互相排斥的。
加载更多回复(11)

18,356

社区成员

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

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