我现在要设计一个UDP服务器。 准备设计成N个接收者,调用阻塞接收函数recvfrom接收到客户端请求后就把数据投递到一个缓冲队列中, 然后N各处理者不停的检测这个缓冲队列,如果缓冲队列有内容,就读取一条进行处理。这样设计合理吗?
有没有更好的方案?  类似的程序或者具体设计思路有没有? 有现成代码参考更好。谢谢各位了,。

解决方案 »

  1.   

    这种方式并不好,你可以接收到数据后就扔给处理线程来处理,接收线程只负责接收数据并分发数据而已,否则UDP数据可能来不及处理而被丢弃。事件处理模型可以参考一下我的博客文章:http://blog.csdn.net/kyee
      

  2.   

    开一个专门的接收线程专门侦听,来了客户端请求,就开辟一个新的线程与客户端建立连接,然后用处理线程来进行数据通信等,可以刹那考IOCP等
      

  3.   


    我的是UDP ,没有监听哦。麻烦看清楚问题。呵呵
      

  4.   


    UDP用完成端口有意义吗?这个问题我一直不清楚,我认为多socket交给完成端口管理是个好方法,但是UDP貌似不需要完成端口。大家说呢。
      

  5.   

    这样处理没什么问题不过不知道你这里的接收者是什么概念,是不是根据发送端的IP,port来区分的如果是的话,还可以有一种方案,就是每个接收者有自己的队列,就是接收到数据看看有没有对应IP,port的
    接收者,如果有就把数据加到接收者自己的队列,如果没有,就创建一个接收者,把数据加到接收者自己的队列,这样数据处理起来针对性更强一些仅供参考
      

  6.   


    你这个方法不好哦。。 说能保证客户端IP总是一样,还经常连接服务器。如果只是为了发送很少的数据和服务器连接一下的话,这种为了每个IP开辟线程来处理的方法太浪费了。
      

  7.   

    我在说下我的方法吧。UDP中不太适合用各种I/O模型,所以自己写个。主线程循环阻塞接收用户数据。如果收到用户数据,则将数据传递给1个处理者子线程来处理(处理者子线程有N个)。请大家发表看法喔,我还想多问一句,如果用非阻塞模式可行吗?感觉非阻塞模式一般都是和I/O模型结合在一起的。是不是自己写并发处理就没必要用非阻塞?
      

  8.   

    不停的检测这个缓冲队列这种做法不好,应该使用Event,加入队列后Event置位,处理线程等待Event,并循环读取队列数据。例子代码:
    // 队列对象和事件对象
    TQueue* FQueue;
    TEvent* FEvent;// 加入数据
    bool AddData(void* AData)
    {
       // 初始化
       bool result = false;   // 加入队列
       if (FQueue->Push(AData))
       {
          FEvent->Set();
          result = true;
       }   // 返回结果
       return result;
    }// 取数据函数
    bool GetData(void* &AData, Longword ATimeout)
    {
       // 初始化
       bool result = true;   // 取队列数据
       if (FQueue->Count() != 0)
          AData = FQueue->Pop();
       else
       {
          // 等待事件
          FEvent->Wait(ATimeout);      // 取队列数据
          if (FQueue->Count() != 0)
             AData = FQueue->Pop();
          else
             result = false;
       }   // 返回结果
       return result;
    }// 若处理数据直接放在线程中
    void DoExecute(TThread* AThread, void* AParam)
    {
       // 初始化
       void*    pData;
       Longword dwNo, dwCount;   // 线程循环体
       while (!AThread->Terminated())
       {
          // 等待事件
          FEvent->Wait();      // 循环处理队列数据
          dwNo    = 0;
          dwCount = FQueue->Count();
          while (!AThread->Terminated() && (dwNo++ < dwCount))
          {
             pData = FQueue->Pop();         // 处理数据
             // ??? ... ...
          }
       }
    }
      

  9.   

    我需要用非阻塞模式吗???????因为我没有用IO模型,所以感觉用非阻塞模式其实也提高不鸟效率。而且我也没有看到过非阻塞不用IO模型的例子。。我感觉非阻塞是个IO模型相辅相成的。大家认为呢? 如果有不同的看法一定要告诉我啊。
      

  10.   

    最简单的就是最好的用一个线程RECV数据
    数据读到后
    投递到全局缓冲,给 0-N个线程发送线程消息进行处理
    这种方式适合 6000个以下的并发数据连接用0-N个线程
    通过一把全局锁
    得到锁的线程负责执行SELECT+RECVFROM
    成功读到数据后,立即释放锁
    然后处理数据
    然后释放锁
    这种方式适合10000个以上的并发数据连接没必要使用什么模型什么完成端口,动辄完成端口的,说明他根本没理解操作系统原理
      

  11.   

    线程切换 跨进程的话 1600个CPU周期左右
    而如果是进程内
    因为不需要切换上下文,开销几乎是0
    放心使用好了第二个方式,因为可以避免WIN 消息队列最多只有10000个的缺陷你自己可以优化的啊
    SELECT到可以读后
    你可以连续多读几个包,然后一起处理我只是给你个思路
    怎么优化,要你自己结合自己的应用去分析测试了
      

  12.   

    我需要写一个跨平台的。而且这里完成端口也不能提高效率。。大家认为呢。而且完成端口的UDP模型好像也基本没有
      

  13.   

    多线程接收者,缓冲区保存数据,多线程处理者。 这种模式最适合UDP。  
      

  14.   

    写入队列前一定要用EnterCriticalSection()(进入临界区)保护即可
      

  15.   

    用0-N个线程
    通过一把全局锁
    得到锁的线程负责执行RECVFROM
    成功读到数据后,立即释放锁
    然后处理数据
    这种方式适合10000个以上的并发数据连接 我就是这样的,
      

  16.   

    用0-N个线程 
    通过一把全局锁 
    得到锁的线程负责执行SELECT+RECVFROM 
    成功读到数据后,立即释放锁 
    然后处理数据 
    然后释放锁 
    这种方式适合10000个以上的并发数据连接 
    这个方法的   得到锁的线程负责执行SELECT+RECVFROM 
    这句话我不是很明白。说能帮我解释一下啊!!!?? 具体点select模型+recvform吗? 我不是很明白怎么做
      

  17.   

    接收数据就用一个线程就可以了
    只是负责接收RECVFROM数据  接收数据时对接收数据的缓冲区进行加锁处理
    其他不必要功能最好不要分析和处理命令放到其他线程处理
      

  18.   

    搭建一个udp 或 tpc 服务器 需要考虑很多内容,比如说多个客户端并发处理,c/s通信方式:比如说,是一对一的,就客户端一个请求,服务器一个应答,还是客户端一个请求,服务器多个应答,或者需不需要实现服务器通知,即服务器主动向客户端发消息。一个稳定的服务器需要做很多工作,如果你这方面经验少,我给你推荐一个很好用,很强大,很免费的软件。现在我们公司做的对战平台服务器都是在这个基础上改的,我给你链接,你自己去下载吧,代码 demo 都有,强力推荐。
    http://www.codeproject.com/KB/IP/serversocket.aspx
      

  19.   

    我这2天写了一个,也是用的这种模式。  N个接收者(可调)专门recvform ,收到后丢入缓存队列, 然后M个处理者(程序根据并发数自动调节M值)进行处理数据。并且用到了内存池和线程池,还有日志机制但是经常听到说  非阻塞模式和IO模型。 我就不知道那样会效率高吗? 据我所知,我这样做应该至少不会比那样效率低。
      

  20.   

    我来说说我的意见吧第一点,设计越简单越好,如果阻塞模式能满足(项目需求的)性能要求和(项目以后可能出现的需求)的扩展性要求,,,,,采用阻塞模式就行第二点,重叠IO模型效率有没有比阻塞模式高?答案是肯定的!!!
         重叠IO模型,就是让你让你提前把准备工作做好,一有机会,就马上完成
         (就象你先拿几个袋子放着,只要有人东西扔进去并好了,马上报告,,,,,,而阻塞模式是,你拿一个袋子,张开等着,收到,返回,,,,再开一个袋子)
          由此可见:
                 1,对于处理数据并发(并发的概念,后面会强调,见最后)的情况,重叠IO模型的优势是显而易见的
                 2,重叠IO模型的效率肯定会比阻塞模型高
                 3,还有,可扩展性的优势+基于事件的优势,(可以想象一下,2种模式中,IO操作和结果处理模块间的耦合度)关于并发的概念,一般都会认为并发只是accept的事情(我想这也是为什么,lz在上面认为UDP不需要重叠IO模型),并发是数据的并发,accept,recv等都会并发,说明同一时间有很多客户端的请求(连接请求,数据处理请求)需要处理
      

  21.   


    这不很简单吗
    因为全局锁可以保证,同一时间只有一个线程[一般建议开启CPU数量+1个线程]可以得到锁
    该线程然后执行
    selsect(udp_socket , 时间参数,例如 2秒) 检查UDP SOCKET是否可读或者发生错误
    当select返回的时候
    有3种可能
    [1] 有数据到达
    [2] 无数据到达,但是返回了一个错误 [例如SOCKET被外部关闭] 一定要加这个分之检测
    [3] 无数据到达,无错误,是时间到了对于 [1]
    你可以立即执行recvfrom读操作,肯定不会阻塞[当然建议你使用非阻塞UDP SOCKET]
    执行完RECVFROM后,立即释放全局锁
    然后读到数据的线程执行数据处理,有其他线程将获得锁,执行同样的重复操作对于[2]
    释放锁
    处理错误,判断是否是外部要求服务停止了
    如果是,退出,否则回到最开始的 获取全局锁对于[3]
    不释放锁,也不执行RECVFROM
    只检查是否有外部要求服务停止
    如果有,那么释放锁,退出
    否则继续SELECT 读尝试循环但是这里面有很多地方可以结合你自己的协议进行优化的
    例如可以尝试一次读多个UDP包,然后处理、
    这些就靠你自己你优化了
      

  22.   

    对于lz的应用,阻塞模式单个线程接收,多个线程处理,这是最有效,最简单直接的方法,根本不用考虑什么性能瓶颈,接收线程只是收取数据,然后获取业务缓冲区锁、投递业务数据、解锁,这3个操作根本不会耗费什么时间而导致在socket上的数据由于来不及收取而被丢弃。
    别动不动就说啥啥模式效率比较高,对于网络io数据量比较小的情况,主要应该在业务处理上考虑提高效率。
    最有效,最简单直接的方法才是最好的方法。
    个人意见,仅供参考。
      

  23.   


    非常谢谢你的支持,好多人都有不同意见。但是我自认为也做了很久这方面的研究,说实话,讨论了这么久我还是比较相信我的方法,这2天把程序也实现了一下,实现了一个复杂的内存池来分配内存,设计了一条动态大小的缓存队列,还有线程池,互斥也考虑的比较完善, 还有最重要的一点,互斥要尽量设的范围小点,否则还是比较影响性能的。另外整个程序的瓶颈是在处理者, 所以需要动态调节处理者线程的数目。这点和内存池的设计均借鉴了apache 
      

  24.   


    也谢谢你提出了宝贵的意见~真的,select模型我很清楚,但是我这里是阻塞模型,select我感觉不能用于阻塞模型里面,不是嘛?  谢谢大家的讨论
      

  25.   


    也非常谢谢你,打这么多字,非常非常感谢你的帮助! 但是我还是想说一下: 阻塞模式可以用IO模型吗?有必要用IO模型吗? 
      

  26.   

    完成端口有一个好处,就是可以一次性投递n个请求进行缓冲,只要足够多,就不容易丢包。
    你只要用两个完成端口,一个预先post足够多的buffer到kernel等候数据到达,io完成后立即post到另一个完成端口进行处理,连锁都省了,因此接收线程能够快速轮转。
      

  27.   

    至于说iocp不如blocking的,都是他们不懂iocp的精髓所在啊。一次queue一个io的话肯定跟blocking差不多了,唉。都不会用的,懒的说。
      

  28.   

    楼主牛B
    SELECT不能用于阻塞模型无语
      

  29.   

    如果是编写windows上服务器应用的话,
    我想没有任何理由不使用IOCP把,
    当然,自己学习代码就另当别论咯
      

  30.   

    竟然发来vc/mfc...
    linux下的话没天生proactor..野生proactor都是reactor模拟的。。
    阿婆主你还是尽量优化recv之后的过程,尽快回到阻塞的队伍中去吧~~阿门
      

  31.   

    我的意思是收线程不要处理数据
    一个thread收一个thread处理
      

  32.   

    28,38楼说得是一种线程模型叫做Leader/Followers,lz搜索一下就明白了
      

  33.   

    IOCP是个网络模型,从来没有限制于哪种协议,看你是否要考虑到网络性能