本帖最后由 passswords 于 2009-06-10 14:26:14 编辑

解决方案 »

  1.   

    楼上说的没错,对于同一个SOCKET的传输来的数据是不能异步的,异步只是在不同SOCKET之间才能实现
      

  2.   


    lz分3次recv一个完整的包吗?
    服务端(发送端)是如何send的呢?用异步出现接收时包顺序改变的话,可以在自己的这边把包顺序强行改正过来,比如:用指针指向这3个数据包,等全部接收完成,再调整顺序。
      

  3.   

    楼上说不能多次recv的,看来是我没把问题说清楚。整个过程是这样的:原先使用的是基于消息的I/O,不是重叠的I/O;所以用分段截取数据流的方法可以很好的各取所需。当触发了FD_RECEIVE事件,调用其响应函数,在该函数中//处理前先注销FD_READ事件
    if(!AsyncSelect(0))
    {  TRACE0(...);
       retrun;
    }//recv的时候先Receive(&wPackType,sizeof(wPackTYpe),0)接收数据包类型 
    WORD wPackType;
    if(Receive(&WORD wPackType;,sizeof(WORD wPackType;),0)!=sizeof())
    {  TRACE0(...);
    }//然后分析数据包类型并调用相应的处理函数 
    switch(wPackType) 

    case PACKAGE_USERLIST: OnReceiveUserList();break; 
    case ... 
      .      . 
    }     //在 OnReceiveUserList里,先读取列表长度
         Recevice((void*)&len,sizeof(len),0)
        //再根据长度,读取完剩下的数据,//处理完毕,重新注册网络事件
    if(AsyncSelect(FA_READ|FD_CLOSE)
    {
    TRACE0(..);
    retrun;
    }但是对于重叠的操作,这就有问题了。首先,由于我们已经准备好了应用程序的缓冲区,所以,当有数据到达的时候就直接填充应用程序缓冲区,而绕过了该套接字的系统缓冲区。
    接着,所有重叠操作可确保按照应用程序安排好的顺序执行,然而,不能确保从完成端口返回的完成通知也按照上述顺序执行。也就是说,对于两个重叠WSARecv操作,如果一个应用程序提供前者10KB的缓冲,而后者提供12KB的缓冲,则10KB缓冲先被填充,然后12KB缓冲被填充。应用程序的工作线程可能会在10KB操作完成事件之前从GetQueuedCompletionStatus接收到12KB WSARecv的通知,总而言之,由于顺序的不确定。,我们没法象以前那样分段截流了,我看到有些资料说,为提交的读I/O分配序列号,但我想不出该怎么实现,所以来请各位帮帮忙,有其他解决方法更好。不知道这回我把问题说清楚了没。本人表达能力有限,惭愧 -_-!!
      

  4.   


    发送的时候是一次发送,但是MTU的限制,数据可能被分成多个包。接收的时候就会分批到达。
      

  5.   

    “但是换成重叠I/O的话WSARecv的时候由于是重叠的 
    可能会这样收 
          用户个数 ,数据包类型,用户信息 
    也就是说,多个异步读调用的时候,我接收的顺序可能组成错误的封包,这个该怎么解决呢? 为提交的读I/O分配序列号???那又怎么分呢,怎么实现呢?大家帮帮忙呀”不会出现你说的这种情况的,除非,你在接收这3个信息时,创建了3个socket,然后分别wsarecv;如果只是一个socket的话,那么你先wsarecv哪个,结果就是先收到哪个的数据。
    不过一般处理时,对同一个socket,是等wsarecv后,实际接收到数据后,才再一次wsarecv,接收下一个数据包。
    WSAGetOverlappedResult(
    g_CliSocketArr[index],
    &g_pPerIODataArr[index]->overlap,
    &cbTransferred,
    TRUE,
    &g_pPerIODataArr[g_iTotalConn]->Flags);
    参考
    Windows Socket五种I/O模型——代码全攻略(一)(转)
    http://hi.baidu.com/xyh2007/blog/item/7f2ebf3de1e69e07bba1674e.html
      

  6.   

    “应用程序的工作线程可能会在10KB操作完成事件之前从GetQueuedCompletionStatus接收到12KB WSARecv的通知,总而言之,由于顺序的不确定。,我们没法象以前那样分段截流了,我看到有些资料说,为提交的读I/O分配序列号,但我想不出该怎么实现,所以来请各位帮帮忙,有其他解决方法更好。 

    BOOL GetQueuedCompletionStatus(
      HANDLE CompletionPort,
      LPDWORD lpNumberOfBytes,
      PULONG_PTR lpCompletionKey,
      LPOVERLAPPED* lpOverlapped,
      DWORD dwMilliseconds
    );
    这个函数的第四个参数可以指明2次wsarecv的不同,所以如果你所说的12kb的先到达的话,那么也是可以区分的。把这12kb的数据放到你需要放到缓冲区就可以了啊~
      

  7.   

    但是对于重叠的操作,这就有问题了。首先,由于我们已经准备好了应用程序的缓冲区,所以,当有数据到达的时候就直接填充应用程序缓冲区,而绕过了该套接字的系统缓冲区。 
    接着,所有重叠操作可确保按照应用程序安排好的顺序执行,然而,不能确保从完成端口返回的完成通知也按照上述顺序执行。也就是说,对于两个重叠WSARecv操作,如果一个应用程序提供前者10KB的缓冲,而后者提供12KB的缓冲,则10KB缓冲先被填充,然后12KB缓冲被填充。应用程序的工作线程可能会在10KB操作完成事件之前从GetQueuedCompletionStatus接收到12KB WSARecv的通知,总而言之,由于顺序的不确定。,我们没法象以前那样分段截流了,我看到有些资料说,为提交的读I/O分配序列号,但我想不出该怎么实现,所以来请各位帮帮忙,有其他解决方法更好。 
    发送数据的时候,加一个计数段位,就算后12KB先触发,你先在内存缓存,等到相应的数据全接受完了,自己重组。
    这样之后再进行你的后续操作。
      

  8.   

    对于同一个socket通知也是按顺序的
      

  9.   

    我算弄明白了,打个比方:
    封装数据包结构:数据包类型+用户个数+用户信息,当数据发过来以后,这些数据存放到一个缓冲区A里面了。当你的Thread1在用WSARecv读数据的时候,从A里面读取数据,假设读入了数据包类型后,这个时候Thread2也读入数据,那个这个Thread2读入的数据必然是用户个数,而不是用户信息。因为数据包都在A里面,并且当线程读入了数据以后,相应的数据将从A里面删除。你可以把WSARecv想象成原子操作。所以,不会这样收到“用户个数 ,数据包类型,用户信息”这样的数据。