当客户端主动发送数据给服务端的时候, 客户端采用winsock 提供的几个模型,反而不对, 是否放弃模型, 而采用堵塞的套接字 去发送数据 较为合适呢////////////////////////////////////////////////////////////////////////异步事件,异步选择等模型, 无论是来自网络,还是书本提供的例子,没有一个例子是客户端采用模型的。 原因或许:模型特点决定的。如:异步选择模型,当某个消息发生的时候,那么再进行相应的动作。常见的消息有:FD_ACCEPT,  FD_READ ,前者是接受客户端的连接, 后者是接受与之通信的主机发送来的数据,这个消息就会产生。
而消息FD_WRITE 如何产生呢?  书本似乎都没有提到过,涉及过。
对于异步事件模型也是同一个道理,调用了WSAWaitForMutipleEvents,  WSAEnumNetWorkEvents 等函数后,才能够确定 具体的何种消息。 附一个片段:
  while(TRUE)
{
// 在所有事件对象上等待
int nIndex = ::WSAWaitForMultipleEvents(nEventTotal, eventArray, FALSE, WSA_INFINITE, FALSE);
// 对每个事件调用WSAWaitForMultipleEvents函数,以便确定它的状态
nIndex = nIndex - WSA_WAIT_EVENT_0;
for(int i=nIndex; i<nEventTotal; i++)
{
nIndex = ::WSAWaitForMultipleEvents(1, &eventArray[i], TRUE, 1000, FALSE);
if(nIndex == WSA_WAIT_FAILED || nIndex == WSA_WAIT_TIMEOUT)
{
continue;
}
else
{
// 获取到来的通知消息,WSAEnumNetworkEvents函数会自动重置受信事件
WSANETWORKEVENTS event;
::WSAEnumNetworkEvents(sockArray[i], eventArray[i], &event);
if(event.lNetworkEvents & FD_ACCEPT) // 处理FD_ACCEPT通知消息
{
if(event.iErrorCode[FD_ACCEPT_BIT] == 0)

这个代码片段说明了FD_ACCEPT ,FD_READ 产生的原因,是有连接,或者有数据发送给我,所以才有相应的事件产生了。但是  FD_WRITE 到底是如何产生的呢?        该在什么地方调用send函数发送数据让其产生 FD_WRITE 事件呢?似乎,没有地方可以调用。
是否可以得出一个结论:网络编程中, 异步选择,异步事件等各种模型只能用于服务端,客户端不能使用

解决方案 »

  1.   

    邮箱地址告诉我 给你发个异步事件模型吧FD_WRITE  至于这个消息,要看你是否绑定了此消息说明:FD_ACCEPT ,FD_READ 是系统帮忙触发的事件,
    那么我们应该自己设置好参数后(参数应该包括:事件句柄和对应的发送缓存)
    之后给指定的事件句柄发送事件即可如果是客户端的话 使用 异步+窗口模型比较容易理解服务器吗  使用 异步 + 事件 还是可以的
      

  2.   

    高手,我和你说, 客户端:异步+窗口 ,问题很多,  比如:我现在提出一个需求来,你采用窗口的, 就会遇到无穷的问题了。 客户端不仅仅要和服务器通信,保持着联系。而且要与其他客户端进行文件传输, 此时 窗口+异步 很是苦难,无法胜任。为何呢?1. 客户端需要主动发送数据给服务器,主动,FD_WRITE 尽管你可以而注册,但是 谁触发?你说系统触发, 系统触发也是需要条件的!!!  如果永远,不主动去调用send之类的函数怕是永远不触发了。2. 客户端一旦要和其他客户端进行传输文件,此时又要开辟线程, 这个是自然的,毫无疑问的。如果采用窗口,1个窗口就和多个套接字捆绑了。 不知道行不行。但是第1点是比较致命的。所以我在怀疑:所谓io模型,是用来解决服务器的, 而客户端不能用之。这是多谢
      

  3.   


    给我发一个行吗,最近我也在看i/o接口模型 [email protected]  谢谢了
      

  4.   


     5. FD_WIRTE事件的作用?一直搞不懂 WSAEventSelect 的 FD_WRITE ,不知道怎么利用他在自己想发数据的时候发数据,后来知道了想发随时发消息 要自己另外去写send方法,FD_WRITE 是用于一开始连接成功侯就开始发送大批量数据的,比如发一个视频连接给别人 ,别人接了 那么这个时候就触发了FD_WRITE ,视频的数据会不停的充满缓存,所以FD_WRITE会不停的触发因为没人教我 只能靠自己苦苦参悟了 希望别的朋友也能看到我的文字,不要 去被 FD_WRITE 烦恼了  想自己随时发数据的时候 ,自己另外去写send方法 如果你不是一次性发送大批量数据的话,就别想着使用FD_WRITE事件了,因为如果既希望于在收到FD_WRITE的时候发送数据,但是又不能发送足够多的数据填满socket缓冲区的话,就只能收到刚刚建连接的时候的第一次事件,之后及不会再收到了,所以当只是发送尽可能少的数据的时候,忘掉FD_WRITE机制,在任何想发送数据的时候直接调用send发送吧。 
    以上是来自网络, 说明 客户端采用模型是错误的,                客户端的需求如果是要主动发送数据,那么 采用模型是无法完成的。
      

  5.   

    客户端的确不需要什么模型,但要开个线程,弄个buffer,比如list,业务层把消息push到list,线程从list里取出消息,阻塞调用send函数发送消息即可。这种方法,不会有任何效率损失,你用个模型说不定还更慢。
    模型是解决多连接大吞吐量的。FD_WRITE如何发生,我还真没研究过(我猜测它是边界触发的,跟linux下的epoll模型的ET模式差不多,即缓存可写的时候,发送一次FD_WRITE消息,然后直到缓存变满,再变为不满时,又发送一次,否则就会不停的收到FD_WRITE消息了,你已经看到了,很麻烦,你要自己缓存缓存的可写状态),因为它就只在异步选择模式中使用,这种模型都是用于配合窗口程序使用的,我从来没用过,我觉得把网络与窗口结合起来,不是好的设计。其实标准模型,只有一个,那就是select模型,其它都是mfc扩展出来的,包括iocp。其它模型(除了异步IO,包括重叠IO和IOCP),如何知道可写,相信你没问题了吧,因为它们都是查询式的,比如select模型,什么时候触发可写状态呢,就是你调用select之后,其它模型也一样,比如WSAWaitForMultipleEvents。我建议客户端,简单处理,开两个线程,分别阻塞读和写,没有任何效率损失的,反而比模型更快。其实服务端,你别看它采用了多么复杂的模型,其它就看单个连接上的数据发送接收速度,是不如阻塞读写方式的。它只是大吞吐量,大吞吐量不代表在单个连接上速度快,这是两回事。
      

  6.   


    我来总结下:当一个套接字连接被建立上时(包括客户端的connect(),connectex()等和服务器端的accept接收到后创建的新套接字),这时会触发FD_WRITE,以后就可以用send(),WSASend()发送数据了.如果以后发送正常的话,将不会再触发FD_WRITE.如果发送数据不正常的话,即用send(),WSASend()等发数据,WSAGetLastError()返回WSAEWOULDBLOCK错误,那么等到系统缓冲可再发送数据时,就会触发FD_WRITE.

    以上是经典老帖中  搜索到的。如果采用异步选择,异步事件模型, 应用于客户端中,问题很多。无法解决:客户单主动隔几秒钟发送数据的需求。弃之不用.
      

  7.   

    如果用异步IO,就是带个重叠结构的方法,阻塞与非阻塞并无根本区别,还是想发发,想收收;
    如果你阻塞send(包括用空的重叠结构调用WSA形状的方法,此时也是非异步的),则FD_WRITE无用,因为就算你收到FD_WRITE,也不代表你就能不阻塞的send(原因很简单,你只知道可写,但不知道写多少,所以同样可能会阻塞);
    如果你用非阻塞非异步写,当缓存写满之后,结过一段时间,缓存重新变得可用时,你肯定还会收到FD_WRITE,这就是所谓的边界触发模式;很少有在异步事件中关注FD_WRITE的,其它模型中,读事件也少见,此事件基本上必须要求非阻塞式(否则的话,你用了模式之后,还是要阻塞写,那还不如不用呢)。
    总之,要么多线程阻塞读写(特别是写),要么异步IO(包括重叠IO和iocp),其它的都用起来很不爽。
      

  8.   

    你概念有点混淆
    事件驱动模型,本质就是一个大while,每轮循环都是等待某个事件到达,然后针对事件类型做相应处理。可以同时等待的事件非常多,包括定时器、窗口消息、网络数据、互斥体信号量等等。整个while就是该线程函数的主体,只要每次事件处理逻辑不是特别复杂很拖时间以致影响下一个事件接收处理的及时性,一个主线程跑while就足够了,完全不需要多线程。
    就你上面的例子,每个客户端做完初始后,就可进入等待状态,比如最开始只有一个等待对象即窗口消息,用户操作后连上服务器,其实就是把服务器socket添加到了等待集合中,之后开始等待两类事件 ,然后在某帧里收到服务器命令,要求与其它客户端直连,这时无非是把那个客户端的socket再添到等待集合里,下一帧开始等待三类事件而已。
      

  9.   

    MSDN上说明了FD_WRITE激发的条件:
    FD_WRITE: 
    a. When WSAAsyncSelect called, if a send or sendto is possible. 
    b. After connect or accept called, when connection established. 
    c. After send or sendto fail with WSAEWOULDBLOCK, when send or sendto are likely to succeed. 
    d. After bind on a connectionless socket. FD_WRITE may or may not occur at this time (implementation-dependent). In any case, a connectionless socket is always writeable immediately after a bind operation. 
      

  10.   

    在客户端开发中,没有使用过异步发送
    数据量小就直接发
    数据量大就先保存,顺着发
    注意判断是否发完就好了(send返回是否和需要发送字节数相同)
      

  11.   

    19楼是我在TCP下的实现方法
    如果使用UDP且网络QOS要求较高
    需处理乱序、丢包、拥塞控制、流量控制等个人浅见,仅供参考