智慧 + 毅力 = 无所不能

正确性、健壮性、可靠性、效率、易用性、可读性、可复用性、兼容性、可移植性...

导航

ProjectDarkStar服务器端开发文档(六)Hello User!

Posted on 2009-11-24 18:04  Bill Yuan  阅读(542)  评论(0编辑  收藏  举报

转自:http://www.david0446.com/?p=67

第五课:Hello User!

Up till now the tutorial lessons have focused on getting your logic up and running in the PDS. But there is another side to the online game equation ─ the users and their computers. This lesson shows how to start communicating between clients and the PDS.

直到现在,指南里的课程都在集中研究你在PDS里的逻辑运行。但是,在网络游戏中还有另一端——用户和他们的电脑。这节课展现了如何开始在客户端与PDS服务器之间建立连接。

In this tutorial, the server side of that communication will be explained and illustrated using a simple pre-built client. For the client-side coding, please see the Project Darkstar Client Tutorial.

这篇指南会解释通信时服务器端的运行,并用一个简单的客户端来说明。关于客户端的代码,请参考Project Darkstar Client Tutorial客户端指南。

1.了解用户的登录

The first step in communicating with users is knowing who is available to communicate with. The PDS provides a callback method on the AppListener for this: loggedIn. The loggedIn method gets passed an object that describes the user; this object is called a ClientSession.(11)

与用户通信的第一步是了解连接时谁是有效的。PDS为此在AppListener里提供了一个回调方法:loggedInloggedIn方法通过一个对象来描述用户,这个对象称之为ClientSession(11)

Below is the code for HelloUser, a trivial application that logs the login of a user.

下面的HelloUser代码,记录了一个用户的登录。

HelloUser

/*
 * Copyright 2007-2009 Sun Microsystems, Inc.
 *
 * This file is part of Project Darkstar Server.
 *
 * Project Darkstar Server is free software: you can redistribute it
 * and/or modify it under the terms of the GNU General Public License
 * version 2 as published by the Free Software Foundation and
 * distributed hereunder to you.
 *
 * Project Darkstar Server is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <
http://www.gnu.org/licenses/>.
 
*/
package com.sun.sgs.tutorial.server.lesson5;

import java.io.Serializable;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.sun.sgs.app.AppListener;
import com.sun.sgs.app.ClientSession;
import com.sun.sgs.app.ClientSessionListener;

/**
 * Simple example of listening for user {
@linkplain AppListener#loggedIn login}
 * in the Project Darkstar Server.
 * <p>
 * Logs each time a user logs in, then kicks them off immediately.
 
*/
public class HelloUser implements AppListener, // to get called during startup
                                                
// and login.
        Serializable // since all AppListeners are ManagedObjects.
{
    
/** The version of the serialized form of this class. */
    
private static final long serialVersionUID = 1L;

    
/** The {@link Logger} for this class. */
    
private static final Logger logger = Logger.getLogger(HelloUser.class
            .getName());

    
// implement AppListener
    /** {@inheritDoc*/
    
public void initialize(Properties props) {
        
// empty
    }

    
/**
     * {
@inheritDoc}
     * <p>
     * Logs a message each time a new session tries to login, then kicks them
     * out by returning {
@code null}.
     
*/
    
public ClientSessionListener loggedIn(ClientSession session) {
        
// User has logged in
        logger.log(Level.INFO, "User {0} almost logged in", session.getName());
        
// Kick the user out immediately by returning a null listener
        return null;
    }
}

 

2.直接通信

You will note that, when you run the server application above and connect to it with a client, the client is immediately logged out. This is because we are returning null from loggedIn. The PDS interprets this as our rejecting the user. To accept the user and allow him or her to stay logged in, you need to return a valid ClientSessionListener. To be valid, this object must implement both ClientSessionListener and Serializable. Below is HelloUser2, which does this.

你会注意到,当你运行上面的服务程序并连接到一个客户时,客户立刻就登出了。这是因为我们在loggedIn里返回null。PDS将此理解为拒绝用户。为了接受用户,允许他或她留下来,你需要返回一个有效的ClientSessionListener。为了有效,这个对象必须实现ClientSessionListenerSerializable接口。下面的HelloUser2就是这样。

HelloUser2

HelloUser2 is identical to HelloUser except for the loggedIn method:

 

/*
 * Copyright 2007-2009 Sun Microsystems, Inc.
 *
 * This file is part of Project Darkstar Server.
 *
 * Project Darkstar Server is free software: you can redistribute it
 * and/or modify it under the terms of the GNU General Public License
 * version 2 as published by the Free Software Foundation and
 * distributed hereunder to you.
 *
 * Project Darkstar Server is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <
http://www.gnu.org/licenses/>.
 
*/
package com.sun.sgs.tutorial.server.lesson5;

import java.io.Serializable;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.sun.sgs.app.AppListener;
import com.sun.sgs.app.ClientSession;
import com.sun.sgs.app.ClientSessionListener;

/**
 * Simple example of listening for user {
@linkplain AppListener#loggedIn login}
 * in the Project Darkstar Server.
 * <p>
 * Logs each time a user logs in, and sets their listener to a new
 * {
@link HelloUserSessionListener}.
 
*/
public class HelloUser2 implements AppListener, // to get called during startup
                                                
// and login.
        Serializable // since all AppListeners are ManagedObjects.
{
    
/** The version of the serialized form of this class. */
    
private static final long serialVersionUID = 1L;

    
/** The {@link Logger} for this class. */
    
private static final Logger logger = Logger.getLogger(HelloUser2.class
            .getName());

    
// implement AppListener
    /** {@inheritDoc*/
    
public void initialize(Properties props) {
        
// empty
    }

    
/**
     * {
@inheritDoc}
     * <p>
     * Logs a message each time a new session logs in.
     
*/
    
public ClientSessionListener loggedIn(ClientSession session) {
        
// User has logged in
        logger.log(Level.INFO, "User {0} has logged in", session.getName());
        
// Return a valid listener
        return new HelloUserSessionListener(session);
    }
}

HelloUserSessionListener

/*
 * Copyright 2007-2009 Sun Microsystems, Inc.
 *
 * This file is part of Project Darkstar Server.
 *
 * Project Darkstar Server is free software: you can redistribute it
 * and/or modify it under the terms of the GNU General Public License
 * version 2 as published by the Free Software Foundation and
 * distributed hereunder to you.
 *
 * Project Darkstar Server is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <
http://www.gnu.org/licenses/>.
 
*/
package com.sun.sgs.tutorial.server.lesson5;

import java.io.Serializable;
import java.nio.ByteBuffer;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.sun.sgs.app.AppContext;
import com.sun.sgs.app.ClientSession;
import com.sun.sgs.app.ClientSessionListener;
import com.sun.sgs.app.ManagedReference;

/**
 * Simple example {
@link ClientSessionListener} for the Project Darkstar Server.
 * <p>
 * Logs each time a session receives data or logs out.
 
*/
class HelloUserSessionListener implements Serializable, ClientSessionListener {
    
/** The version of the serialized form of this class. */
    
private static final long serialVersionUID = 1L;

    
/** The {@link Logger} for this class. */
    
private static final Logger logger = Logger
            .getLogger(HelloUserSessionListener.
class.getName());

    
/** The session this {@code ClientSessionListener} is listening to. */
    
private final ManagedReference<ClientSession> sessionRef;

    
/** The name of the {@code ClientSession} for this listener. */
    
private final String sessionName;

    
/**
     * Creates a new {
@code HelloUserSessionListener} for the given session.
     * 
     * 
@param session
     *            the session this listener is associated with
     
*/
    
public HelloUserSessionListener(ClientSession session) {
        
if (session == null) {
            
throw new NullPointerException("null session");
        }
        sessionRef 
= AppContext.getDataManager().createReference(session);
        sessionName 
= session.getName();
    }

    
/**
     * Returns the session for this listener.
     * 
     * 
@return the session for this listener
     
*/
    
protected ClientSession getSession() {
        
// We created the ref with a non-null session, so no need to check it.
        return sessionRef.get();
    }

    
/**
     * {
@inheritDoc}
     * <p>
     * Logs when data arrives from the client.
     
*/
    
public void receivedMessage(ByteBuffer message) {
        logger.log(Level.INFO, 
"Message from {0}", sessionName);
    }

    
/**
     * {
@inheritDoc}
     * <p>
     * Logs when the client disconnects.
     
*/
    
public void disconnected(boolean graceful) {
        String grace 
= graceful ? "graceful" : "forced";
        logger.log(Level.INFO, 
"User {0} has logged out {1}"new Object[] {
                sessionName, grace });
    }
}

 

HelloUserSessionListener is a glue object that listens for either data from the user or the disconnect of the user; it allows our server code to respond to these events. So far, all we do is log some information, but in a complete PDS application, these would both be important events to which we would want to respond.

HelloUserSessionListener是一个监听用户发来的数据和用户断开连接的对象,它允许我们的服务器代码响应这些事件。到目前为止,我们所做的只是记录一些信息,但是在一个完整的PDS应用里,这些信息对于我们想要响应的事件来说都是很重要的。

There are two kinds of communication in the PDS:

● Direct Communication

● Channel Communication

在PDS里有两种通信方式:

● 直接通信

● 通道通信

Direct Communication is built into the core of the system and provides a pipe for the flow of data between a single user client and its PDS application.

直接通信被建立为系统的核心,为用户的客户端和它的PDS应用之间的数据流通提供一个管道。

Channel Communication is provided by a standard manager, the Channel Manager, and provides for publish/subscribe group communications. While there is nothing in the Channel Manager’s functionality that could not be implemented on top of the Direct Communication mechanisms, putting the channel functionality in a manager allows for a much more efficient implementation.

通道通信是一个标准管理器提供的,通道管理器,提供给发布/订阅组通信。然而,在通道管理器的函数里,并没有什么不能实现直接通信机制,但考虑到一个更加有效的实现,还是把通道功能放进一个管理器里。

The HelloEcho PDS application echoes back to the user anything the user sends to the application. Besides the name, there is only one line difference in HelloEchoSessionListener from HelloUserSessionListener: the addition of a session.send call.

HelloEcho应用向用户回送任何用户发向应用的数据。除了名字之外,HelloEchoSessionListenerHelloUserSessionListener只有一个不同:增加一个session.send的调用。

HelloEchoSessionListener

/*
 * Copyright 2007-2009 Sun Microsystems, Inc
 *
 * This file is part of Project Darkstar Server.
 *
 * Project Darkstar Server is free software: you can redistribute it
 * and/or modify it under the terms of the GNU General Public License
 * version 2 as published by the Free Software Foundation and
 * distributed hereunder to you.
 *
 * Project Darkstar Server is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <
http://www.gnu.org/licenses/>.
 
*/
package com.sun.sgs.tutorial.server.lesson5;

import java.io.Serializable;
import java.nio.ByteBuffer;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.sun.sgs.app.AppContext;
import com.sun.sgs.app.ClientSession;
import com.sun.sgs.app.ClientSessionListener;
import com.sun.sgs.app.ManagedReference;

/**
 * Simple example {
@link ClientSessionListener} for the Project Darkstar Server.
 * <p>
 * Logs each time a session receives data or logs out, and echoes any data
 * received back to the sender.
 
*/
class HelloEchoSessionListener implements Serializable, ClientSessionListener {
    
/** The version of the serialized form of this class. */
    
private static final long serialVersionUID = 1L;

    
/** The {@link Logger} for this class. */
    
private static final Logger logger = Logger
            .getLogger(HelloEchoSessionListener.
class.getName());

    
/** The session this {@code ClientSessionListener} is listening to. */
    
private final ManagedReference<ClientSession> sessionRef;

    
/** The name of the {@code ClientSession} for this listener. */
    
private final String sessionName;

    
/**
     * Creates a new {
@code HelloEchoSessionListener} for the given session.
     * 
     * 
@param session
     *            the session this listener is associated with
     
*/
    
public HelloEchoSessionListener(ClientSession session) {
        
if (session == null) {
            
throw new NullPointerException("null session");
        }
        sessionRef 
= AppContext.getDataManager().createReference(session);
        sessionName 
= session.getName();
    }

    
/**
     * Returns the session for this listener.
     * 
     * 
@return the session for this listener
     
*/
    
protected ClientSession getSession() {
        
// We created the ref with a non-null session, so no need to check it.
        return sessionRef.get();
    }

    
/**
     * {
@inheritDoc}
     * <p>
     * Logs when data arrives from the client, and echoes the message back.
     
*/
    
public void receivedMessage(ByteBuffer message) {
        ClientSession session 
= getSession();
        logger.log(Level.INFO, 
"Message from {0}", sessionName);
        
// Echo message back to sender
        session.send(message);
    }

    
/**
     * {
@inheritDoc}
     * <p>
     * Logs when the client disconnects.
     
*/
    
public void disconnected(boolean graceful) {
        String grace 
= graceful ? "graceful" : "forced";
        logger.log(Level.INFO, 
"User {0} has logged out {1}"new Object[] {
                sessionName, grace });
    }
}

 

3.运行例子

To try all the examples in this part of the server tutorial, you need a simple client capable of logging in, as well as direct client/server communication. You can find this client as part of Lesson 1 of the Project Darkstar Client Tutorial (com.sun.sgs.tutorial.client.lesson1.HelloUserClient in the tutorial-client.jar file).

为了运行这部分的所有例子,你需要一个简单的客户端来登录,以及直接的客户端/服务器通信。你可以在Project Darkstar Client Tutorial客户端指南中的第一课中找到这个客户端(com.sun.sgs.tutorial.client.lesson2.HelloChannelClient in tutorial-client.jar)。

注释:

(11) 事实上,ClientSession描述了新的连接会话,用户信息只是那些参数中的一个。这个区别在那种情况下是很重要的,就是在用户断开连接,会话结束时,你并不能保存一个ClientSession对象并让它是有效的。