来自同一页面的多个 websocket,使用 java 作为服务器端
Posted
技术标签:
【中文标题】来自同一页面的多个 websocket,使用 java 作为服务器端【英文标题】:Multiple websockets from the same page with java as the server side 【发布时间】:2015-09-10 04:32:55 【问题描述】:在我的网络应用程序中,我有 2 个 websocket 连接到同一端口上的服务器。一个 websocket 用于聊天信使,另一个用于 同一页面上的 websocket 显示当前查看该事件的总人数。
聊天 Websocket:
var chat = new WebSocket("ws://localhost:8080/chat");
我的聊天窗口上有一个发送按钮,当用户点击发送按钮时,调用 send_message 函数发送消息 通过 websocket 聊天到服务器。
function send_message()
chat.send("Hey There!");
当从服务器接收到消息时,我正在调用 onMessage 函数来获取数据。
chat.onmessage = function(evt) onMessage(evt) ;
function onMessage(evt)
alert('Message Recived from server: "+evt.data);
一旦页面加载,聊天 websocket 就会打开,而当任何用户点击加入事件时,attendeeCount websocket 就会打开 按钮。如果有人加入或离开活动,我想向其他用户显示参加者人数的增加或减少作为实时更新。所以, 假设一个用户正在参加一个活动并且他现在看到的当前参加者人数是 10 并且另一个用户加入了该活动 计数应更新为 11。
当用户单击“加入事件”按钮时,将对服务器进行 ajax 调用,并在参加者表中创建一个条目。所以一旦ajax 调用在我的 ajax 调用的成功回调中是成功的 我正在打开第二个 websocket 连接并将数据发送到服务器 向其他用户显示更新的与会者人数。就像 Facebook 的点赞一样,它会在你眼前更新,而无需 刷新页面。
$.ajax(
type: 'POST',
url: '/mixtri/rest/event/updateAttendeeCount',
contentType: "application/x-www-form-urlencoded",
data: data,
success: function(result)
var attendeeCount = new WebSocket("ws://localhost:8080/attendeeCount");
attendeeCount.onopen = function(evt) onOpen(attendeeCount,result.countOfAttendees) ;
attendeeCount.onmessage = function(evt) onAttendeeJoin(evt) ;
);
/*Function called in ajax success call back to send data to the server via websocket attendeeCount */
function onOpen(attendeeCount,countOfAttendees)
console.log('Connected live Data Update: ');
attendeeCount.send(countOfAttendees);
现在,当从服务器接收到消息时,我正在通过方法 onAttendeeJoin all users 更新 UI 上的与会者计数。
/*Function called when message recieved from the server*/
function onAttendeeJoin(evt)
var attendeeCount = evt.data;
$('#attendeeCount').html(' '+attendeeCount);
现在我有几个问题:
我们可以从同一页面打开 2 个以上的 websocket 吗?因为我还需要更多内容才能在我的页面上显示更多实时更新。
另一个问题是我的参加者计数在 UI 上为其他用户正确更新,但我的聊天 websocket 与 我的参加者计数 websocket。我的意思是,一旦用户在聊天窗口中输入内容并单击发送按钮,onMessage 就会发生冲突 聊天 websocket 的函数被调用得很好,但是附加到attendeeCount websocket 的 onAttendeeJoin 函数也被调用 被调用,我的聊天消息也显示在 $('#attendeeCount').html(' '+attendeeCount) div 中。我无法弄清楚 为什么会这样?虽然 onAttendeeJoin 和 onMessage 函数都绑定到相同类型的事件,即 onmessage,但它们是 来自不同的网络套接字。
如果我得到前两个问题的答案,我的最后一个问题是,现在当用户使用聊天功能时,消息会转到 该页面上的所有用户,无论他们参加什么活动。因此,参加活动的用户 1 发送消息,用户在 event2 也收到了不正确的消息。理想情况下,来自 event1 的用户只能看到来自参加 event1 的用户的消息。 换句话说,同一个聊天室里的人应该只能互相聊天,他们的消息不应该超出聊天范围 房间。如何在 websocket 中将我的事件 ID 与参加该事件的人绑定,以便同一事件聊天中的消息 房间还在里面。
【问题讨论】:
为什么要打开多个webSocket?这只是一个沟通渠道。您可以通过该频道发送与不同主题相关的不同消息。你真的不应该在同一个页面/服务器之间需要多个 webSocket。 @jfriend00 我明白你的意思,确实有道理。但是,我如何确定我从服务器收到的消息是聊天消息还是与会者人数更新,或者如果我还需要该页面上的更多实时更新,则可以是其他内容? 一般的想法是,你不只是发送数据,而是发送消息名称和一些数据。然后,所有接收代码可以根据消息名称决定做什么。您可能对 socket.io 感兴趣,它在 webSocket 之上为您创建此格式,或者您可以使用 webSocket 自己做,如 here 所示。 @jfriend00 我只是按照您发布的外观查看了 Websockets 的代码。其实我之前也看过那个链接,但我想我错过了主要部分。它使用的是一种 if else 的 switch case,它仅用于处理从服务器接收到的不同类型的数据。这确实是有道理的。让我重新构建我的代码尝试一下。同时对我的问题 3 有任何想法吗? webSockets 本身不具备您要求的“参加活动”功能。使用普通的 webSockets,您必须跟踪哪个套接字在哪个事件中,并且当您想要发送到一个事件时,您只发送到与该事件关联的连接的 webSockets。这将是您自己的所有代码。同样,我上面提到的 socket.io 库内置了这个功能。这听起来像你真正想要的。 socket.io 也有 Java 服务器支持。 socket.io 有内置的聊天室,并且能够向给定聊天室中的人广播。 【参考方案1】:我会把我的 cmets 放到一个答案中:
我们可以从同一页面打开 2 个以上的 websocket 吗?因为我需要 以及在我的页面上显示更多实时更新。
是的,你可以,但你不应该这样做。为什么要打开多个 webSocket?这只是一个沟通渠道。您可以通过该频道发送与不同主题相关的不同消息。你真的不应该在同一个页面/服务器之间需要多个 webSocket。
一般的想法是,您不只是发送数据,而是发送消息名称和一些数据。然后,所有接收代码可以根据消息名称决定做什么。您可能对 socket.io 感兴趣,它在 webSocket 之上为您创建这种格式,或者您可以使用 webSocket 自己做,如 here 所示。
如果我得到前两个问题的答案,我的最后一个问题是,对 现在,当用户使用聊天功能时,消息会发送到所有 该页面上的用户,无论他们参加什么活动。所以一个 参加活动 1 的用户发送消息,参加活动 2 的用户得到 该消息也是不正确的。理想情况下,来自 event1 的用户可以 只看到来自参加 event1 的用户的消息。换句话说,人们 在同一个聊天室应该只能互相聊天 他们的消息不应该出现在聊天室之外。我怎样才能绑定我的 websocket 中的事件 id 与参加该事件的人一起,以便 同一事件聊天室中的消息仍保留在其中。
webSockets 本身不具备您所要求的“参加活动”功能。使用普通的 webSockets,您必须跟踪哪个套接字在哪个事件中,并且当您想要发送到一个事件时,您只发送到与该事件关联的连接的 webSockets。这将是您自己的所有代码。同样,我上面提到的 socket.io 库内置了这个功能。这听起来像你真正想要的。 socket.io 也有 Java 服务器支持。 socket.io 具有内置的聊天室,并且能够向给定聊天室中的人广播。
【讨论】:
我正在处理这样一个案例,解耦某些 websocket 功能似乎是有意义的。我的 SPA 会将标头发送到 Stomp 服务器,这些标头为特定的 websocket 连接会话存储,而断开连接负责清理。同时,我的应用程序将有一个用于用户通知、一般私人消息传递等的通用 websocket 连接。对所有内容使用相同的 websocket 连接似乎没有意义;如果决定将不同的微服务转移到另一个集群,那就意味着你不能。【参考方案2】:可以在同一个网站打开两个多个 web Socket 连接。
如果您应该以一定的延迟打开两个 web Socket 连接,以便浏览器可以识别两者。
例如。在index.html
<!DOCTYPE html>
<html>
<head>
<title></title>
<script type="text/javascript" src="js/websocket1.js"></script>
</head>
<body>
<!-- Other code goes here -->
<script type="text/javascript" src="js/websocket2.js"></script>
</body>
</html>
这里websocket1.js
和websocket2.js
是两个javascript源文件,其中两个new webSocket(URL)
是在一定的时间间隔内打开的。
这还取决于您使用的浏览器和部署的服务器。顺便说一句,我使用 Chrome 和 GlassFish 4 作为服务器,这工作正常。
【讨论】:
以上是关于来自同一页面的多个 websocket,使用 java 作为服务器端的主要内容,如果未能解决你的问题,请参考以下文章
如何使用同一端口(使用码头 8)拥有具有多个上下文的 websocket
Laravel:如何打开多个域(不是子域)以显示来自同一服务器的页面(无重定向)?