这几日在做Sun的Darkstar项目,看了三天教程,初步了解了这个平台的架构。

服务器端主要包括AppListener和ClientSessionListener。

  1. 在AppListener中设计Initialize和loggedIn。loggedIn的任务是给每一个连进来的session分配一个ClientSessionListener。Initialize的任务是用ChannelManager建立Channel(建立好的Channel无需保存引用,可以在后面用getChannel按名称调用)。

  2. 在ClientSessionListener中设计receivedMessage和disconnected。receivedMessage表示服务器收到客户端发来的消息,disconnected表示服务器收到客户端掉线或logout的信息。

  3. 在ClientSessionListener中需要设置成员变量ManagedReference<ClientSession> sessionRef,并在构造函数中令sessionRef = AppContext.getDataManager().createReference(session)来保存session的一个引用。这样以后可以用sessionRef.get().send()向该客户端发送消息。

  4. 在ClientSessionListener的构造函数中用channelManager.getChannel(channelName)得到channel,再用channel.join(session)将相应的session加入该channel。

  5. 服务器向一个channel群发消息只需用channelManager.getChannel(channelName)得到channel,再用channel.send()发送即可。

  6. 服务器端踢人只需调用AppContext.getDataManager().removeObject(sessionRef.get())即可。(如果没有在构造函数中把该session加入Data Store,那么踢人就不知道怎么实现了……)

客户端主要包括SimpleClientListener。

  1. 在SimpleClientListener中需要设置成员变量SimpleClient simpleClient,并在构造函数中令simpleClient = new SimpleClient(this)来生成一个simpleClient。这个simpleClient可以执行login/logout等操作。

  2. SimpleClientListener的构造函数还需要:设置Properties,login。具体代码为:

    simpleClient = new SimpleClient(this);
    Properties props = new Properties();
    props.put("host", "localhost");
    props.put("port", "1139");
    try {
        simpleClient.login(props);
    } catch (IOException e) {
        e.printStackTrace();
    }
    
  3. 在SimpleClientListener中还需要加入函数

    public PasswordAuthentication getPasswordAuthentication() {
        return new PasswordAuthentication(player,password.toCharArray());
    }
    

    来生成登入信息发送给服务器。

  4. 实现SimpleClientListener和ServerSessionListener接口要求的其他函数:

    public void loggedIn() {
        System.out.println(player + " has logged in");
    }
    public void loginFailed(String reason) {
        System.out.println(player + " failed to log in");
    }
    public void disconnected(boolean graceful, String reason) {
        System.out.println(player + " has disconnected");
    }
    public ClientChannelListener joinedChannel(ClientChannel channel) {
        return new ClientSideChannelListener(); // 其中ClientSideChannelListener是自己写的implements ClientChannelListener的类
    }
    public void receivedMessage(ByteBuffer message) {
        System.out.println(message);
    }
    public void reconnected() {
        System.out.println(player + " has reconnected");
    }
    public void reconnecting() {
        System.out.println(player + " is reconnecting");
    }
    public static void main(String[] args) {
        new ClientSide();
    }
    
  5. 实现类ClientSideChannelListener:

    class ClientSideChannelListener implements ClientChannelListener {
        public void leftChannel(ClientChannel channel) {
            System.out.println("Removed from channel " + channel.getName());
        }
        public void receivedMessage(ClientChannel channel, ByteBuffer message) {
            System.out.println("Message from channel " + channel.getName() + ":" + message);
        }
    }
    

最后附上C/S端的源码,S端就不说了,C端的流程是login,等待,logout,等待,结束。

// ServerSide.java

import java.io.*;
import java.util.*;
import java.nio.*;
import com.sun.sgs.app.*;
public class ServerSide implements AppListener, Serializable {
    private static final long serialVersionUID = 1L;
    public void initialize(Properties props) {
        ChannelManager channelManager = AppContext.getChannelManager();
        channelManager.createChannel("BaseChannel", new ServerSideChannelListener(), Delivery.RELIABLE);
    }
    public ClientSessionListener loggedIn(ClientSession session) {
        System.out.println(session.getName() + " has logged in");
        return new ServerSideSessionListener(session);
    }
}
class ServerSideSessionListener implements ClientSessionListener,Serializable {
    public static final long serialVersionUID = 2L;
    private final ManagedReference<ClientSession> sessionRef;
    private final String sessionName;
    public ServerSideSessionListener(ClientSession session) {
        sessionRef = AppContext.getDataManager().createReference(session);
        sessionName = session.getName();
        ChannelManager channelManager = AppContext.getChannelManager();
        Channel baseChannel = channelManager.getChannel("BaseChannel");
        baseChannel.join(session);
    }
    public void receivedMessage(ByteBuffer message) {
        System.out.println(message);
    }
    public void disconnected(boolean graceful) {
        System.out.println(sessionName + " has disconnected " + (graceful ? "gracefully" : "ungracefully"));
    }
}
class ServerSideChannelListener implements ChannelListener,Serializable {
    private static final long serialVersionUID = 3L;
    public void receivedMessage(Channel channel, ClientSession session, ByteBuffer message) {
        System.out.println("session " + session.getName() + " sent a message on channel " + channel.getName());
        channel.send(session, message);
    }
}

// ClientSide.java

import java.util.*;
import java.io.*;
import java.nio.*;
import java.net.*;
import com.sun.sgs.client.*;
import com.sun.sgs.client.simple.*;
public class ClientSide implements SimpleClientListener {
    protected final SimpleClient simpleClient;
    private String player = "Michael Jackson";
    private String password = "123456";
    public ClientSide() {
        simpleClient = new SimpleClient(this);
        Properties props = new Properties();
        props.put("host", "localhost");
        props.put("port", "1139");
        try {
            simpleClient.login(props);
        } catch (IOException e) {
            e.printStackTrace();
        }
        for (int i = 0;i < 1000000;i++)
            for (int j = 0;j < 10000;j++)
                ;
        simpleClient.logout(false);
        for (int i = 0;i < 1000000;i++)
            for (int j = 0;j < 10000;j++)
                ;
    }
    public PasswordAuthentication getPasswordAuthentication() {
        return new PasswordAuthentication(player,password.toCharArray());
    }
    public void loggedIn() {
        System.out.println(player + " has logged in");
    }
    public void loginFailed(String reason) {
        System.out.println(player + " failed to log in" + ";" + reason);
    }
    public void disconnected(boolean graceful, String reason) {
        System.out.println(player + " has disconnected " + (graceful ? "gracefully" : "ungracefully") + ":" + reason);
    }
    public ClientChannelListener joinedChannel(ClientChannel channel) {
        System.out.println(player + " has joined channel " + channel.getName());
        byte[] buf = {1,2,3};
        try {
            channel.send(ByteBuffer.wrap(buf));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return new ClientSideChannelListener();
    }
    public void receivedMessage(ByteBuffer message) {
        System.out.println(message);
    }
    public void reconnected() {
        System.out.println(player + " has reconnected");
    }
    public void reconnecting() {
        System.out.println(player + " is reconnecting");
    }
    public static void main(String[] args) {
        new ClientSide();
    }
}

class ClientSideChannelListener implements ClientChannelListener {
    public void leftChannel(ClientChannel channel) {
        System.out.println("Removed from channel " + channel.getName());
    }
    public void receivedMessage(ClientChannel channel, ByteBuffer message) {
        System.out.println("Message from channel " + channel.getName() + ":" + message);
    }
}