开发服务器端程序时,调用WSAAsyncSelect将套接字设置为异步非阻塞,服务器端和客户端的通讯是客户端先向服务器端发送一组数据,服务器给客户端回复一组数据,就这样反复执行。//消息响应函数
...
case   FD_READ:     //网络数据包到达事件   
  {   
  OnReceive(CurSock);   
  break;   
  }   
 case   FD_WRITE:     //发送网络数据事件   
  {   
  OnSend(CurSock);   
  break;   
  }
...我的设想是调用OnReceive接收数据后后马上传递给OnSend函数进行处理,处理完后OnSend函数将处理后的数据发送给客户端。可是我怎么控制OnReceive和OnSend的执行顺序啊?
FD_READ事件是当对方发送数据过来后就应该自动触发的,FD_WRITE是怎么触发的?按我的情况,最好响应FD_READ事件后响应FD_WRITE事件。请高手给指点迷津。还有个小问题,使用WSAAsyncSelect将socket设置为异步非阻塞模式后,还能用send吗?还是必须用WSASend?

解决方案 »

  1.   

    FD_WRITE事件是socket已经准备好了,你可以调用send了,这个时候触发的,如果未收到这个消息就调用send会失败。你可以定义两个信号量,假设为HasData和ReadyToSend,OnReceive中检查如果ReadyToSend被设置则调用OnSend并清除该信号,否则设置HasData信号;FD_WRITE中检查如果HasData被设置则调用OnSend并清除该信号,否则设置ReadyToSend信号。因为这些操作都是单线程,所以使用信号量即可,不必使用同步对象。
      

  2.   

    补充一下FD_WRITE只会触发一次
      

  3.   

    FD_WRITE只会触发一次?我试试。
      

  4.   

    FD_WRITE事件是socket已经准备好了,你可以调用send了,这个时候触发的,如果未收到这个消息就调用send会失败。
    ///那也就是说当我接收到数据后,直接调用send是不行的了?case FD_READ:  //网络数据包到达事件       
    {       
        OnReceive(CurSock);  
        send();               //直接发送数据 
        
        break;       
    } 给我的感觉是基于消息的异步模式下,FD_READ和FD_WRITE事件都是被动触发的,就是只有FD_READ和FD_WRITE事件被触发了,才可以发送和接收数据。那如果我在对话框中加一个按钮,希望点击按钮后,就能发送出去一条数据,该怎么做?又或者我希望服务器端周期性的发送数据给客户端,又该怎么实现?
      

  5.   

    FD_WRITE感觉用处不太大,你要发送数据的时候,直接SEND就可以了
      

  6.   

    FD_WRITE感觉用处不太大,你要发送数据的时候,直接SEND就可以了
    ///
    FD_WRITE事件是socket已经准备好了,你可以调用send了,这个时候触发的,如果未收到这个消息就调用send会失败。 
    ////以上两种说法究竟哪种是正确的?
      

  7.   

    都是正确的因为,FD_WRITE只会触发一次假如你connect之前使用,WSAAsyncSelect
    那么你就会先收到FD_CONNECT,紧接着,是FD_WRITE
    以后就再也不会收到FD_WRITE,所以说 连接成功之后就可以随便发数据了.在你未收到FD_WRITE的时候 调用Send肯定会失败.
      

  8.   

    我在1楼提的做法有误,FD_WRITE是在连接建立或者发送数据失败返回WSAEWOULDBLOCK之后,socket准备就绪后触发的。所以一般情况下你可以直接send,如果send失败且返回WSAEWOULDBLOCK时可以再次等待FD_WRITE事件。你可以在OnReceive接收数据后立即send,如果send失败且错误码是WSAEWOULDBLOCK时,把要发送的数据挂起,并做一个标记,在响应FD_WRITE事件时判断这个标记发送数据。
      

  9.   

    FD_WRITE在两种情况下被触发
    1.如果socket跟远程目标连接上后(connect()或connectEx()等),就会触发到FD_WRITE(如果socket在调用connect()等API前就将FD_WRITE用WSAAsyncSelect()设置了的话)
    2.当socket有数据要发送,而且系统缓冲有空闲位置让你发数据(一般情况下是发送数据,但WSAGetLastError()返回WSAEWOULDBLOCK错误,说明系统缓冲已满,当系统缓冲有位置可发送数据后,就会触发FD_WRITE)
      

  10.   

    "都是正确的因为,FD_WRITE只会触发一次 假如你connect之前使用,WSAAsyncSelect 
    那么你就会先收到FD_CONNECT,紧接着,是FD_WRITE 
    以后就再也不会收到FD_WRITE,所以说   连接成功之后就可以随便发数据了. 在你未收到FD_WRITE的时候   调用Send肯定会失败."上面说法是有问题的.FD_WRITE不会只触发一次,可以是很多次.只要用send(),WSASend()等发数据,WSAGetLastError()返回WSAEWOULDBLOCK错误,那么等到系统缓冲可再发送数据时,就会有FD_WRITE被触发.
      

  11.   

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