游戏开发论坛

 找回密码
 立即注册
搜索
查看: 1968|回复: 1

用Perl写一个游戏服务端的简单框架,阐述client/server之间

[复制链接]

1

主题

3

帖子

0

积分

新手上路

Rank: 1

积分
0
发表于 2011-12-24 15:28:00 | 显示全部楼层 |阅读模式
用于简单的 flash client/server 测试,自己添加内容还是比较方便


#!/usr/bin/perl
# Eric Lau 2011-12-17 QQ340004
use strict;
use warnings;

use POE;
use POE::Component::Server::TCP;

# 发往客户端的信息结尾符号,客户端 FLASH 一般要求以 \0 结尾接收信息
my $CLIENT_EOL         = "\0";

# 首次连接时要求客户端确认的信息
my $CONFIRM_Q          = "ok, connected";

# 在指定端口创建 TCP 服务
POE::Component::Server::TCP->new(
    Alias              => "game_server",
    Port               => 5122,
    InlineStates       => {send => \&handle_send},
    ClientConnected    => \&client_connected,
    ClientError        => \&client_disconnected,
    ClientDisconnected => \&client_disconnected,
    ClientInput        => \&client_input,
);

POE::Kernel->run();
exit 0;

# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
# 当前在线用户信息
my %users;

# 发信处理
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
sub handle_send {
    my ($heap, $message) = @_[HEAP, ARG0];

    # 客户端 FLASH 要求以 \0 结尾接收信息
    $heap->{client}->put($message.$CLIENT_EOL);
}

# 首次连接处理
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
sub client_connected {
    my $session_id = $_[SESSION]->ID;

    # 创建在现用户
    $users{$session_id} = {
        SID       => $session_id,
        STATUS    => 0, # 客户端连接状态
    };

    # 一旦客户端连接到服务器,立即向客户端确认
    POE::Kernel->post($session_id => send => $CONFIRM_Q);
}

# 断开连接
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
sub client_disconnected {
    my $session_id = $_[SESSION]->ID;

    # 删除在线用户信息
    my $user = delete $users{$session_id};

    $_[KERNEL]->yield("shutdown");

    # 客户端下线后的处理
    # ...
}

# 处理客户端输入
# 注意,要使 POE 接收到客户端发来的数据,其数据内容必须以 "\n" 结尾
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
sub client_input {
    my($kernel, $session, $input) = @_[KERNEL, SESSION, ARG0];

    # 客户端信息
    my $session_id = $session->ID;
    my $user = $users{$session_id};

    # 将信息结尾的 \0 或 \n 去除
    chomp $input; #$input =~ s/\0$//;

# 这里列出了一个通讯过程
# 1. 客户端与服务端建立连接,服务端立即发送 $CONFIRM_Q 进行确认(这里设置为要求客户端登录)
# 2. 客户端发送一串字符,则服务端返回 “.” ,请继续其他指令
#    如果客户端发送了一个空字符串(这里表示登陆错误),服务端则要求其继续登录
# 3  设置客户端已登陆成功信息 $user->{STATUS} = 1;
# 4. 客户端发送 1或2,3等指令,服务端返回相应数据,如果是其他内容则强行断开连接
#

    # 验证客户端是否通过了首次连接验证,这里用作登录处理
    if ($user->{STATUS} == 0)
        {
        # 验证用户名和密码
        my $userinfo = user_login($input);

        # 登录成功,更新用户信息
        if (defined $userinfo) {
            $user->{STATUS} = 1;
            $user->{NAME}   = $user->{name};

            # 可以继续,等待客户端请求
            POE::Kernel->post($session_id => send => '.');
        }
        else {
            # 失败,请重试
            POE::Kernel->post($session_id => send => $CONFIRM_Q);
        }

        return;
    }

    # 客户端已登录,处理客户端的各种请求
    CASE:
    {
                # 可以编辑 “请求代码 => 函数” 列表进行处理
                # 客户端请求代码为 1
        $input eq "1" && do {

                        # 信息只发给当前客户端
            POE::Kernel->post($session_id => send => '.');
            last CASE;
        };

        $input eq "2" && do {
                        # 广播
            broadcast($session_id, "b.");
            last CASE;
        };

        $input eq "3" && do {

            broadcast($session_id, "c.");
            last CASE;
        };

        # ELSE 错误指令,强行断开客户端的连接
        # 删除在线用户信息
        delete $users{$session_id};

        $_[KERNEL]->yield("shutdown");

        # 客户端下线后的处理
        # ...
    }
}

# 用户登录,返回用户信息
my $user_id = 0;
sub user_login {
    my($input) = @_;

        # 这里进行用户登录验证
        if ($input) {
                $user_id++;
                my $userinfo = {
                        id         => $user_id,
                        name => 'User_'.$user_id,
                };

                return $userinfo;
        }

        return undef;
}

# 向所有用户广播
sub broadcast {
    my ($sender, $message) = @_;
    foreach my $user (keys %users) {
                # 这里可以根据 $users{$user} 的信息进行选择性广播,比如只向屏幕范围内的用户广播。
        if ($user == $sender) {
            POE::Kernel->post($user => send => "You $message");
        } else {
            POE::Kernel->post($user => send => "$sender $message");
        }
    }
}

1

主题

3

帖子

0

积分

新手上路

Rank: 1

积分
0
 楼主| 发表于 2011-12-24 15:38:00 | 显示全部楼层

Re: 用Perl写一个游戏服务端的简单框架,阐述client/server之

附件要压缩啊。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

作品发布|文章投稿|广告合作|关于本站|游戏开发论坛 ( 闽ICP备17032699号-3 )

GMT+8, 2025-6-9 04:59

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表