May 28

网游服务器的主循环中, 必须做如下事情: 读取客户端请求(read_request), 把请求交给处理过程(handle_request), 读取异步过程的结果(read_result), 同步指令给客户端(sync_client). 因为read_request和read_result可能被阻塞, 所以先测试(test)再读取. 同时还要考虑时钟周期, 让主循环休眠一段时间. 如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
while(1){
    n = test_clients();
    if(n > 0){
        read_request();
        handle_request();
    }
 
    n = test_async_handlers();
    if(n > 0){
        read_result();
    }
 
    sync_client();
 
    sleep();
}

显然, sleep白白浪费了计算资源, 应该避免. 可以把sleep浪费的资源用来做别的事. 可以变成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
while(1){
    while(还不足一个时钟周期){
        wait_request_and_result(timeout);
        if(first_request_of_each_client){
            handle_request();
        }else{
            new_request_queue.append();
        }
        read_result();
    }
 
    if(old_request_queue.count > 0){
        read_request();
        handle_request();
    }
    old_request_queue += new_request_queue;
 
    sync_client();
}

问题是, wait_request_and_result()会很难实现.

Related posts:

  1. 用脚本语言开发网游 – C整合Python
  2. 网络游戏的架构
  3. 网游服务器的架构 – 层次结构
  4. 网游服务器如何处理用户的指令
  5. 网络游戏与单机游戏的关系

Written by benegg at 2009-05-28 18:13:19 | Views: 3802

9 Responses to “网游服务器的主循环”

  1. 1. kennywong Says:

    我的做法是把网络层和逻辑层分开进程做.
    通过两个用共享内存实现的单读单写的消息队列通信.
    网络层把解出来的包入列,逻辑主循环读取消息队列中
    的消息并处理,消息队列没有使用锁,也不存在阻塞的情况.
    当逻辑需要发包的时候,通过另一个消息队列将数据包传递
    给网络进程.

  2. 2. kennywong Says:

    对于象网关这样逻辑处理很少的服务器.我分成三层,第一层是处理内连接部分.
    第二层是加密解密部分,第三层是客户连接处理部分.各层之间使用消息队列
    连接.对于第三层和第二层,也可以同时启动多个进层,例如一个进程只处理
    512个连接.最终结构如下:

    内连接处理进程
    | |
    加解密进程 …加解密进程
    | |
    客户连接进程 …客户连接进程

  3. 3. benegg Says:

    回复kennywong:

    虽然把服务器分为传输层和逻辑层, 但是还是有眼前的问题需要解决. 比如, 传输层和逻辑层都需要处理连接的登录, 同时, 逻辑层除了和传输层相互通信外, 还要和其它的服务层通信. 这样, 传输层和逻辑层不可避免要进行IO多路复用. 也就是说, 任何一个进程, 都必须和多于一个进程通信.

  4. 4. kennywong Says:

    传输层并不仅仅只是做网络层和逻辑层简单的中转,有些必要的逻辑还是要处理的,
    例如一些控制协议包.以连接登陆为例,在传输层,只要accept了就认为已经登陆,
    通过后续的认证由逻辑层来判断客户是否合法.如果不合法,将一个控制包传入
    消息队列,由传输层将连接断开.一个进程与多于一个进程的通信在某些服务上肯定会出现.例如在网关上,一个内连接进程就可能会跟数个客户端连接进程通信.如果这些通信使用的是管道或socket等,那么肯定是要使用IO多路复用.如果用的是共享消息队列,那么IO复用就不需要了.但这里进程间通信跟与客户端进程间通信区别还是很大,即使是轮询,每个循环也只需要轮询几次.

  5. 5. kennywong Says:

    当然这只是目前正在实现的一个设计,具体的性能和存在的一些问题,
    要实现之后通过实际的测试才知道.

  6. 6. benegg Says:

    回复kennywong:

    其实大家的想法都有不少的共同之处. 只是, 想法和实现差别很大. 前段时间我设计好了不少模型, 等到实现时, 立即就被代码弄糊涂了. 所以, 模型变了又变. 确实应了那名话: 说的容易做的难.

    分析时, 一个个对象一个个进程活灵活现, 实现起来寸步难行. 所以, 我现在急切地要先做出一个具体的实现, 才好做进一步的讨论和改进.

    我的思路有一点和你有较大区别, 我设计的进程通信总是使用 TCP/IP socket 进行通信, 这样可以方便分布式. 就算多个进程部署在单机, 使用 socket 也利于跨平台. 既然已经使用多进程了, 相信从设计上通信不应该成为瓶颈.

  7. 7. kennywong Says:

    对啊,我也经常是设计好,实现时又推翻.反反复复.

  8. 8. kennywong Says:

    朋友,有MSN或QQ没有,跟你研究个问题.

  9. 9. benegg Says:

    回复kennywong: 可以通过Email联系吧,

Pages:

Leave a Reply

必须登录, 或者浏览器开启JavaScript支持才可以评论!