websocket 聊天室搭建技术点

spring 配置:

<bean id="websocket" class="com.xianlaohu.yao.controller.socket.SocketHandler"/>

<websocket:handlers>
   <websocket:mapping path="/room/chat" handler="websocket"/>
   <websocket:handshake-interceptors>
      <bean class="com.xianlaohu.yao.controller.socket.HandshakeInterceptor"/>
   </websocket:handshake-interceptors>
</websocket:handlers>

依赖包:

<dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-websocket</artifactId>
   <version>${spring.version}</version>
</dependency>

<dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-messaging</artifactId>
   <version>${spring.version}</version>
</dependency>

nginx 配置

upstream home-dev-ws{

server IP: port;

}

#websocket 需要加下这个

map $http_upgrade $connection_upgrade {

default upgrade;

‘‘      close;

}

server {

listen 80;

server_name xxxxx.com

rewrite ^(.*)/__dev/?$ /__dev/;

if ( $http_cookie ~* "(.*)$")

{

set $user_cookie $1;

}

location /room/chat {

proxy_pass  http://home-dev-ws;

proxy_redirect    off;

proxy_read_timeout 43200;

keepalive_timeout 600;  # 链接保持的时间

proxy_set_header X-Real-IP $remote_addr;

proxy_set_header Host $host;

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

proxy_http_version 1.1;

proxy_set_header Upgrade $http_upgrade;

proxy_set_header Connection "upgrade";

}

}

socket 链接已经信息处理handler:

public class SocketHandler extends TextWebSocketHandler {

    private final static Logger logger = LoggerFactory.getLogger(SocketHandler.class);

    private static Map<String, UserWebSocketSession> users= new HashMap<>(); //所有在线用户

    private static Map<String, Set<String>> rooms = new HashMap<>();         //所有房间

    private final static String roomId = "12345";

    /**
     * 在UI在用js调用websocket.send()时候,会调用该方法
     */
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {

        super.handleTextMessage(session, message);
        UserWebSocketSession userWebSocketSession = users.get(session.getId());
        if(userWebSocketSession != null && userWebSocketSession.getRoomId() != null){

            Set<String> room = rooms.get(userWebSocketSession.getRoomId());
            logger.info("----12---room:{}"+ JsonUtil.toJSON(room));
            if(room == null || room.size() <= 0){
                return;
            }

            sendMessageToUsers(session, room, message);
            logger.info("----------1");
        }else {
            logger.error("current_user could not send messege userWebSocketSession:{}", JsonUtil.toJSON(userWebSocketSession));
        }
    }

    /**
     * 连接成功时候,会触发UI上onopen方法
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {

        if(users.get(session.getId()) == null){
            UserWebSocketSession userWebSocketSession = new UserWebSocketSession();
            userWebSocketSession.setRoomId(roomId);
            userWebSocketSession.setSession(session);
            users.put(session.getId(), userWebSocketSession);

            Set<String> room = rooms.get(roomId);
            if(room == null){
                room = new HashSet<>();
                rooms.put(roomId, room);
            }
            logger.info("----====-----rooms:{}" + JsonUtil.toJSON(rooms));
            room.add(session.getId());
            logger.info("---------------room:{}" + JsonUtil.toJSON(room));
            logger.info("new user ====session_id:{}", session.getId());

        }
        logger.info("connect to the websocket success..... .");

    }

    /**
     * Handle an error from the underlying WebSocket message transport.
     * @param session
     * @param exception
     * @throws Exception
     */
    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {

        UserWebSocketSession userSession= users.get(session.getId());
        if(userSession == null){
            return;
        }

        Set<String> room = rooms.get(userSession.getRoomId());//查找所在房间
        room.remove(session.getId());//从房间中去除

        if(room.size() <=0){         //房间没人,清除房间
            rooms.remove(userSession.getRoomId());
        }

        users.remove(session.getId());//从在线用户列表里移除
        logger.info("websocket connection closed......");
    }

