在IOCP模型中,如果要同时处理大量的并发连接,网上说最好是使用 AcceptEx函数,并且用一个单独的线程来负责,所有的连接。我始终不知道如何去将用户的I/O和Connect分开。哪位能给一个简单代码的例子,感激不尽如果服务器使用IOCP模型,那么客户端是否一定要使用 WSASend函数,才能发送数据,是否可以使用 send函数。目前公司正要开发一个网络的程序,欢迎关于网络方面的朋友根我讨论,
Skype账号是 magicknife.prince
msn 账号是 [email protected]

解决方案 »

  1.   

    "如果服务器使用IOCP模型,那么客户端是否一定要使用 WSASend函数,才能发送数据,是否可以使用 send函数。"
    不是,客户端怎么会要知道服务器是怎么实现的?这是荒谬的!!使用 AcceptEx 和使用 WSASend 一样,调用以后,在调用 GetQueuedCompletionStatus 线程中如果是得到 AcceptEx 的响应,则说明连接已经完成。可以同时调用多个 AcceptEx 以增加同时接收连接的能力 -- 要保持这种能力请记住,当有一定连接完成时,要调用相应的 AcceptEx 去弥补这种能力
      

  2.   

    你的意思是说,服务器使用异步IOCP,客户端可以直接发送数据使用send对吧? 那么我有一点不明白了。因为在 GetQueuedCompletionStatus 函数,有第4个参数,使一个自定义的结构,用来关联缓冲的,那么如果使用 send函数,如何能返回结构呢? 看下面的代码
    Server部分
     typedef  struct 
       {
       OVERLAPPED Overlapped;
       WSABUF DataBuf;
       CHAR Buffer[DATA_BUFSIZE];
       DWORD BytesSEND;
       DWORD BytesRECV;
    }  PER_IO_OPERATION_DATA,  *  LPPER_IO_OPERATION_DATA;线程函数代码void ThreadFun(void* parameter)
    {
    ...
    while (TRUE)
         {
           // 完成端口有消息来了 ,这里第4个参数,使自己的结构亚,如果用send怎么传???
            if  (GetQueuedCompletionStatus(CompletionPort,  & BytesTransferred,
             (LPDWORD) & PerHandleData, (LPOVERLAPPED  * )  & PerIoData, INFINITE)  ==   0 )
            {
             printf( " GetQueuedCompletionStatus failed with error %d\n " , WSAGetLastError());
              return   0 ;
          } 
        ...省略代码
    }
    }
      

  3.   

    AcceptEx就相当于一个接待员,与Accept所不同的是,Accept永远只有一个接待员,并且接待员只管接待,而AcceptEx则是一种安排,可以安排N个接待员去接待,并且接待的同时还能接收一部分数据(相关的参考相关AcceptEx的函数参考)。而GetQueuedCompletionStatus就相当于一个业务处理大厅,只要有接待员在里面,就可以接受客户的业务。Accept的接待员是在大厅外工作的,不会进往大厅,而AcceptEx的接待员是在大厅当中工作的,只要有接待指标,任何空闲的业务员(线程)都可以进行接待业务。接待完一个顾客之后,这个接待指标也同时被取消,如果需要更多的指标,只有继续增加指针(发起AcceptEx)。
      

  4.   

    至于第二个问题,我的意思是使用一个专门的线程来处理,所有的客户端connet事件,因为大家知道 GetQueuedCompletionStatus函数,可以接受到包括 connect,wsasend,wsarecv等一系列的事件,我如何只让单独的一个线程来接受所有的 connect 事件,其他的线程来接受所有的i/o事件呢
      

  5.   

    waini12(魔刀王子) ( ) 信誉:98    Blog   加为好友  2007-04-27 14:14:00  得分: 0  
     
     
       至于第二个问题,我的意思是使用一个专门的线程来处理,所有的客户端connet事件,因为大家知道 GetQueuedCompletionStatus函数,可以接受到包括 connect,wsasend,wsarecv等一系列的事件,我如何只让单独的一个线程来接受所有的 connect 事件,其他的线程来接受所有的i/o事件呢
    ==========================================
    线程池的概念就是把一个人做事的模式clone到整个团队里面去,目的在于,不至于由于工作的分派,而导致因为工种配置不当而导致有部分人过于空闲,而另一部分人则过于繁忙。
      

  6.   

    unsigned(僵哥(学温州商人思路,做好事也要突出自己的利益点) 感谢你的回复,你的例子举的非常的形象,让我对IOCP又理解的进了一步。可能是我对我想表达的问题,让你误会了,其实我晓得这个关系的。我只是想让一个单独的来处理connect事件,而不是当有消息连的时候,就让任何一个空闲的线程来处理。这是因为,如果有大量的并发connect事件,会导致connect事件的丢失。如果让一个线程专门处理connect ,其他线程处理所有的 i/o 我感觉会更好,这也是很多文章所描述的方法,但是都没有提到实现方法
      

  7.   

    unsigned(僵哥(学温州商人思路,做好事也要突出自己的利益点) 不要把服务器的设计与客户端相混合甚至是混淆,两者是完全独立的。 我完全同意你的说法,但是我有点疑问,因为客户端发送数据肯定是要按照一定格式才能让服务器识别的亚,这点你不会反对吧。那么同步函数的 send没有那么多参数,而异步 wsaSend就可以传递参数。如果我的服务器没有使用自定义结构,那我还可以相信,Microsoft的api里面可以自己转换,但是我有自己的结构 亚,如果传过来的数据不对,那服务器是要奔溃的亚
      

  8.   

    使用单独的线程来Accept就没有必要考虑使用AcceptEx,而直接采用一个线程accept就OK了,当然你还可以使用一个单独的完成端口来处理AcceptEx,也就形成有一个单独的线程池专职处理AcceptEx的工作。
      

  9.   

    函数的参数个数并不影响数据,同样的网络服务之间除了相关协议需要外,不会多余给用户发送任何数据,至于发多少数据什么格式,完成在于你自己控制的用户数据当中。 以上你的说法,我感觉很抽象。要不我来举个例子,你来回答一下,让我明白透彻吧。谢谢啦
     typedef  struct 
       {
       OVERLAPPED Overlapped;  //重叠结构
       WSABUF DataBuf;         //要发送的数据
       CHAR Buffer[DATA_BUFSIZE];  //缓冲区
       DWORD dwType;               //类型
    }  PER_IO_OPERATION_DATA,  *  LPPER_IO_OPERATION_DATA;就用上面的结构来打个比方,如果我客户端使用异步 发送数据可以这样处理
    PER_IO_OPERATION_DATA* p = GlobalAlloc(,sizeof(PER_IO_OPERATION_DATA));
    p->DataBuf.buf = p->Buffer;
    strcpy(p->Buffer,"hello,world");
    p->dwType = 1; //1表示发送,0表示接受
    WSASend(...);那么如果我使用send 函数,那么,就没有一个PER_IO_OPERATION_这样的结构,而是直接使用
    send (,"helloworld",11,0);那么如果我的服务器是这样写的,会有什么后果呢?// 完成端口有消息来了 
            if  (GetQueuedCompletionStatus(CompletionPort,  & BytesTransferred,
             (LPDWORD) & PerHandleData, (LPOVERLAPPED  * )  & PerIoData, INFINITE)  ==   0 )
            {
             printf( " GetQueuedCompletionStatus failed with error %d\n " , WSAGetLastError());
              return   0 ;
          } switch(PerIoData -> dwType )  //如果用Send 那么这里不是要错吗?
           {
    case 1:case 2
          } 
      

  10.   

    使用单独的线程来Accept就没有必要考虑使用AcceptEx,而直接采用一个线程accept就OK了,当然你还可以使用一个单独的完成端口来处理AcceptEx,也就形成有一个单独的线程池专职处理AcceptEx的工作。
    ***********************************你这得方法很不错,我当时也正好是这样想的。我的疑惑就在于 一个程序里面能够有多个完成端口吗?
      

  11.   

    我用的单独线程来接收连接的,没有用AcceptEx,测试结果短时间高并发连接也是会丢失连接,这个问题一直都没有解决
      

  12.   

    你应该用AcceptEx,在单独线程中处理的,那样就不会丢失连接,
      

  13.   

    我已经,对以上的两个问题,完全了解了,再次感谢 
    unsigned(僵哥(学温州商人思路,做好事也要突出自己的利益点))
      

  14.   

    请问 下面这从段是如何理解的,我这碰到这个问题,想不明白那么如果我使用send 函数,那么,就没有一个PER_IO_OPERATION_这样的结构,而是直接使用
    send (,"helloworld",11,0);那么如果我的服务器是这样写的,会有什么后果呢?// 完成端口有消息来了 
            if  (GetQueuedCompletionStatus(CompletionPort,  & BytesTransferred,
             (LPDWORD) & PerHandleData, (LPOVERLAPPED  * )  & PerIoData, INFINITE)  ==   0 )
            {
             printf( " GetQueuedCompletionStatus failed with error %d\n " , WSAGetLastError());
              return   0 ;
          } switch(PerIoData -> dwType )  //如果用Send 那么这里不是要错吗?
           {
    case 1:case 2
          }