GCM CCS服务器实现未接收上游消息

Bog*_*rac 8 java xmpp google-cloud-messaging

我已经为Android应用程序和Web服务器之间的双向消息实现了新的GCM CCS.下游消息(网络设备)完美运行.不幸的是,服务器上没有收到上游消息(device-web).它们似乎确实在客户端发送(请参阅下面的Android应用程序日志消息),但服务器上没有收到任何内容.

D/GCM? GcmService start Intent { act=com.google.android.gcm.intent.SEND flg=0x10 pkg=com.google.android.gms cmp=com.google.android.gms/.gcm.GcmService (has extras) } com.google.android.gcm.intent.SEND
Run Code Online (Sandbox Code Playgroud)

我认为Android方面没有任何问题,而是在服务器端.问题是,我无法弄清楚出了什么问题,因为连接仍然存在,我确实收到了来自GCM服务器的一些消息,比如ACK.那么为什么没有收到正常的消息?有人有任何想法吗?

值得一提的其他一些细节是使用的Web服务器是Glassfish,我在Servlet中启动XMPP连接.下面是一些片段.

编辑:正如我在答案中所述,阻止服务器上收到任何消息的主要问题已得到解决.但是,仍然没有收到相当多的消息(大约50%).

例如,我在后台线程上一个接一个地发送2条消息,每次用户在Android应用程序中进行更改(按下按钮,因此每批2之间至少有几秒钟).有时我在服务器上收到这两条消息,有时我只收到其中的一条消息,有时甚至什么都没发生......这是一个严重的问题,特别是对于依赖这项技术的应用程序而言.任何人都可以得到进一步的帮助,以解决这个问题吗?

更多信息:我很确定这不是客户端相关的,因为每条消息都被发送,就像你在上面的logcat日志中看到的那样,我也会在一段时间后收到"event:sent"GCM广播(不是立即,也许,也许像5分钟).所以它必须是基于GCM或基于服务器的东西.

public class CcsServlet extends HttpServlet
{
    private static Logger logger = Logger.getLogger(CcsServlet.class.getName());


    public void init(ServletConfig config) throws ServletException
    {
        CcsManager ccsManager = CcsManager.getInstance();
        try
        {
            ccsManager.connect();
        }
        catch (Exception e)
        {
            logger.warning("Cannot connect to CCS server.");
            e.printStackTrace();
        }
    }
}


public class CcsManager
{
    private static XMPPConnection connection;
    private static Logger logger = Logger.getLogger(CcsManager.class.getName());


    public static final String GCM_SERVER = "gcm.googleapis.com";
    public static final int GCM_PORT = 5235;

    private static CcsManager sInstance = null;
    private static final String USERNAME = "xxxxxxxxxx" + "@gcm.googleapis.com";
    private static final String PASSWORD = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";




        public CcsManager()
        {
            // Add GcmPacketExtension
            ProviderManager.getInstance().addExtensionProvider(
                    GcmPacketExtension.GCM_ELEMENT_NAME,
                    GcmPacketExtension.GCM_NAMESPACE, new PacketExtensionProvider()
                    {
                        public PacketExtension parseExtension(XmlPullParser parser) throws Exception
                        {
                            String json = parser.nextText();
                            return new GcmPacketExtension(json);
                        }
                    });
        }