    /**
     * Invoked after the WebSocket connection has been closed by either side,
     * or after a transport error has occurred. Although the session may technically still be open,
     * depending on the underlying implementation, sending messages at this point is discouraged and most likely will not succeed.
     * @param session
     * @param closeStatus
     * @throws Exception
     */

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) {
        logger.info("----close---11-closeStatus:{} session-status:{}__ user_lise:{}", JsonUtil.toJSON(closeStatus), session.isOpen(), users.size());
        UserWebSocketSession userSession= users.get(session.getId());
        if(userSession == null){
            return;
        }

        Set<String> room = rooms.get(userSession.getRoomId());//查找所在房间
        room.remove(session.getId());                         //从房间中去除
        if(room.size() <=0){               //房间没人,清除房间
            rooms.remove(userSession.getRoomId());
        }
        users.remove(session.getId());     //从在线用户列表里移除
        logger.info("----------1111_ user_size:{}"+users.size() );
    }

    /*
    Whether the WebSocketHandler handles partial messages.
     If this flag is set to true and the underlying WebSocket server supports partial messages,
      then a large WebSocket message, or one of an unknown size may be split and maybe received over multiple calls to WebSocketHandler.handleMessage(WebSocketSession,
       WebSocketMessage). The flag WebSocketMessage.isLast() indicates if the message is partial and whether it is the last part.
     */
    @Override
    public boolean supportsPartialMessages() {

        logger.info("websocket connection supportsPartialMessages......");
        return false;
    }

    /**
     * 给某个用户发送消息
     * @param currentSession
     * @param message
     */
    public void sendMessageToUsers(WebSocketSession currentSession, Set<String> sessionIdSet, TextMessage message) {

        logger.info("currentSession_id:{}=======sessionIdSet:{}", currentSession.getId(), sessionIdSet.size());

        Iterator<String> iterator = sessionIdSet.iterator();
        while (iterator.hasNext()) {
            String sessionId = iterator.next();

            if(sessionId.equals(currentSession.getId())){//信息不发给自己
                continue;
            }

            UserWebSocketSession user = users.get(sessionId);
            String fromUserName = user.getUserName();
            WebSocketSession userSession = user.getSession();
            logger.info("-send to--session_id:{},  user_name:{}", userSession.getId(), fromUserName);
            if (!userSession.equals(currentSession)) {
                if (userSession.isOpen()) {
                    sendMessageToUser(userSession, fromUserName, message);
                }
            }
        }
    }

    /**
     * 给某个用户发送消息
     *
     * @param message
     */
    public void sendMessageToUser(WebSocketSession userSession, String userName,  TextMessage message) {

        logger.info("======send message to session_id:{}: name:{}", userSession.getId(), userName);
        if(userSession != null && userSession.isOpen()){
            TextMessage returnMessage = new TextMessage(new DateTime().toString("HH:mm:ss")+"/<br>"+(userName != null? userName:"")+"   "+message.getPayload());
            try {
                userSession.sendMessage(returnMessage);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

   }

拦截器:

HandshakeInterceptor
public class HandshakeInterceptor extends HttpSessionHandshakeInterceptor {

    @Override
    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
                                   Map<String, Object> attributes) throws Exception {

        boolean b = super.beforeHandshake(request, response, wsHandler, attributes);
        System.out.println("Before Handshake=====:"+ b);

        return b;
    }

    @Override
    public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception ex) {
        super.afterHandshake(request, response, wsHandler, ex);
        System.out.println("after  Handshake=====: 1");
    }

}

交互界面------

<%@ page language="java" contentType="text/html; charset=UTF-8"
         pageEncoding="UTF-8"%>

