精华内容
下载资源
问答
  • WebSocket实现

    千次阅读 2017-03-18 14:44:21
    概念客户端websocket允许通过JavaScript建立与远程服务器的连接,从而实现客户端与服务器间双向的通信。在websocket中有两个方法:   1、send() 向远程服务器发送数据  2、close() 关闭该websocket链接  ...

    概念

    客户端

    websocket允许通过JavaScript建立与远程服务器的连接,从而实现客户端与服务器间双向的通信。在websocket中有两个方法:  
        1、send() 向远程服务器发送数据
        2、close() 关闭该websocket链接
      websocket同时还定义了几个监听函数    
        1、onopen 当网络连接建立时触发该事件
        2、onerror 当网络发生错误时触发该事件
        3、onclose 当websocket被关闭时触发该事件
        4、onmessage 当websocket接收到服务器发来的消息的时触发的事件,也是通信中最重要的一个监听事件。msg.data
      websocket还定义了一个readyState属性,这个属性可以返回websocket所处的状态:
        1、CONNECTING(0) websocket正尝试与服务器建立连接
        2、OPEN(1) websocket与服务器已经建立连接
        3、CLOSING(2) websocket正在关闭与服务器的连接
        4、CLOSED(3) websocket已经关闭了与服务器的连接

        

    <%@ page language="java" contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8"%>
    <%
    String path = request.getContextPath();
    String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
    %>
        <%@ page import="com.hzm.socialweb.beans.Login"%>
    <jsp:useBean id="login" type="com.hzm.socialweb.beans.Login" scope="session"/>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    
    <html>
    <head>
        <meta charset="UTF-8">
        <title>Test WebSocket</title>
        <style>
            #chat{
                width:410px;
            }
    
            #console-container{
                width:410px;
            }
    
            #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>
            var Chat = {};
    
            Chat.socket = null;
    
            Chat.connect = (function(host){
                if('WebSocket' in window){
                    Chat.socket = new WebSocket(host);
                }else if('MozWebSocket' in window){
                    Chat.socket = new MozWebSocket(host);
                }else{
                    Console.log('Error:WebSocket is not supported by this browser.');
                    return;
                }
    
                Chat.socket.onopen = function(){
                    Console.log("Info:WebSocket connection opened.");
                    document.getElementById('chat').onkeydown = function(event){
                        if(event.keyCode == 13){
                            Chat.sendMessage();
                        }
                    }
                }
                Chat.socket.onclose = function(){
                    document.getElementById('chat').onkeydown = null;
                    Console.log('Info:WebSocket closed.');
                }
    
                Chat.socket.onmessage = function(message){
                    Console.log(message.data);
    
                }
            }
            );
    
            Chat.initialize = function(){
                if(window.location.protocol == 'http:'){
                    Chat.connect('ws://' + window.location.host + '/SocialWeb/websocket/chat/'+'<jsp:getProperty name="login" property="id" />');
    
                }else{
                    Chat.connect('wss://' + window.location.host + '/SocialWeb/websocket/chat/'+'<jsp:getProperty name="login" property="id" />');
                }
            }
    
            Chat.sendMessage = (function(){
                var message = document.getElementById("chat").value;
                if(message != ''){
                    Chat.socket.send(message);
                    document.getElementById('chat').value='';
                }
            })
    
            var Console = {};
            Console.log = (function(message){
                var console = document.getElementById('console');
                var p = document.createElement('p');
                p.style.wordWrap = "break-word";
                p.innerHTML = message;
                console.appendChild(p);
                while(console.childNodes.length > 25){
                    console.removeChild(console.firstChild);
                }
                console.scrollTop = console.scrollHeight;
            })
    
            Chat.initialize();
    
        </script>
    
    
    </head>
    <body>
        <div>
            <p>
                <input type="text" placeholder="type and press enter to chat" id="chat" />
            </p>
            <div id="console-container">
                <div id="console">
                </div>
            </div>
        </div>
    </body>
    </html>

    服务端

    使用 @ServerEndpoint 注释作为 WebSocket 服务器的端点。如果需要传参,可以使用{参数名}来传参。
    例如:@ServerEndpoint(“/文件路径(随意)/{参数名})


    package com.hzm.socialweb.servlet;
    import java.io.IOException;
    import java.util.Set;
    import java.util.concurrent.CopyOnWriteArraySet;
    
    import javax.websocket.OnClose;
    import javax.websocket.OnError;
    import javax.websocket.OnMessage;
    import javax.websocket.OnOpen;
    import javax.websocket.Session;
    import javax.websocket.server.PathParam;
    import javax.websocket.server.ServerEndpoint;
    
    
    @ServerEndpoint(value = "/websocket/chat/{user}")//{user}为传入映射的值
    
    public class ChatAnnotation{
    
    
        private static final Set<ChatAnnotation> connections =
                new CopyOnWriteArraySet<ChatAnnotation>();
    
        private  String nickname;
        String id;
    
        private Session session;
    
        @OnOpen
        public void start(@PathParam("user")String user,Session session) {//@PathParam为获取传入映射的值
            this.nickname=user;
            this.session = session;
            connections.add(this);
            String message = String.format("* %s %s", nickname, "has joined.");
            broadcast(message);
        }
    
    
        @OnClose
        public void end() {
            connections.remove(this);
            String message = String.format("* %s %s",
                    nickname, "has disconnected.");
            broadcast(message);
        }
    
    
        @OnMessage
        public void incoming(String message) {
            // Never trust the client
            String filteredMessage = String.format("%s: %s",
                    nickname, message);
            broadcast(filteredMessage);
        }
    
    
    
    
        @OnError
        public void onError(Throwable t) throws Throwable {
            t.printStackTrace();
        }
    
    
        private static void broadcast(String msg) {
            for (ChatAnnotation client : connections) {
                try {
                    synchronized (client) {
                        client.session.getBasicRemote().sendText(msg);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                    connections.remove(client);
                    try {
                        client.session.close();
                    } catch (IOException e1) {
                        // Ignore
                    }
                    String message = String.format("* %s %s",
                            client.nickname, "has been disconnected.");
                    broadcast(message);
                }
            }
        }
    }

    代码均改自tomcat WebSocket

    展开全文
  • websocket最伟大之处在于服务器和客户端可以在给定的时间范围内的...实现功能:springboot整合websocket实现一对一,多对多聊天系统。 依赖 <dependency> <groupId>com.alibaba</groupId> <

    websocket最伟大之处在于服务器和客户端可以在给定的时间范围内的任意时刻,相互推送信息。 浏览器和服务器只需要要做一个握手的动作,在建立连接之后,服务器可以主动传送数据给客户端,客户端也可以随时向服务器发送数据。

    实现功能:springboot整合websocket实现一对一,多对多聊天系统。

    依赖

            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>fastjson</artifactId>
                <version>1.2.28</version>
            </dependency>       
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-websocket</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-thymeleaf</artifactId>
            </dependency>

    配置类WebSocketConfig

    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.socket.server.standard.ServerEndpointExporter;
    
    @Configuration
    public class WebSocketConfig {
    
    	/**
    	 * 服务器节点
    	 * 如果使用独立的servlet容器,而不是直接使用springboot的内置容器,就不要注入ServerEndpointExporter,因为它将由容器自己提供和管理
    	 */
    	@Bean
    	public ServerEndpointExporter serverEndpointExporter() {
    		return new ServerEndpointExporter();
    	}
    
    }

    WebSocket

    import com.alibaba.fastjson.JSON;
    import com.alibaba.fastjson.JSONObject;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.stereotype.Component;
    
    import javax.websocket.*;
    import javax.websocket.server.PathParam;
    import javax.websocket.server.ServerEndpoint;
    import java.io.IOException;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Set;
    import java.util.concurrent.ConcurrentHashMap;
    
    @Slf4j
    @Component
    @ServerEndpoint("/websocket/{username}")
    public class WebSocket {
    
    	/**
    	 * 在线人数
    	 */
    	public static int onlineNumber = 0;
    	/**
    	 * 以用户的姓名为key,WebSocket为对象保存起来
    	 */
    	private static Map<String, WebSocket> clients = new ConcurrentHashMap<String, WebSocket>();
    	/**
    	 * 会话
    	 */
    	private Session session;
    	/**
    	 * 用户名称
    	 */
    	private String username;
    
    	/**
    	 * OnOpen 表示有浏览器链接过来的时候被调用
    	 * OnClose 表示浏览器发出关闭请求的时候被调用
    	 * OnMessage 表示浏览器发消息的时候被调用
    	 * OnError 表示有错误发生,比如网络断开了等等
    	 */
    
    	/**
    	 * 建立连接
    	 *
    	 * @param session
    	 */
    	@OnOpen
    	public void onOpen(@PathParam("username") String username, Session session) {
    		onlineNumber++;
    		log.info("现在来连接的客户id:" + session.getId() + "用户名:" + username);
    		this.username = username;
    		this.session = session;
    		log.info("有新连接加入! 当前在线人数" + onlineNumber);
    		try {
    			//messageType 1代表上线 2代表下线 3代表在线名单 4代表普通消息
    			//先给所有人发送通知,说我上线了
    			Map<String, Object> map1 = new HashMap<>();
    			map1.put("messageType", 1);
    			map1.put("username", username);
    			sendMessageAll(JSON.toJSONString(map1), username);
    
    			//把自己的信息加入到map当中去
    			clients.put(username, this);
    			//给自己发一条消息:告诉自己现在都有谁在线
    			Map<String, Object> map2 = new HashMap<>();
    			map2.put("messageType", 3);
    			//移除掉自己
    			Set<String> set = clients.keySet();
    			map2.put("onlineUsers", set);
    			sendMessageTo(JSON.toJSONString(map2), username);
    		} catch (IOException e) {
    			log.info(username + "上线的时候通知所有人发生了错误");
    		}
    
    
    	}
    
    	@OnError
    	public void onError(Session session, Throwable error) {
    		log.info("服务端发生了错误" + error.getMessage());
    		//error.printStackTrace();
    	}
    
    	/**
    	 * 连接关闭
    	 */
    	@OnClose
    	public void onClose() {
    		onlineNumber--;
    		//webSockets.remove(this);
    		clients.remove(username);
    		try {
    			//messageType 1代表上线 2代表下线 3代表在线名单  4代表普通消息
    			Map<String, Object> map1 = new HashMap<>();
    			map1.put("messageType", 2);
    			map1.put("onlineUsers", clients.keySet());
    			map1.put("username", username);
    			sendMessageAll(JSON.toJSONString(map1), username);
    		} catch (IOException e) {
    			log.info(username + "下线的时候通知所有人发生了错误");
    		}
    		log.info("有连接关闭! 当前在线人数" + onlineNumber);
    	}
    
    	/**
    	 * 收到客户端的消息
    	 *
    	 * @param message 消息
    	 * @param session 会话
    	 */
    	@OnMessage
    	public void onMessage(String message, Session session) {
    		try {
    			log.info("来自客户端消息:" + message + "客户端的id是:" + session.getId());
    			JSONObject jsonObject = JSON.parseObject(message);
    			String textMessage = jsonObject.getString("message");
    			String fromusername = jsonObject.getString("username");
    			String tousername = jsonObject.getString("to");
    			//如果不是发给所有,那么就发给某一个人
    			//messageType 1代表上线 2代表下线 3代表在线名单  4代表普通消息
    			Map<String, Object> map1 = new HashMap<>();
    			map1.put("messageType", 4);
    			map1.put("textMessage", textMessage);
    			map1.put("fromusername", fromusername);
    			if (tousername.equals("All")) {
    				map1.put("tousername", "所有人");
    				sendMessageAll(JSON.toJSONString(map1), fromusername);
    			} else {
    				map1.put("tousername", tousername);
    				sendMessageTo(JSON.toJSONString(map1), tousername);
    			}
    		} catch (Exception e) {
    			log.info("发生了错误了");
    		}
    	}
    
    	public void sendMessageTo(String message, String ToUserName) throws IOException {
    		for (WebSocket item : clients.values()) {
    			if (item.username.equals(ToUserName)) {
    				item.session.getAsyncRemote().sendText(message);
    				break;
    			}
    		}
    	}
    
    	public void sendMessageAll(String message, String FromUserName) throws IOException {
    		for (WebSocket item : clients.values()) {
    			item.session.getAsyncRemote().sendText(message);
    		}
    	}
    
    	public static synchronized int getOnlineCount() {
    		return onlineNumber;
    	}
    
    }
    

    WebSocketController

    import lombok.extern.slf4j.Slf4j;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    @Slf4j
    @Controller
    public class WebSocketController {
    
    	@RequestMapping("/websocket/{name}")
    	public String webSocket(@PathVariable String name, Model model) {
    		try {
    			log.info("跳转到websocket的页面上");
    			model.addAttribute("username", name);
    			return "websocket";
    		} catch (Exception e) {
    			log.info("跳转到websocket的页面上发生异常,异常信息是:" + e.getMessage());
    			return "error";
    		}
    	}
    }
    

    websocket.html(位置:templates文件夹下)

    <!DOCTYPE html>
    <html xmlns:th="http://www.w3.org/1999/xhtml">
    <head>
        <title>websocket</title>
        <script type="text/javascript" src="http://ajax.microsoft.com/ajax/jquery/jquery-1.4.min.js"></script>
        <script src="http://cdn.bootcss.com/stomp.js/2.3.3/stomp.min.js"></script>
        <script src="https://cdn.bootcss.com/sockjs-client/1.1.4/sockjs.min.js"></script>
    </head>
    
    <body>
    <div style="margin: auto;text-align: center">
        <h1>Welcome to websocket</h1>
    </div>
    <br/>
    <div style="margin: auto;text-align: center">
        <select id="onLineUser">
            <option>--所有--</option>
        </select>
        <input id="text" type="text"/>
        <button onclick="send()">发送消息</button>
    </div>
    <br>
    <div style="margin-right: 10px;text-align: right">
        <button onclick="closeWebSocket()">关闭连接</button>
    </div>
    <hr/>
    <div id="message" style="text-align: center;"></div>
    <input type="text" th:value="${username}" id="username" style="display: none"/>
    </body>
    
    
    <script type="text/javascript">
        var webSocket;
        var commWebSocket;
        if ("WebSocket" in window) {
            webSocket = new WebSocket("ws://localhost:8080/websocket/" + document.getElementById('username').value);
    
            //连通之后的回调事件
            webSocket.onopen = function () {
                //webSocket.send( document.getElementById('username').value+"已经上线了");
                console.log("已经连通了websocket");
                setMessageInnerHTML("已经连通了websocket");
            };
    
            //接收后台服务端的消息
            webSocket.onmessage = function (evt) {
                var received_msg = evt.data;
                console.log("数据已接收:" + received_msg);
                var obj = JSON.parse(received_msg);
                console.log("可以解析成json:" + obj.messageType);
                //1代表上线 2代表下线 3代表在线名单 4代表普通消息
                if (obj.messageType == 1) {
                    //把名称放入到selection当中供选择
                    var onlineName = obj.username;
                    var option = "<option>" + onlineName + "</option>";
                    $("#onLineUser").append(option);
                    setMessageInnerHTML(onlineName + "上线了");
                } else if (obj.messageType == 2) {
                    $("#onLineUser").empty();
                    var onlineName = obj.onlineUsers;
                    var offlineName = obj.username;
                    var option = "<option>" + "--所有--" + "</option>";
                    for (var i = 0; i < onlineName.length; i++) {
                        if (!(onlineName[i] == document.getElementById('username').value)) {
                            option += "<option>" + onlineName[i] + "</option>"
                        }
                    }
                    $("#onLineUser").append(option);
    
                    setMessageInnerHTML(offlineName + "下线了");
                } else if (obj.messageType == 3) {
                    var onlineName = obj.onlineUsers;
                    var option = null;
                    for (var i = 0; i < onlineName.length; i++) {
                        if (!(onlineName[i] == document.getElementById('username').value)) {
                            option += "<option>" + onlineName[i] + "</option>"
                        }
                    }
                    $("#onLineUser").append(option);
                    console.log("获取了在线的名单" + onlineName.toString());
                } else {
                    setMessageInnerHTML(obj.fromusername + "对" + obj.tousername + "说:" + obj.textMessage);
                }
            };
    
            //连接关闭的回调事件
            webSocket.onclose = function () {
                console.log("连接已关闭...");
                setMessageInnerHTML("连接已经关闭....");
            };
        } else {
            // 浏览器不支持 WebSocket
            alert("您的浏览器不支持 WebSocket!");
        }
    
        //将消息显示在网页上
        function setMessageInnerHTML(innerHTML) {
            document.getElementById('message').innerHTML += innerHTML + '<br/>';
        }
    
        function closeWebSocket() {
            //直接关闭websocket的连接
            webSocket.close();
        }
    
        function send() {
            var selectText = $("#onLineUser").find("option:selected").text();
            if (selectText == "--所有--") {
                selectText = "All";
            } else {
                setMessageInnerHTML(document.getElementById('username').value + "对" + selectText + "说:" + $("#text").val());
            }
            var message = {
                "message": document.getElementById('text').value,
                "username": document.getElementById('username').value,
                "to": selectText
            };
            webSocket.send(JSON.stringify(message));
            $("#text").val("");
    
        }
    </script>
    
    </html>

    测试

    http://localhost:8080/websocket/Jack

    http://localhost:8080/websocket/Rose

    在这里插入图片描述

    展开全文
  • websocket实现斗鱼弹幕系统

    千人学习 2019-08-05 19:16:59
    本课程主要讲解了1.服务器的消息如何发给客户端;2.通过实现方式利用websocket;3.websocket实现方案概述等内容,希望学完之后对你有所收获。
  • WebSocket实现一个聊天室

    千次阅读 多人点赞 2020-11-22 17:33:15
    WebSocket实现一个聊天室 在线聊天室

    相关参考:

    阮一峰老师:WebSocket 教程

    MDN:WebSocket

    简书:nodejs-websocket介绍

    一、WebSocket 介绍

    WebSocket 协议是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工( full-duplex)通信一一允许服务器主动发送信息给客户端。

    websockets是一种持久协议,http是非持久协议

    现在很多网站都有实时推送的需求,比如聊天,客服咨询等。

    早期没有 WebSocket 时,通过AJAX轮询(不停发送请求,询问是否有新消息),由于http请求本身的限制,服务器无法给浏览器主动发送数据,因此需要浏览器定时的给服务器发送请求(如1s-次),服务器把最新的数据响应给浏览器。这种模式的缺点就是浪费性能和资源。

    在这里插入图片描述

    二、WebSocket 基本使用

    2.1 创建一个 WebSocket

    在H5当中已经提供了 WebSocket 的 API,我们可以直接使用

    语法:

    var aWebSocket = new WebSocket(url [, protocols]);
    

    url:要连接的URL;这应该是WebSocket服务器将响应的URL。

    protocols 可选:
            一个协议字符串或者一个包含协议字符串的数组。这些字符串用于指定子协议,这样单个服务器可以实现多个WebSocket子协议(例如,您可能希望一台服务器能够根据指定的协议(protocol)处理不同类型的交互)。如果不指定协议字符串,则假定为空字符串。

    2.2 常用事件

    使用 addEventListener() 或将一个事件监听器赋值给本接口的 WebSocket对象来监听下面的事件。

    事件名称 事件描述
    open 连接成功时触发。也可以通过 onopen 属性来设置。
    message 收到数据时触发。也可以通过 onmessage 属性来设置。
    close 连接被关闭时触发。也可以通过 onclose 属性来设置。
    error 连接因错误而关闭时触发,例如无法发送数据时。也可以通过 onerror 属性来设置.
    // 创建一个 WebSocket 连接
    const socket = new WebSocket('ws://localhost:8080');
    
    // 连接成功
    socket.addEventListener('open', (event) => {
      socket.send('Hello Server!');
    });
    
    // 监听消息
    socket.addEventListener('message', function (event) {
        console.log('Message from server ', event);
    });
    
    // 关闭连接
    socket.addEventListener('close', (event) => {
      console.log('The connection has been closed successfully.');
    )};
    
    // 监听可能发生的错误
    socket.addEventListener('error', function (event) {
      console.log('WebSocket error: ', event);
    });
    

    2.3 常用方法

    方法名 方法描述
    WebSocket.send(data) 发送数据(排队发送)
    WebSocket.close([code[, reason]]) 关闭当前链接。
    // 发送数据
    button.addEventListener('click',function() {
      let value = input.value 
      socket.send('Hello Wolrd:'+value)
    })
    

    2.4 小案例

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Document</title>
      <style>
        div {
          width: 200px;
          height: 200px;
          border: 1px solid black;
        }
      </style>
    </head>
    <body>
      <input type="text" placeholder="输入你的内容">
      <button>发送请求</button>
      <!-- 显示结果 -->
      <div></div>
      
      <script>
        const input = document.querySelector('input')
        const button = document.querySelector('button')
        const div = document.querySelector('div')
    
        // 1.创建websocket
        // 参数:WebSocket(url [, protocols]);
        const socket = new WebSocket('wss://echo.websocket.org')
    
        // 2. open:当和 websocket服务连接成功的时候触发
        socket.addEventListener('open', function () {
          div.innerHTML = '连接成功~'
        })
    
        // 3.主动给 websocket服务发送消息
        button.addEventListener('click', function () {
          let value = input.value
          socket.send(value)
        })
    
        // 4. message:收到服务器返回的数据触发
        socket.addEventListener('message', function (event) {
          console.log(event.data);
          div.innerHTML = event.data
        })
    
        // 5.close:服务已断开
        socket.addEventListener('close', function () {
          div.innerHTML = '服务已断开~'
        })
      </script>
    </body>
    </html>
    

    三、使用 nodejs 搭建一个 WebSocket服务器

    3.1 安装 nodejs-websocket

    nodejs-websocket 是一个非常方便的 websocket 依赖

    这里不做过多介绍,有关使用方式:
    GItHub地址:Nodejs Websocket
    简书:Nodejs -websocket介绍

    npm install -g nodejs-websocket
    

    3.2 简陋版聊天室

    index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Document</title>
    </head>
    <body>
      <input type="text" placeholder="输入你的内容">
      <button>发送请求</button>
      <!-- 显示结果 -->
      <div></div>
      <script>
        const input = document.querySelector('input')
        const button = document.querySelector('button')
        const div = document.querySelector('div')
        
        const TYPE_ENTER = 0
        const TYPE_LEAVE = 1
        const TYPE_MSG = 2
    
        // 1.创建websocket
        // 参数:WebSocket(url [, protocols]);
        const socket = new WebSocket('ws://127.0.0.1:8000')
    
        // 2. open:当和 websocket服务连接成功的时候触发
        socket.addEventListener('open', function () {
          div.innerHTML = '连接成功~'
        })
    
        // 3.主动给 websocket服务发送消息
        button.addEventListener('click', function () {
          let value = input.value
          socket.send(value)
          input.value = ''
        })
    
        // 4. message:收到服务器返回的数据触发
        socket.addEventListener('message', function (event) {
          let result = JSON.parse(event.data)
          console.log(result);
    
          let newDiv = document.createElement('div')
          newDiv.innerHTML = result.msg + '-----' + result.time
          if (result.type === TYPE_ENTER) {
            newDiv.style.color = 'green'
          } else if (result.type === TYPE_LEAVE) {
            newDiv.style.color = 'red'
          } else {
            newDiv.style.color = 'black'
          }
          div.appendChild(newDiv)
        })
    
        // 5.close:服务已断开
        socket.addEventListener('close', function () {
          div.innerHTML = '服务已断开~'
        })
      </script>
    </body>
    </html>
    

    app.js

    const { connect } = require('http2');
    const { findSourceMap } = require('module');
    const ws = require('nodejs-websocket')
    
    const TYPE_ENTER = 0
    const TYPE_LEAVE = 1
    const TYPE_MSG = 2
    /*    type:消息的类型      0:进入      1:离开      2:正常message  */
    
    // 记录当前连接上来的用户数量
    let count = 0
    
    // connect 代表每个连接到服务器的用户,都会有一个connect对象
    const server = ws.createServer(connect => {
      console.log('新的连接');
      count++
      connect.userName = `用户${count}`
    
      // 1.告诉所有用户,有人加入了聊天室
      broadcast({
        type: TYPE_ENTER,
        msg: `${connect.userName}进入了聊天室`,
        time: new Date().toLocaleTimeString()
      })
    
      // 每当接受到用户传递数据过来(客户端的send方法),text事件就会被触发
      connect.on('text', data => {
        // 2.当我们接收到某个用户的数据,广播给所有用户
        console.log('接受到数据:' + data);
        broadcast({
          type: TYPE_MSG,
          msg: connect.userName + ":" + data,
          time: new Date().toLocaleTimeString()
        })
      })
    
      // 关闭连接时触发
      connect.on('close', data => {
        console.log('关闭连接');
        
        // 3.有人离开了,广播给所有用户
        count--
        broadcast({
          type: TYPE_LEAVE,
          msg: `${connect.userName}离开了聊天室`,
          time: new Date().toLocaleTimeString()
        })
      })
      // 发生异常
      connect.on('error', data => {
        console.log("发生异常");
      })
    })
    
    // 广播,给所有的用户发送消息  connections(这个数组里,保存了每个连接)
    function broadcast(msg) {
      server.connections.forEach(connect => {
        connect.send(JSON.stringify(msg))
      })
    }
    
    server.listen(8000, () => {
      console.log('Server started Complete: ws://127.0.0.1:8000');
    })
    

    效果:

    在这里插入图片描述
    在这里插入图片描述

    四、 服务端手动搭建 WebSocket 服务器流程

    在这里插入图片描述

    展开全文
  • springboot+websocket实现服务端、客户端

    万次阅读 多人点赞 2019-01-12 12:54:43
    一、引言 小编最近一直在使用springboot框架...websocket主要功能就是实现网络通讯,比如说最经典的客服聊天窗口、您有新的消息通知,或者是项目与项目之间的通讯,都可以采用websocket实现。 二、websocket介...

     

    一、引言

    小编最近一直在使用springboot框架开发项目,毕竟现在很多公司都在采用此框架,之后小编也会陆续写关于springboot开发常用功能的文章。 

    什么场景下会要使用到websocket的呢?

    websocket主要功能就是实现网络通讯,比如说最经典的客服聊天窗口、您有新的消息通知,或者是项目与项目之间的通讯,都可以采用websocket来实现。

    二、websocket介绍

    百度百科介绍:WebSokcet

    在公司实际使用websocket开发,一般来都是这样的架构,首先websocket服务端是一个单独的项目,其他需要通讯的项目都是以客户端来连接,由服务端控制消息的发送方式(群发、指定发送)。 但是也会有服务端、客户端在同一个项目当中,具体看项目怎么使用。

    本文呢,采用的是服务端与客户端分离来实现,包括使用springboot搭建websokcet服务端、html5客户端、springboot后台客户端, 具体看下面代码。

    三、服务端实现

    步骤一: springboot底层帮我们自动配置了websokcet,引入maven依赖

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-websocket</artifactId>
    </dependency>

    步骤二:如果是你采用springboot内置容器启动项目的,则需要配置一个Bean。如果是采用外部的容器,则可以不需要配置。

    /**
     * @Auther: liaoshiyao
     * @Date: 2019/1/11 11:49
     * @Description: 配置类
     */
    @Component
    public class WebSocketConfig {
    
        /**
         * ServerEndpointExporter 作用
         *
         * 这个Bean会自动注册使用@ServerEndpoint注解声明的websocket endpoint
         *
         * @return
         */
        @Bean
        public ServerEndpointExporter serverEndpointExporter() {
            return new ServerEndpointExporter();
        }
    }
    

    步骤三:最后一步当然是编写服务端核心代码了,其实小编不是特别想贴代码出来,贴很多代码影响文章可读性。

    package com.example.socket.code;
    
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.stereotype.Component;
    
    import javax.websocket.OnClose;
    import javax.websocket.OnMessage;
    import javax.websocket.OnOpen;
    import javax.websocket.Session;
    import javax.websocket.server.PathParam;
    import javax.websocket.server.ServerEndpoint;
    import java.util.concurrent.ConcurrentHashMap;
    
    /**
     * @Auther: liaoshiyao
     * @Date: 2019/1/11 11:48
     * @Description: websocket 服务类
     */
    
    /**
     *
     * @ServerEndpoint 这个注解有什么作用?
     *
     * 这个注解用于标识作用在类上,它的主要功能是把当前类标识成一个WebSocket的服务端
     * 注解的值用户客户端连接访问的URL地址
     *
     */
    
    @Slf4j
    @Component
    @ServerEndpoint("/websocket/{name}")
    public class WebSocket {
    
        /**
         *  与某个客户端的连接对话,需要通过它来给客户端发送消息
         */
        private Session session;
    
         /**
         * 标识当前连接客户端的用户名
         */
        private String name;
    
        /**
         *  用于存所有的连接服务的客户端,这个对象存储是安全的
         */
        private static ConcurrentHashMap<String,WebSocket> webSocketSet = new ConcurrentHashMap<>();
    
    
        @OnOpen
        public void OnOpen(Session session, @PathParam(value = "name") String name){
            this.session = session;
            this.name = name;
            // name是用来表示唯一客户端,如果需要指定发送,需要指定发送通过name来区分
            webSocketSet.put(name,this);
            log.info("[WebSocket] 连接成功,当前连接人数为:={}",webSocketSet.size());
        }
    
    
        @OnClose
        public void OnClose(){
            webSocketSet.remove(this.name);
            log.info("[WebSocket] 退出成功,当前连接人数为:={}",webSocketSet.size());
        }
    
        @OnMessage
        public void OnMessage(String message){
            log.info("[WebSocket] 收到消息:{}",message);
            //判断是否需要指定发送,具体规则自定义
            if(message.indexOf("TOUSER") == 0){
                String name = message.substring(message.indexOf("TOUSER")+6,message.indexOf(";"));
                AppointSending(name,message.substring(message.indexOf(";")+1,message.length()));
            }else{
                GroupSending(message);
            }
    
        }
    
        /**
         * 群发
         * @param message
         */
        public void GroupSending(String message){
            for (String name : webSocketSet.keySet()){
                try {
                    webSocketSet.get(name).session.getBasicRemote().sendText(message);
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        }
    
        /**
         * 指定发送
         * @param name
         * @param message
         */
        public void AppointSending(String name,String message){
            try {
                webSocketSet.get(name).session.getBasicRemote().sendText(message);
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }
    

    四、客户端实现

    HTML5实现:以下就是核心代码了,其实其他博客有很多,小编就不多说了。

     var websocket = null;
        if('WebSocket' in window){
            websocket = new WebSocket("ws://192.168.2.107:8085/websocket/testname");
        }
    
        websocket.onopen = function(){
            console.log("连接成功");
        }
    
        websocket.onclose = function(){
            console.log("退出连接");
        }
    
        websocket.onmessage = function (event){
            console.log("收到消息"+event.data);
        }
    
        websocket.onerror = function(){
            console.log("连接出错");
        }
    
        window.onbeforeunload = function () {
            websocket.close(num);
        }
        

    SpringBoot后台实现:小编发现多数博客都是采用js来实现客户端,很少有用后台来实现,所以小编也就写了写,大神请勿喷?。很多时候,项目与项目之间通讯也需要后台作为客户端来连接。

    步骤一:首先我们要导入后台连接websocket的客户端依赖

    <!--websocket作为客户端-->
    <dependency>
        <groupId>org.java-websocket</groupId>
        <artifactId>Java-WebSocket</artifactId>
        <version>1.3.5</version>
    </dependency>

    步骤二:把客户端需要配置到springboot容器里面去,以便程序调用。

    package com.example.socket.config;
    
    import lombok.extern.slf4j.Slf4j;
    import org.java_websocket.client.WebSocketClient;
    import org.java_websocket.drafts.Draft_6455;
    import org.java_websocket.handshake.ServerHandshake;
    import org.springframework.context.annotation.Bean;
    import org.springframework.stereotype.Component;
    
    import java.net.URI;
    
    /**
     * @Auther: liaoshiyao
     * @Date: 2019/1/11 17:38
     * @Description: 配置websocket后台客户端
     */
    @Slf4j
    @Component
    public class WebSocketConfig {
    
        @Bean
        public WebSocketClient webSocketClient() {
            try {
                WebSocketClient webSocketClient = new WebSocketClient(new URI("ws://localhost:8085/websocket/test"),new Draft_6455()) {
                    @Override
                    public void onOpen(ServerHandshake handshakedata) {
                        log.info("[websocket] 连接成功");
                    }
    
                    @Override
                    public void onMessage(String message) {
                        log.info("[websocket] 收到消息={}",message);
    
                    }
    
                    @Override
                    public void onClose(int code, String reason, boolean remote) {
                        log.info("[websocket] 退出连接");
                    }
    
                    @Override
                    public void onError(Exception ex) {
                        log.info("[websocket] 连接错误={}",ex.getMessage());
                    }
                };
                webSocketClient.connect();
                return webSocketClient;
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    
    }
    

    步骤三:使用后台客户端发送消息

    1、首先小编写了一个接口,里面有指定发送和群发消息两个方法。

    2、实现发送的接口,区分指定发送和群发由服务端来决定(小编在服务端写了,如果带有TOUSER标识的,则代表需要指定发送给某个websocket客户端)

    3、最后采用get方式用浏览器请求,也能正常发送消息

    package com.example.socket.code;
    
    /**
     * @Auther: liaoshiyao
     * @Date: 2019/1/12 10:57
     * @Description: websocket 接口
     */
    public interface WebSocketService {
    
        /**
         * 群发
         * @param message
         */
         void groupSending(String message);
    
        /**
         * 指定发送
         * @param name
         * @param message
         */
         void appointSending(String name,String message);
    }
    
    package com.example.socket.code;
    
    import org.java_websocket.client.WebSocketClient;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    /**
     * @Auther: liaoshiyao
     * @Date: 2019/1/12 10:56
     * @Description: websocket接口实现类
     */
    @Component
    public class ScoketClient implements WebSocketService{
    
        @Autowired
        private WebSocketClient webSocketClient;
    
        @Override
        public void groupSending(String message) {
            // 这里我加了6666-- 是因为我在index.html页面中,要拆分用户编号和消息的标识,只是一个例子而已
            // 在index.html会随机生成用户编号,这里相当于模拟页面发送消息
            // 实际这样写就行了 webSocketClient.send(message)
            webSocketClient.send(message+"---6666");
        }
    
        @Override
        public void appointSending(String name, String message) {
            // 这里指定发送的规则由服务端决定参数格式
            webSocketClient.send("TOUSER"+name+";"+message);
        }
    }
    
    package com.example.socket.chat;
    
    import com.example.socket.code.ScoketClient;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    /**
     * @Auther: liaoshiyao
     * @Date: 2019/1/11 16:47
     * @Description: 测试后台websocket客户端
     */
    @RestController
    @RequestMapping("/websocket")
    public class IndexController {
    
        @Autowired
        private ScoketClient webScoketClient;
    
        @GetMapping("/sendMessage")
        public String sendMessage(String message){
            webScoketClient.groupSending(message);
            return message;
        }
    }
    

    五、最后

    其实,贴了这么多大一片的代码,感觉上影响了博客的美观,也不便于浏览,如果没看懂小伙伴,可以下载源码看下。

    里面一共两个项目,服务端、客户端(html5客户端、后台客户端),是一个网页群聊的小案例。

    https://download.csdn.net/download/weixin_38111957/10912384

     

    祝大家学习愉快~~~

    六、针对评论区的小伙伴提出的疑点进行解答

    看了小伙伴提出的疑问,小编也是非常认可的,如果是单例的情况下,这个对象的值都会被修改。

    小编就抽了时间Debug了一下,经过下图也可以反映出,能够看出,webSokcetSet中存在三个成员,并且vlaue值都是不同的,所以在这里没有出现对象改变而把之前对象改变的现象。

    服务端这样写是没问题的。

    紧接着,小编写了一个测试类,代码如下,经过测试输出的结果和小伙伴提出的疑点是一致的。

    最后总结:这位小伙伴提出的观点确实是正确的,但是在实际WebSocket服务端案例中为什么没有出现这种情况,当WebSokcet这个类标识为服务端的时候,每当有新的连接请求,这个类都是不同的对象,并非单例。

    这里也感谢“烟花苏柳”所提出的问题。

    import com.alibaba.fastjson.JSON;
    
    import java.util.concurrent.ConcurrentHashMap;
    
    /**
     * @Auther: IT贱男
     * @Date: 2018/11/1 16:15
     * @Description:
     */
    public class TestMain {
    
        /**
         * 用于存所有的连接服务的客户端,这个对象存储是安全的
         */
        private static ConcurrentHashMap<String, Student> webSocketSet = new ConcurrentHashMap<>();
    
        public static void main(String[] args) {
            Student student = Student.getStudent();
            student.name = "张三";
            webSocketSet.put("1", student);
    
            Student students = Student.getStudent();
            students.name = "李四";
            webSocketSet.put("2", students);
    
            System.out.println(JSON.toJSON(webSocketSet));
        }
    }
    
    /**
     * 提供一个单例类
     */
    class Student {
    
        public String name;
    
        private Student() {
        }
    
        private static final Student student = new Student();
    
        public static Student getStudent() {
            return student;
    
        }
    }
    {"1":{"name":"李四"},"2":{"name":"李四"}}

    ----------------------------------------------------- 更新于2019-08-14 -----------------------------------------------------

    展开全文
  • 基于spring-boot-starter-websocket实现websocket
  • 概述 本文对websocket集群的方案进行讨论: 实现websocket集群。...在上个博文Spring Boot系列20 Spring Websocket实现向指定的用户发送消息中实现向指定用户发送消息的功能,但是我们将提供websock...
  • 基于Vue+springboot+websocket实现的简短仿微信web聊天室(私聊和群聊功能)( www.tcefrep.site 聊天室模块 项目已经上线,可在线预览)
  • Spring Boot系列20 Spring Websocket实现向指定的用户发送消息## 概述 上一篇文章Spring Boot系列21 Spring Websocket实现websocket集群方案讨论里详细介绍了WebSocket集群的有三种方案,并得出结论第三个方案是...
  • webSocket实现Android客户端之间简单的通讯

    千次下载 热门讨论 2016-09-22 18:54:01
    webSocket实现Android客户端之间简单的通讯,或者群发
  • C# WinForm 通过WebSocket 实现文件传输示例,包含了客户端和服务端。
  • WebSocket :用WebSocket实现推送你必须考虑的几个问题

    万次阅读 多人点赞 2017-07-23 06:54:47
    目录:目录 WebSocket简介 项目背景硬件环境及客户端支持 本文研究内容 ...项目背景、硬件环境及客户端支持本项目通过WebSocket实现同时在线用户量5k推送服务器(可内网运行)。且可实时查看用户在线状
  • WebSocket实现实时通讯

    2020-10-29 17:17:05
    WebSocket实现实时通讯 WebSocket是HTML5以后基于TCP协议应用层的一种全双工实时通讯协议。注:全双工:个人了解服务器和客户端可以进行信息的相互传递 WebSocket由何而来 在没有WebSocket的时候,我们都是基于...
  • 简单的websocket实现

    千次阅读 2016-09-19 10:26:25
    一个简单的websocket实现server和client通信。
  • SpringBoot + Websocket 实现实时聊天

    千次阅读 2020-06-24 02:01:42
    最近有点小时间,上个项目正好用到了websocket实现广播消息来着,现在来整理一下之前的一些代码,分享给大家。 WebSocket协议是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工(full-duplex)通信——允许...
  • WebSocket实现在线聊天

    千次阅读 2019-04-03 21:33:50
    这一篇文章前面部分我们会先介绍WebSocket协议的基本知识,在最后我们会用Spring Boot来集成WebSocket实现一个简单的在线聊天功能,单纯想看实现部分的话可以直接跳过前面介绍的部分。 前言 通常情况下,浏览器和...
  • 在Spring Boot框架下使用WebSocket实现聊天功能

    万次阅读 多人点赞 2016-12-27 17:13:25
    上一篇博客我们介绍了在Spring Boot框架下使用WebSocket实现消息推送,消息推送是一对多,服务器发消息发送给所有的浏览器,这次我们来看看如何使用WebSocket实现消息的一对一发送,模拟的场景就是两个人在网页上...
  • Websocket实现断网重连

    千次阅读 2020-05-01 15:12:47
    Websocket实现断网重连 代码如下: 定义的变量如下: var lockReconnect = false;//避免重复连接 var wsUrl = "ws://localhost:8080/websocket/111"; // websocket链接 var ws;// websocket对象 首先判断是否支持...
  • spring websocket实现前后端通信

    万次阅读 多人点赞 2018-07-10 17:00:22
    项目要用websocket实现一个前后端实时通信的功能,做完之后感触颇多,写个博客回顾下整个历程,也希望能给后面的同志有点帮助。我使用springmvc的websocket组件,官网地址:点击打开链接示例内容:用户登陆之后往...
  • 使用WebSocket实现Android端即时通讯聊天功能

    万次阅读 多人点赞 2018-05-02 09:31:12
    本篇文章主要介绍自己使用WebSocket实现Android端即时通讯聊天功能的过程,最终我们使用WebSocket实现了两个客户端之间的即时通讯聊天功能和直播中的聊天室功能,当然整个WebSocket还是比较复杂的,特别是长链接的...
  • websocket实现方式原理websocket的原理主要是,利用websocket提供的api,客户端只需要向服务器发起一次连接即可,然后服务器就可以主动地源源不断地向客户端发送数据,只要客户端不关闭浏览器,那么这个连接就会一直...
  • websocket 实现消息实时推送 https://www.jb51.net/article/166411.htm https://github.com/ops-coffee/demo/tree/master/websocket https://channels.readthedocs.io/en/latest/ ...websocket是客户端和服务端之间的...
  • Tomcat 7的WebSocket实现

    千次阅读 2019-02-16 16:05:25
    Tomcat 7的WebSocket实现
  • Android如何使用websocket实现实时通信,求专家给个demo参考一下 同时通过服务来实现长连接
  • Android中 使用 WebSocket 实现消息通信

    千次阅读 2020-04-06 09:46:16
    一般简单的推送我们可以使用第三方推送的SDK,比如极光推送、信鸽推送等,但是对于消息聊天这种及时性有要求的或者三方推送不满足业务需求的,我们就需要使用WebSocket实现消息推送功能。 基本流程 WebSocket是...
  • vue websocket 实现页面实时刷新

    千次阅读 2019-09-05 10:33:37
    vue websocket 实现页面实时刷新 最近公司项目需求后台web端要做实时能看到用户的登录状态以及所在位置,说白了就是要做数据实时刷新。 直接上代码吧! <!DOCTYPE html> <html lang="en"> <head>...
  • Websocket实现私聊和群聊1. websocket的概念1.1. 全双工概念2. websocket实现聊天室2.1. WebSocket API2.1.1. 构造方法2.1.1.1. 语法2.1.1.2. 参数2.1.1.3. 抛出异常2.1.2. 常量2.1.3. 属性2.1.4. 方法2.1.5. 事件3....
  • HTML5+NodeJs实现WebSocket实现循环推送 最近在做图表展示方面需要实现循环推送效果,那么webSocket无疑是比较好的选择了,WebSocket相较于HTTP来说,有很多的优点,主要表现在WebSocket只建立一个TCP连接,可以主动...
  • 在Spring Boot框架下使用WebSocket实现消息推送

    万次阅读 多人点赞 2016-12-23 16:48:37
    Spring Boot的学习持续进行中。前面两篇博客我们介绍了如何使用Spring Boot容器搭建Web项目(使用Spring Boot开发Web项目)以及怎样为我们的Project添加HTTPS的支持(使用Spring Boot开发Web项目(二)之...什么是WebSocket
  • 通过websocket 实现与容器的交互

    千次阅读 2017-10-19 09:53:51
    通过websocket 实现与容器的交互

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 81,949
精华内容 32,779
关键字:

websocket怎么实现