大气框架:多次广播广播消息

时间:2015-12-02 11:32:31

标签: java sockets long-polling atmosphere

我目前正在根据这个例子开发一个简单的聊天多房间:

https://github.com/Atmosphere/atmosphere-samples/blob/master/samples/chat-multiroom/

我的开发环境:

  • Tomee Plus 1.7.2服务器
  • Atmosphere-runtime版本2.4.0
  • Atmosphere-cdi版本2.4.0
  • Java EE 1.7
  • 使用长轮询协议

在解释我的问题之前,我已经实现了聊天室的全局机制:

  1. 用户A连接到套接字" chat / all"。这个插座允许 发送ou接收他和他的对话者之间的任何通知。

  2. 用户A从第一个网络应用程序发出聊天请求并等待 (弹出式微调器)来自用户B的响应。

  3. 用户B也连接到套接字" chat / all"。用户B检查 每次,从第二个Web应用程序,如果有新的聊天请求 (来自数据库的SQL请求)。如果他找到了新的请求,他可以或 不接受这个要求。

  4. 用户B接受来自用户A的聊天请求。此时,通过 socket" chat / all",用户B按下一条消息表示他已接受此消息 请求。之后,用户B连接到第二个插座 "聊天/ 1" (特定聊天室的随机ID)。他现在在等 (用户B之类的弹出式微调器)用于连接到用户A的用户A. 插座。

  5. 用户A收到此消息并连接到套接字" chat / 1"。 从服务器,用户A现在连接到此聊天室。 此聊天室中有两个用户,我向其广播消息 只有用户B通知用户A已连接并关闭弹出窗口 旋转器。

  6. 当我只为一个资源广播消息时没有问题。但是,当我为两个用户广播消息时," onMessage"方法被多次调用!

    这是关于管理聊天室的代码:

    @ManagedService(path = "/chat/{id_room}")
    public final class ChatRoom {
    
     //many static final private attribute
    
     private static final Logger logger = LoggerFactory.getLogger(Chat.class);
    
     @PathParam("id_room")
     private String idChatRoom;
    
     private final static String CHAT = "/chat/";
    
     private final HashMap<Integer, List<String>> users = new HashMap<Integer, List<String>>();
    
     private Universe universe;
    
     private BroadcasterFactory broadcasterFactory = Universe.broadcasterFactory();
    
     private AtmosphereResourceFactory resourceFactory = Universe.resourceFactory();    
    
     private ChatMessageEncoderDecoder chatEncodeDecode = new ChatMessageEncoderDecoder();
    
    @Message(encoders = { ChatMessageEncoderDecoder.class }, decoders = { ChatMessageEncoderDecoder.class })
     public final void onMessage(AtmosphereResource r, final ChatMessage message) throws UnsupportedEncodingException {
        Integer chatRoomId = !NOTIFICATION_SOCKET_ALL.equals(idChatRoom) == true ? Integer.parseInt(idChatRoom) : 0;
        [...]
        if(...) {
            [...]
        }
        else {
            roomsList.add(idChatRoom);
            boolean messageEmpty = "".equals(message.getMessage());
            boolean chatConnectedWithTwoUsers = users.get(chatRoomId).size() > 1;
            boolean chatConnectedWithOneUser = users.get(chatRoomId).size() == 1;
                if(chatConnectedWithTwoUsers && MESSAGE_EVENT.equals(message.getEvent())) { //communication between two users to the chat room id
                    Users user = CDIUtil.getBean(RechercheUserService.class).getUserChat(message.getMail());
                    if(user != null){
                        try {
                            List<String> listUsersFromRoom = users.get(chatRoomId);
                            message.setUsers(listUsersFromRoom);
                            message.setEvent(MESSAGE_EVENT);
                            logger.info("{} a envoyé le message {}", message.getAuthor(), message.getMessage());
    
                            String messageToSend = chatEncodeDecode.encode(message);
                            broadcasterFactory.lookup(CHAT + idChatRoom).broadcast(messageToSend);
    
                            String messageUtf8 = new String(message.getMessage().getBytes(), "UTF-8");
                            CDIUtil.getBean(MessageRoomsService.class).createMessageContents(idChatRoom, user, messageUtf8);
                        } catch (IMException e) {
                            message.setEvent(MESSAGE_NOT_REGISTER_EVENT);
                            logger.error("Impossible d'enregistrer le message de l'utilisateur");
                        }
                    }
                    else{
                        message.setEvent(USER_NOT_EXIST_EVENT);
                        logger.error("Utilisateur Inconnu");
                    }
                }
                else if(chatConnectedWithOneUser) { //two users connected to the chat room id
                    users.get(chatRoomId).add(r.uuid()); 
                    logger.info("L'utilisateur {} a rejoint le chat {}", r.uuid(), idChatRoom);
    
                    AtmosphereResource resource = resourceFactory.find(users.get(chatRoomId).get(0)); //get the first user connected to the chat room
    
                    List<String> listUsersFromRoom = users.get(chatRoomId);
                    message.setUsers(listUsersFromRoom);
                    message.setEvent(CHAT_COMPLETE_EVENT);
    
                    String messageToSend = chatEncodeDecode.encode(message);
                    broadcasterFactory.lookup(CHAT + idChatRoom).broadcast(messageToSend, resource);
                }
            }
       }
    }
    

    因此,当广播完成时,在界面用户上显示3条消息。例如,用户A发送消息&#34;您好,我能为您做什么?&#34;,用户B看到此消息的3次。

    我认为有三条消息,因为两个套接字上有三个资源处于活动状态。的确,第一个插座&#34;聊天/全部&#34;对于一个资源(用户B)和第二个套接字&#34; chat / 1&#34;对两个资源(用户A和用户B)有效。有三种资源。

    有没有人已经面临这个问题?或者是否有人知道如何解决它?

1 个答案:

答案 0 :(得分:0)

我也有同样的问题..我已经解决了阅读此链接的问题Multiple messages arrive as single response body or message received are incomplete

我在我的Atmosphere Servlet中添加了web.xml这个init-param

<init-param>
   <param-name>org.atmosphere.cpr.AtmosphereInterceptor</param-name>
   <param-value>org.atmosphere.client.TrackMessageSizeInterceptor</param-value>
</init-param>

和客户端我在请求中添加了trackMessageLength : true

var request = { url: document.location.toString() + 'chat',
                contentType : "application/json",
                logLevel : 'debug',
                transport : 'long-polling' ,
                trackMessageLength : true,
                fallbackTransport: 'long-polling'};

正如此链接中所述

  

如果您广播多条消息并且底层服务器将它们缓冲在内存中,则可以使用多条消息而不是单条消息来调用atmopshere.js回调或函数。如果您使用的是文本,则可能不是问题,但如果您使用的是JSON,则解析可能会失败,因为您的回调/函数会被多个JSON消息调用。

我希望这也适合你!