<!doctype html>
<html>
<head>
    <title>WebSocket/SockJS Echo Sample (Adapted from Tomcat‘s echo sample)</title>
    <style type="text/css">
        #connect-container {
            float: left;
            width: 400px
        }

        #connect-container div {
            padding: 5px;
        }

        #console-container {
            float: left;
            margin-left: 15px;
            width: 400px;
        }

        #console {
            border: 1px solid #CCCCCC;
            border-right-color: #999999;
            border-bottom-color: #999999;
            height: 170px;
            overflow-y: scroll;
            padding: 5px;
            width: 100%;
        }

        #console p {
            padding: 0;
            margin: 0;
        }
    </style>

    <%--<script src="http://cdn.sockjs.org/sockjs-0.3.min.js"></script>--%>

    <script type="text/javascript">
        var ws = null;
        var url = null;
        var transports = [];

        function setConnected(connected) {
            document.getElementById(‘connect‘).disabled = connected;
            document.getElementById(‘disconnect‘).disabled = !connected;
            document.getElementById(‘echo‘).disabled = !connected;
        }

        function connect() {
            alert("url:"+url);
            if (!url) {
                alert(‘Select whether to use W3C WebSocket or SockJS‘);
                return;
            }

            ws = (url.indexOf(‘sockjs‘) != -1) ?
                    new SockJS(url, undefined, {protocols_whitelist: transports}) : new WebSocket(url);

            ws.onopen = function () {
                setConnected(true);
                log(‘Info: connection opened.‘);
            };
            ws.onmessage = function (event) {
//                log(‘Received: ‘ + event.data);
                  log(event.data);

            };
            ws.onclose = function (event) {
                setConnected(false);
                log(‘Info: connection closed.‘);
                log(event);
            };
        }

        function disconnect() {
            if (ws != null) {
                ws.close();
                ws = null;
            }
            setConnected(false);
        }

        function echo() {
            if (ws != null) {
                var message = document.getElementById(‘message‘).value;
//                log(‘Sent: ‘ + message);
                log( message);

                ws.send(message);
            } else {
                alert(‘connection not established, please connect.‘);
            }
        }

        function updateUrl(urlPath) {
            if (urlPath.indexOf(‘sockjs‘) != -1) {
                url = urlPath;
                document.getElementById(‘sockJsTransportSelect‘).style.visibility = ‘visible‘;
            }
            else {
                if (window.location.protocol == ‘http:‘) {
                    url = ‘ws://‘ + window.location.host + urlPath;
                } else {
                    url = ‘wss://‘ + window.location.host + urlPath;
                }
                document.getElementById(‘sockJsTransportSelect‘).style.visibility = ‘hidden‘;
            }
        }

        function updateTransport(transport) {
            alert(transport);
            transports = (transport == ‘all‘) ?  [] : [transport];
        }

        function log(message) {
            var console = document.getElementById(‘console‘);
            var p = document.createElement(‘p‘);
            p.style.wordWrap = ‘break-word‘;
            p.appendChild(document.createTextNode(message));
            console.appendChild(p);
            while (console.childNodes.length > 25) {
                console.removeChild(console.firstChild);
            }
            console.scrollTop = console.scrollHeight;
        }
    </script>
</head>
<body>
<noscript>
    <h2 style="color: #ff0000">Seems your browser doesn‘t support Javascript! Websockets
    rely on Javascript being enabled. Please enable
    Javascript and reload this page!</h2>
</noscript>
<div>
    <div id="connect-container">
        <input id="radio1" type="radio" name="group1" onclick="updateUrl(‘/room/chat‘);">
        <label for="radio1">W3C WebSocket</label>
        <br>
        <input id="radio2" type="radio" name="group1" onclick="updateUrl(‘/room/chat‘);">
        <label for="radio2">SockJS</label>
        <div id="sockJsTransportSelect" style="visibility:hidden;">
            <span>SockJS transport:</span>
            <select onchange="updateTransport(this.value)">
                <option value="all">all</option>
                <option value="websocket">websocket</option>
                <option value="xhr-polling">xhr-polling</option>
                <option value="jsonp-polling">jsonp-polling</option>
                <option value="xhr-streaming">xhr-streaming</option>
                <option value="iframe-eventsource">iframe-eventsource</option>
                <option value="iframe-htmlfile">iframe-htmlfile</option>
            </select>
        </div>
        <div>
            <button id="connect" onclick="connect();">进入房间</button>
            <button id="disconnect" disabled="disabled" onclick="disconnect();">退出房间</button>
        </div>
        <div>
            <textarea id="message" style="width: 350px">Here is a message!</textarea>
        </div>
        <div>
            <button id="echo" onclick="echo();" disabled="disabled">发送</button>
        </div>
    </div>
    <div id="console-container">
        <div id="console"></div>
    </div>
