【问题标题】:Google App Engine Channel APIGoogle App Engine 频道 API
【发布时间】:2012-01-06 11:05:05
【问题描述】:

我正在尝试学习 GAE 的频道 API(使用 Java),但我不知道从哪里开始。

我浏览了Channel API Overview (Java),但出于简洁目的,那里发布的代码并不完整。

由于我是新手,如果有完整的示例代码将非常有帮助。

谢谢, 雪莉

【问题讨论】:

    标签: java google-app-engine channel-api


    【解决方案1】:

    您链接到的 Channel API 概述中的代码非常完整,只是有点乱七八糟。我承认,一旦你理解了它,我觉得它比他们看起来的要简单得多,但我很高兴他们在提供太多信息方面犯了错误。

    很难在不引入无关信息的情况下为此提供完整的解决方案,因为您使用 Channel API 的某些方式在某种程度上取决于您现有应用的基础架构。出于这个原因,我试图详细说明 AppEngine 文档提供的内容,希望您能更好地理解。如果您有任何问题,cmets 将允许您提出具体问题。

    首先,一些词汇:

    • Channel Message:您希望发送给客户的消息(可能是您最初使用 Channel API 的原因)。
    • Channel Key:用户唯一的字符串以及用户尝试发送消息的范围。
    • Channel Token:任何客户端唯一的字符串。每位客户每 2 小时 1 个频道令牌。
    • 频道服务: AppEngine 服务器端类,提供创建频道并通过它们发送频道消息的方法。

    在服务器上,您需要执行以下操作:

    ChannelService channelService = ChannelServiceFactory.getChannelService();
    
    // The channelKey can be generated in any way that you want, as long as it remains
    // unique to the user.
    String channelKey = "xyz";
    String token = channelService.createChannel(channelKey);
    

    获得令牌后,您只需通过某种方式将其发送到客户端代码。您链接到的 AppEngine 文档通过从 Java servlet 提供 HTML 并调用 index.replaceAll("\\{\\{ token \\}\\}", token) 来完成此操作。

    这是如何工作的,他们所做的是将文字字符串 {{ token }} 放入他们的 JavaScript 代码中(如下所示),所以无论 {{ token }} 出现在 JavaScript 代码中的什么地方,它都会被替换为由上面的channelService.createChannel(...) 调用生成的实际令牌。请注意,您不需要需要将令牌注入您以这种方式提供服务的客户端代码中,但这是一个很好的起点,因为他们就是这样做的(并记录下来)。


    现在您已经将令牌注入到 JavaScript 中,您需要将带有通道令牌的代码获取到客户端(请注意,如上所述,您也可以只获取客户端的令牌,然后以这种方式创建通道)。他们拥有的代码是:

    <body>
      <script>
        channel = new goog.appengine.Channel('{{ token }}');
        socket = channel.open();
        socket.onopen = onOpened;
        socket.onmessage = onMessage;
        socket.onerror = onError;
        socket.onclose = onClose;
      </script>
    </body>
    

    他们删除了有关如何从服务器上的文件中读取此内容的详细信息,但同样,您可以以任何您喜欢的方式执行此操作。您也可以在 JavaServlet 中使用 resp.getWriter().print(index) 直接打印字符串,其中 index 是存储上面列出的 HTML/JavaScript 内容的字符串。就像我最初所说的那样,最适合您的应用现有基础架构的事情取决于您。

    他们打算让您定义自己的 JavaScript 函数 onOpenedonMessageonErroronClose,分别在通道打开、接收消息、遇到错误或关闭时调用.您可能希望创建简单的实现以更好地了解正在发生的事情:

    function onOpened() {
        alert("Channel opened!");
    }
    
    function onMessage(msg) {
        alert(msg.data);
    }
    
    function onError(err) {
        alert(err);
    }
    
    function onClose() {
        alert("Channel closed!");
    }
    

    我仍然建议将它们分成单独的函数,这样您就可以更轻松地扩展它们来玩弄和解决问题。有关 JavaScript API 的更多详细信息,请参阅Channel API JavaScript Reference


    您需要建立一种机制来获取要从客户端发送到服务器的数据。再一次,你希望如何做到这一点并不重要。 AppEngine 文档建议设置一个XMLHttpRequest 来实现该目的。

    sendMessage = function(path, opt_param) {
      path += '?g=' + state.game_key;
      if (opt_param) {
        path += '&' + opt_param;
      }
      var xhr = new XMLHttpRequest();
      xhr.open('POST', path, true);
      xhr.send();
    };
    

    这里,opt_param 只是一串可选参数,格式为x=1&amp;y=2&amp;z=3。这是他们为 Tic-Tac-Toe 示例应用程序构建的所有基础设施,对于 Channel API 的功能并不重要;就像我说的,你可以随意拨打这个电话。

    path 是您的 servlet 的路径(您需要在 web.xml 文件中设置),它应该处理消息发送和接收(请参阅以下部分)。


    将消息从客户端发送到服务器后,您将需要一个 servlet,它可以使用相同的通道密钥向所有客户端发送更新

    ChannelService channelService = ChannelServiceFactory.getChannelService();
    
    // This channelKey needs to be the same as the one in the first section above.
    String channelKey = "xyz"
    
    // This is what actually sends the message.
    channelService.sendMessage(new ChannelMessage(channelKey, "Hello World!"));
    

    上面的channelService.sendMessage(...) 调用是实际发送消息的内容,以便您在上一节中定义的onMessage 函数可以接收它。


    我希望这个答案是完整的(就此而言,是正确的)足以帮助您入门。他们在文档中的大部分内容(以及我在此处的代码)都可以复制和粘贴,只需稍作调整即可。

    【讨论】:

    • 非常感谢 :) 我对此感到困惑.. index.replaceAll("\\{\\{ token \\}\\}", token) 现在我可以开始了。 . :)
    • 它工作正常.. :),我如何多播消息..?有任何 API 吗?
    • 这个答案值得某种奖励:)
    • 你是说来自 Java 的单个 sendMessage 调用将消息发送到多个客户端,每个客户端都有不同的令牌,共享通道密钥?这似乎与developers.google.com/appengine/docs/java/channel/… 的文档相矛盾,该文档指出“一次只有一个客户端可以使用给定的客户端 ID 连接到通道,因此应用程序不能使用客户端 ID 进行扇出。”如果它像你说的那样工作,那就太好了。但我认为不会。
    • AFAIK,所描述的扇出方法在本地有效,但在生产中无效。您需要为不同的客户端分配不同的通道密钥并遍历它们,将更新发送给每个客户端。
    【解决方案2】:

    我是 StackOverflow 的新手,不确定这个问题是否仍然存在,但如果您仍在寻找使用 Google 的 Channel API 的完整 Java 示例,ServerSide(Java) 和 Client(Java) 都可以找到详细描述我写在这里:http://masl.cis.gvsu.edu/2012/01/31/java-client-for-appengine-channels/

    它列出了从创建通道(客户端和服务器)、在通道上发送消息(客户端和服务器)以及 Java 客户端可以用来与通道交互的简单框架的所有内容。我也很难理解 Google 的文档并理解这一切。我希望这些信息仍然具有相关性和帮助性:-)

    完整的源代码和聊天示例可以在 GitHub 上找到:https://github.com/gvsumasl/jacc

    这是一些示例代码,希望对您有所帮助:-)


    Java 客户端通道创建(使用 ChannelAPI 框架:Jacc)

    ChatListener chatListener = new ChatListener();
    ChannelAPI channel = new ChannelAPI("http://localhost:8888", "key", chatListener);
    channel.open();
    

    Java 服务器端通道创建:

    public class ChatChannelServlet extends HttpServlet {
      @Override
      public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {    
        String channelKey = req.getParameter("c");
    
        //Create a Channel using the 'channelKey' we received from the client
        ChannelService channelService = ChannelServiceFactory.getChannelService();
        String token = channelService.createChannel(channelKey);
    
        //Send the client the 'token' + the 'channelKey' this way the client can start using the new channel
        resp.setContentType("text/html");
        StringBuffer sb = new StringBuffer();
        sb.append("{ \"channelKey\":\"" + channelKey + "\",\"token\":\"" + token + "\"}");
    
        resp.getWriter().write(sb.toString());
      }
    }
    

    Java 客户端消息发送(使用 ChannelAPI 框架:Jacc)

    /***
    * Sends your message on the open channel
    * @param message
    */
    public void sendMessage(String message){
    try {
            channel.send(message, "/chat");
        } catch (IOException e) {
            System.out.println("Problem Sending the Message");
        }
    }
    

    Java 服务器端消息发送:

    public class ChatServlet extends HttpServlet {
      @Override
      public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        String channelKey = req.getParameter("channelKey");
        String message = req.getParameter("message");
    
        //Send a message based on the 'channelKey' any channel with this key will receive the message
        ChannelService channelService = ChannelServiceFactory.getChannelService();
        channelService.sendMessage(new ChannelMessage(channelKey, message));
      }
    }
    

    【讨论】:

    • 我通过拉取请求修复了它。希望他们接受。
    • jacc 在什么许可证下?
    猜你喜欢
    • 2014-08-23
    • 2012-06-08
    • 2012-06-28
    • 2013-08-09
    • 1970-01-01
    • 1970-01-01
    • 2013-06-23
    • 2017-10-12
    • 2012-08-24
    相关资源
    最近更新 更多