        public static CcsManager getInstance()
        {
            if (sInstance == null)
                sInstance = new CcsManager();
            return sInstance;
        }

/**
 * Connects to GCM Cloud Connection Server
 */
public void connect() throws IOException, XMPPException
{
    ConnectionConfiguration config = new ConnectionConfiguration(GCM_SERVER, GCM_PORT);
    config.setSecurityMode(ConnectionConfiguration.SecurityMode.enabled);
    config.setReconnectionAllowed(true);
    config.setRosterLoadedAtLogin(false);
    config.setSendPresence(false);
    config.setSocketFactory(SSLSocketFactory.getDefault());
    config.setDebuggerEnabled(false);
    connection = new XMPPConnection(config);
    connection.connect();
    connection.addConnectionListener(new ConnectionListener()
    {
        public void reconnectionSuccessful()
        {
            logger.info("Reconnecting..");
        }

        public void reconnectionFailed(Exception e)
        {
            logger.log(Level.INFO, "Reconnection failed.. ", e);
        }

        public void reconnectingIn(int seconds)
        {
            logger.log(Level.INFO, "Reconnecting in %s secs", seconds);
        }

        public void connectionClosedOnError(Exception e)
        {
            logger.info("Connection closed on error.");
        }

        public void connectionClosed()
        {
            logger.info("Connection closed.");
        }
    });

    // Handle incoming packets
    connection.addPacketListener(new PacketListener()
    {
        public void processPacket(Packet packet)
        {
            logger.log(Level.INFO, "Received: " + packet.toXML());
            Message incomingMessage = (Message) packet;
            GcmPacketExtension gcmPacket =
                    (GcmPacketExtension) incomingMessage.getExtension(GcmPacketExtension.GCM_NAMESPACE);
            String json = gcmPacket.getJson();
            try
            {
                @SuppressWarnings("unchecked")
                Map<String, Object> jsonObject =
                        (Map<String, Object>) JSONValue.parseWithException(json);

                // present for "ack"/"nack", null otherwise
                Object messageType = jsonObject.get("message_type");

                if (messageType == null)
                {
                    // Normal upstream data message
                    handleIncomingDataMessage(jsonObject);

                    // Send ACK to CCS
                    String messageId = jsonObject.get("message_id").toString();
                    String from = jsonObject.get("from").toString();
                    String ack = createJsonAck(from, messageId);
                    send(ack);
                }
                else if ("ack".equals(messageType.toString()))
                {
                    // Process Ack
                    handleAckReceipt(jsonObject);
                }
                else if ("nack".equals(messageType.toString()))
                {
                    // Process Nack
                    handleNackReceipt(jsonObject);
                }
                else
                {
                    logger.log(Level.WARNING, "Unrecognized message type (%s)",
                            messageType.toString());
                }
            }
            catch (ParseException e)
            {
                logger.log(Level.SEVERE, "Error parsing JSON " + json, e);
            }
            catch (Exception e)
            {
                logger.log(Level.SEVERE, "Couldn't send echo.", e);
            }
        }
    }, new PacketTypeFilter(Message.class));


    // Log all outgoing packets
    connection.addPacketInterceptor(new PacketInterceptor()
    {
        public void interceptPacket(Packet packet)
        {
            logger.log(Level.INFO, "Sent: {0}",  packet.toXML());
        }
    }, new PacketTypeFilter(Message.class));

    connection.login(USERNAME, PASSWORD);
}
    }
Run Code Online (Sandbox Code Playgroud)

Bog*_*rac 6

似乎Web应用程序在服务器上部署了两次.这导致创建XMPP连接的servlet初始化一次,然后销毁,然后再次初始化.对于与GCM(dho ..)的连接,这个序列可能不是一件好事.

只需确保servlet只初始化一次.通过在其init()和destroy()方法中使用记录器来检查这一点.如果确实多次调用它,请尝试将Web模块分配给特定的虚拟服务器以进行部署.我相信这与Web服务器不同.对于Glassfish,您需要在管理控制台(localhost:4848)中执行此操作.

这解决了更大的问题.我遇到的另一个问题是上游消息传递根本不可靠.有时来自同一设备的多个连续上游消息可以完美地工作,只能尝试另一个未完全推送到服务器的消息.还没有弄清楚这个问题的任何模式......如果我找到其他任何东西,我会回来的.

编辑:显然在本地服务器上使用实现时出现问题.移动到远程服务器(暂存VPS),问题似乎消失了.服务器接收每条消息.如果问题仍然存在,我会回来的,但我对此表示怀疑.我认为本地问题是由于我的ISP,或者heck,甚至是我本地的Wi-Fi连接.关于究竟是什么造成这种情况,我没有完整的答案,但至少它在登台服务器上运行良好.