</div>
</body>
</html>
时间: 2024-10-14 05:20:49

websocket 聊天室搭建技术点的相关文章

WebSocket聊天室demo

根据Socket异步聊天室修改成WebSocket聊天室 WebSocket特别的地方是 握手和消息内容的编码.解码(添加了ServerHelper协助处理) ServerHelper: using System; using System.Collections; using System.Text; using System.Security.Cryptography; namespace SocketDemo { // Server助手 负责:1 握手 2 请求转换 3 响应转换 clas

php websocket聊天室,支持私聊

后台代码: <?php //send用户加入 //send1发送信息 //send2退出登录 error_reporting(E_ALL ^ E_NOTICE); ob_implicit_flush(); //连接服务器 $sk = new Sock('127.0.0.1',8000); $sk->run(); class Sock{ public $sockets; public $users; public $master; private $sda = array();//已接收的数据

php +html5 websocket 聊天室

针对内容比较长出错,修改后的解码函数 和 加码函数 原文请看上一篇 http://yixun.yxsss.com/yw3104.html function uncode($str,$key){ $mask = array(); $data = ''; $msg = unpack('H*',$str); $head = substr($msg[1],0,2); if ($head == '81' && !isset($this->slen[$key])) { $len=substr($

swoole 1.79 websocket 聊天室 基于swoole_server

基于 swoole 1.79 swoole_server 写的 websocket 网页聊天室,基本功能,以供参考 所需环境 php swoole 1.79 redis <a href="http://pan.baidu.com/s/1o6uTT7W">源码百度网盘下载</a>

node实现websocket聊天室

const express = require('express'); const app = express(); const ws = require('ws').Server; const wss = new ws({port: 3001}); var sockets = []; wss.on('connection', function(ws) { ws.send('连接成功'); ws.send('欢迎进入聊天室'); sockets.push(ws); ws.on('message'

swoole webSocket 聊天室示例

swoole1.7.9增加了内置的WebSocket服务器支持,通过几行PHP代码就可以写出一个异步非阻塞多进程的WebSocket服务器. 基于swoole websocket的用户上下线通知,在线用户列表,群聊等简易功能的聊天室: 源码前往github : https://github.com/wanggang826/about_swoole/websocket_chat 简易聊天室示例地址:  http://sw.wanggangg.top/websocket_chat 原文地址:http

基于Tomcat7、Java、WebSocket的服务器推送聊天室

http://blog.csdn.net/leecho571/article/details/9707497 http://blog.fens.me/java-websocket-intro/ java EE 7 去年刚刚发布了JSR356规范,使得WebSocket的Java API得到了统一,Tomcat从7.0.47开始支持JSR356,这样一来写WebSocket的时候,所用的代码都是可以一样的. HTML5 WebSocket实现了服务器与浏览器的双向通讯,双向通讯使服务器消息推送开发

视频聊天室用什么技术开发的?

视频聊天室有很多中不同的技术可以开发,下面为大家稍微举几个列子: 一.可以用纯C/S架构来进行开发,好处是功能实现起来会更加强大,缺点是开发成本极高,周期较长.一般不适合中小型企业站长运用. 二.通过开发插件来实现高性能的视频聊天室,不过它的缺点和纯C/S架构一样就是开发成本太高,目前网络木马盛行,很多开发人员对此类方式不太感冒. 三.利用纯web的手段去开发视频聊天室,它的优点是:开发成本低.运作效率高,可以通过简单的工具就能开发实现. 综上所述,目前最好的视频聊天室开发技术还是推荐用纯web

Flask基于websocket的简单聊天室

1.安装gevent-websocket pip install -i https://pypi.tuna.tsinghua.edu.cn/simple/ gevent-websocket 2.chat.py文件内容如下: from flask import Flask,request,render_template import json from geventwebsocket.handler import WebSocketHandler from gevent.pywsgi import