我的一个程序用了WSAEventSelect,模型,发现无法正常工作:
我的Event是用WSACreateEvent建立的,步骤如下:
1、WSAEventSelect(m_hSocket,m_hWaitEvents[0],FD_WRITE | FD_CLOSE)选择事件,
2、WSAWaitForMultipleEvents(sizeof(m_hWaitEvents)/sizeof(HANDLE), m_hWaitEvents,FALSE,m_dwTimeout,FALSE);等待事件
3、WSAEnumNetworkEvents(m_hSocket,m_hWaitEvents[0],&we);判断事件类型
4、send(m_hSocket,(const char *)pData+nSentSize,nSize-nSentSize,0);发送数据
然后我发现下一轮中与Socket相关联的Event再也无法被激活了,非常奇怪!谁能告诉我是那里出了问题啊!急!谢谢了!

解决方案 »

  1.   

    你说的是哪个事件啊?如果是FD_WRITE事件的话,你去参考我的贴子吧。
    http://expert.csdn.net/Expert/topic/1172/1172287.xml?temp=.8762781
      

  2.   

    发了帖子才看到你的帖子,发现问题差不多MSDN里说send可以reenable FD_WRITE事件,但我用的时候却发现根本不行。现在任务紧,线用别的方法做完,再回来一起研究一下。
      

  3.   

    用Send产生FD_WRITE事件,是在Send返回为WSAEWOULDBLOCK的时候。
      

  4.   

    int nRet = WSAEventSelect(m_hSocket1,
      m_hEvent1,
      FD_CONNECT|FD_CLOSE|FD_READ);
    第三个不是可以设置网络事件吗?不要设FD_WRITE就行了
      

  5.   

    To:bind
    这么说我在没有收到WSAEWOULDBLOCK前一直可以发数据?那返回WSAEWOULDBLOCK的那次操作数据会不会发出去?我试过好像是没有发出去。另外有一个百思不得其解的问题,就是socket的发送缓冲区。MSDN说对于异步socket的send如果成功的话,返回值为1-max bytes之间,既然这样,我自然就靠send的返回值来分包了,所以对于传入send的数据大小我并没有限制,结果发现当我发一个16M的数据包时(我用的是内存映射文件的指针),send的返回值居然也是16M,我总觉的这是不可能的事情。系统分配给socket的发送缓冲区我记得就8K,他怎么可能把16M的数据全拷到缓冲里,但事实是send确实很快就返回了,而且对方确实也能收到数据(局域网),谁能帮我解释一下?
      

  6.   

    系统分配给socket的发送缓冲区我记得就8K?呵呵,乱说,tcp每次发送它会根据自己实际情况分成很多个报文段(一般是512字节,1024),每次都是以报文段发送的,等待客户返回一个ack(确认消息)及窗口大小(接收方tcp缓冲区可接收数据的空余空间),你可以找<TCP/IP详解卷1:协议》看
      

  7.   

    嗯, MSDN 的意思是, 不断的 IO(send, recv) 直到返回 WSAEWOULDBLOCK, 才 WAIT EVENT
      

  8.   

    To:yanhuahui(小辉) 
    你说的是TCP层的,我说的是socket层的,两回事。socket还可以不设缓冲,TCP层总不能没有缓冲吧。tcp给自己分配空间总有个限度吧?我如果很多socket同时发送16M的数据包,难道他还都满足啊?To:ttzzgg_80713(别欺侮我) 
    WSAEnumNetworkEvents就有reset的功能了。我的园子早停了,现在虽然也有宽带,不过机子上装的是professional,没法运行SQL和正规的IIS
      

  9.   

    WSAEnumNetworkEvents之后要清除网络事件。下次要用重新设置吧。
      

  10.   

    socket就是tcp层的接口。同时发10M我没试过,单独发30M我成功实验过。
      

  11.   

    发出去了啊!在SEND未返回SOCKET_ERROR之前,所有的数据发送都是正常的。windows网络编程是这样解释的:
    将一个套接字置为非锁定模式之后,WINSOCK API调用会立即返回。在大多数情况下,这些调用都会“失败”,并返回一个WSAWOULDBLOCK错误。什么意思呢?它意味着请求的操作在调用期间没有时间完成。又:若应用程序针对一个套接字调用了WSAASYNCSELECT,那么套接字的模式会从“锁定”自动变成非锁定。
      

  12.   

    To:Bind(天高云淡) 
    那么短的时间不可能全发出去的,我用的是10M网,16M的数据不可能在不到1秒的时间内全部发送出去。而且send返回的也不是什么WSAWOULDBLOCK,而是那16M数据的大小 !!
      

  13.   

    你的担心有点多余了。TCP/IP是支持从容关闭的。在发送方发出关闭请求后,接收方会把未接收完的数据继续接收完再响应这个关闭消息。
      

  14.   

    这个我当然知道,还可以通过设置那个LINGER标志来设定这个选项,只是奇怪系统为什么要把那么大的数据块全部放到缓冲里,不怕撑死啊
      

  15.   

    哪有一次放啊?每次把一部分放入SOCKET缓冲中。大小不超过缓冲区的最大长度。这怎么会撑死呢?
      

  16.   

    我一次send 16M的数据包,半秒内就给我成功返回了,这么短的时间内数据肯定是发不完,那当然是方缓冲里了
      

  17.   

    发送是这样做的:把数据从你的缓冲中拷贝到SOCKET缓冲再发送。如果你的数据太大了,当然要分几次拷贝了。我猜里面是有一个FOR循环式的操作。
      

  18.   

    MSDN上说异步send如果成功的话,返回值在1-max size之间,也就是说,send内部应该没有那个循环来保证所有的数据全部发送出去
      

  19.   

    讨论这个问题就比较难了。不管send内部如何操作,我们只需关心它的返回值就行了。总之大于0就是发送成功小于0就是失败。
      

  20.   

    呵呵,16M?是的,send真的把16M“一次”发出去了,不知道你用的机器是不是2000, 如果是的话可以细心的看看system tray里你的网络适配器的状态,它应该是不继地亮着的也就是说你的send正在发送数据。
    当你用send发送数据时,winsock dll会新建一个thread为你进行数据的发送操作,一次把16M的数据投到send里头,thread就会一点点的慢慢发,但send就马上返回,如果你再一次send的话,应该你会收到WSAWOULDBLOCK的错误,因为winsock(不是TCP/IP传输层)的thread还没发完啊,发完后才会收到FD_WRITE。
    在用DEBUG版本的程序结束运行后没发现在output里的thread exit code 多了好几个吗?
      

  21.   

    对于send返回发送数据的大小的这个问题, 我也感到很困惑, 它要不就WSAWOULDBLOCK,要不就是整个数据区的大小。好像没必要我们去进行数据分段了。但我又想send是从unix系统继承过为的东西,微软也说过unix上开发的这种通信程序在理论上是可以不用修改就能移植到Windows上的。那么windows上的一套winsock函数都是与unix的一模一样。可能在unix系统blocking状态下的socket在send时就会有返回一部分数据区长度的机会,需要进行分段处理。但在Windows异步机制下的socket send始终是整个数据区大小或WSAWOULDBLOCK。以上是只是我的猜测,反正我做程序时都进行了分段处理了。
      

  22.   

    返回整个BUFFER的长度是一种理想状态。不妨在拨号的环境下调试绝对会出现返回值小于BUFFER长度的情况出现。所以分段处理是必要的。
      

  23.   

    没有啊,我的程序就是在拨号环境下调试的。我的程序运行环境是2000 prof,是不是,2000 下就不用分段。
      

  24.   

    我用的是2000
    关于JJONY() 的猜测:当你用send发送数据时,winsock dll会新建一个thread为你进行数据的发送操作。socket应该不会再去建线程了吧?那样一个send还要再建一个线程开销太大了,不过系统应该是把它放到一个缓冲里了,我很奇怪系统为什么要这么处理