博客地址:https://ainyi.com/#/67
有一个月没有写博客了,也是因为年前需求多、回家过春节的原因,现在返回北京的第二天,想想,应该也要分享技术专题的博客了!!
主题
基于 websocket 网页端聊天室
WebSocket 协议是基于 TCP 的一种新的网络协议。它实现了浏览器与服务器全双工 (full-duplex) 通信——允许服务器主动发送信息给客户端。
使用 java 开发后台
需要导入一个jar包:javax.websocket-api-1.0-rc4.jar
后台代码
package com.krry.socket;import java.io.IOException;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.ServerEndpoint; //该注解用来指定一个URI,客户端可以通过这个URI来连接到WebSocket。类似Servlet的注解mapping。无需在web.xml中配置。@ServerEndpoint("/websocket")public class MyWebSocket { ???//静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。 ???private static int onlineCount = 0; ????????//concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。若要实现服务端与单一客户端通信的话,可以使用Map来存放,其中Key可以为用户标识 ???private static CopyOnWriteArraySet<MyWebSocket> webSocketSet = new CopyOnWriteArraySet<MyWebSocket>(); ????????//与某个客户端的连接会话,需要通过它来给客户端发送数据 ???private Session session; ????????/** ????* 连接建立成功调用的方法 ????* @param session ?可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据 ????*/ ???@OnOpen ???public void onOpen(Session session){ ???????this.session = session; ???????webSocketSet.add(this); ????//加入set中 ???????addOnlineCount(); ??????????//在线数加1 ???????System.out.println("有新连接加入!当前在线人数为" + getOnlineCount()); ???} ????????/** ????* 连接关闭调用的方法 ????*/ ???@OnClose ???public void onClose(){ ???????webSocketSet.remove(this); ?//从set中删除 ???????subOnlineCount(); ??????????//在线数减1 ???????????System.out.println("有一连接关闭!当前在线人数为" + getOnlineCount()); ???} ????????/** ????* 收到客户端消息后调用的方法 ????* @param message 客户端发送过来的消息 ????* @param session 可选的参数 ????*/ ???@OnMessage ???public void onMessage(String message, Session session) { ???????System.out.println("来自客户端的消息:" + message); ????????????????//群发消息 ???????for(MyWebSocket item: webSocketSet){ ????????????????????????try { ???????????????item.sendMessage(message); ???????????} catch (IOException e) { ???????????????e.printStackTrace(); ???????????????continue; ???????????} ???????} ???} ????????/** ????* 发生错误时调用 ????* @param session ????* @param error ????*/ ???@OnError ???public void onError(Session session, Throwable error){ ???????System.out.println("发生错误"); ???????error.printStackTrace(); ???} ????????/** ????* 这个方法与上面几个方法不一样。没有用注解,是根据自己需要添加的方法。 ????* @param message ????* @throws IOException ????*/ ???public void sendMessage(String message) throws IOException{ ???????this.session.getBasicRemote().sendText(message); ???????//this.session.getAsyncRemote().sendText(message); ???} ????public static synchronized int getOnlineCount() { ???????return onlineCount; ???} ????public static synchronized void addOnlineCount() { ???????MyWebSocket.onlineCount++; ???} ????????public static synchronized void subOnlineCount() { ???????MyWebSocket.onlineCount--; ???}}
前端代码
注意
前端需要实现这几个方法:
?// 注册事件 ?// 监听打开连接 ?ws.onopen = function(){ ???openWs(); ?}; ?// 监听消息 ?ws.onmessage = function(event){ ???msgWs(event); ?}; ?// 监听关闭连接 ?ws.onclose = function(){ ???closeWs(); ?}; ?// 监听发送错误 ?ws.onerror = function(){ ???errorWs(); ?};
具体代码
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%><!doctype html><html> ???<head> ???<meta http-equiv="Content-Type" content="text/html;charset=utf-8"> ???<meta name="keywords" content=""> ???<meta name="description" content=""> ???<title> ?????基于Java服务器端的消息主动推送技术揭秘 --krry ???</title> ???<link rel="stylesheet" href="css/animate.css" /> ???<link rel="stylesheet" type="text/css" href="css/sg.css" /> ???<style> ?????*{margin:0;padding:0;} body{background:url("images/5.jpg");background-size:cover;} ?????h1{margin-top:50px;text-align:center;color:#fff;text-shadow:1px 1px 1px ?????#000;font-family:-webkit-body;font-size:24px;} .box{width:700px;margin:20px ?????auto;} .box span{color:#f60;font-size:16px;font-family:"微软雅黑";} .box .shu{text-indent:1em;height:24px;font-family:"微软雅黑";border:0;outline:none;font-size:14px;} ?????.box .add{width:300px;margin-right:24px;} .box .user{width:200px;} .box ?????.btn{width:80px;height:34px;color:#fff;background:#6c0;border:0;outline:none;cursor:pointer;margin-top:20px;font-size:16px;font-family:"微软雅黑";} ?????.box .area{line-height: 29px;height:280px;width:680px;padding:10px;overflow:auto;font-size:16px;font-family:"微软雅黑";margin:20px ?????0;outline:none;box-shadow:1px 2px 18px #000} .box .setex{text-indent:1em;height:28px;border:1px ?????solid #6c0;width:618px;outline:none;float:left;font-family:"微软雅黑";} .box ?????.send{font-size:14px;width:80px;height:30px;color:#fff;background:#6c0;border:0;outline:none;cursor:pointer;font-family:"微软雅黑";} ???</style> ?</head> ???<body> ???<h1> ?????基于Java服务器端的消息主动推送技术揭秘 --krry ???</h1> ???<div class="box"> ?????<span> ???????服务器地址: ?????</span> ?????<input type="text" class="shu add" value="www.ainyi.com/krry_NetChat/websocket" ?????readonly/> ?????<span> ???????用户名: ?????</span> ?????<input type="text" class="shu user" value="匿名" /> ?????<input type="button" value="连接" class="btn" /> ?????<div class="area" id="boxx"> ?????</div> ?????<div class="c_cen"> ???????<input type="text" class="setex" /> ???????<input type="button" value="发送" class="send"> ?????</div> ???</div> ???<script src="js/jquery-1.11.1.min.js"> ???</script> ???<script src="js/sg.js"> ???</script> ???<script src="js/sgutil.js"> ???</script> ???<script> ?????var close = true; ?????var ws; ?????$(function() { ???????$(".c_cen").hide(); ???????//首先判断浏览器是否支持webSocket,支持h5的浏览器才会支持 ???????if (window.WebSocket) { ?????????printMsg("您的浏览器支持WebSocket,您可以尝试连接到聊天服务器!", "OK"); ???????} else { ?????????printMsg("您的浏览器不支持WebSocket,请选择其他浏览器!", "ERROR"); ?????????//设置按钮不可点击 ?????????$(".btn").attr("disabled", "true"); ???????} ?????}); ?????//打印信息 ?????function printMsg(msg, msgType) { ???????if (msgType == "OK") { ?????????msg = "<span style=‘color:green‘>" + msg + "</span>"; ???????} ???????if (msgType == "ERROR") { ?????????msg = "<span style=‘color:red‘>" + msg + "</span>"; ???????} ???????$(".area").append(msg + "<br/>"); ???????var boxx = document.getElementById("boxx"); ???????boxx.scrollTop = boxx.scrollHeight; //使滚动条一直在底部 ?????} ?????//打开Socket ?????function openWs() { ???????printMsg("链接已建立", "OK"); ???????ws.send("【" + $(".user").val() + "】已进入聊天室"); ???????$(".c_cen").show(); ?????} ?????//接收消息的时候 ?????function msgWs(e) { ???????printMsg(e.data); ?????} ?????//关闭连接 ?????function closeWs() { ???????$(".btn").val("连接"); ???????$(".c_cen").hide(); ?????} ?????//产生错误 ?????function errorWs() { ???????printMsg("您与服务器连接错误...", "ERROR"); ?????} ?????//点击发送按钮 ?????$(".send").click(function() { ???????var text = $(".setex").val(); ???????if (text == null || text == "") return; ???????$(".setex").val(""); ???????ws.send("【" + $(".user").val() + "】:" + text); ?????}); ?????//点击连接 ?????$(".btn").click(function() { ???????if ($(".add").val() && $(".user").val()) { ?????????if (close) { ???????????printMsg("正在准备连接服务器,请稍等..."); ???????????var url = "wss://" + $(".add").val(); ???????????if ("WebSocket" in window) { ?????????????ws = new WebSocket(url); ???????????} else if ("MozWebSocket" in window) { ?????????????ws = new MozWebSocket(url); ???????????} ???????????//已连接 ???????????$(".btn").val("断开"); ???????????close = false; ???????????//注册事件 ???????????ws.onopen = function() { ?????????????openWs(); ???????????}; ???????????ws.onmessage = function(event) { ?????????????msgWs(event); ???????????}; ???????????ws.onclose = function() { ?????????????closeWs(); ???????????}; ???????????ws.onerror = function() { ?????????????errorWs(); ???????????}; ???????????//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。 ???????????window.onbeforeunload = function() { ?????????????ws.send("【" + $(".user").val() + "】离开了聊天室"); ?????????????close = true; ?????????????ws.close(); ???????????}; ?????????} else { ???????????ws.send("【" + $(".user").val() + "】离开了聊天室"); ???????????close = true; ???????????ws.close(); ?????????} ???????} else { ?????????$.tmDialog.alert({ ???????????open: "left", ???????????content: "服务器地址和用户名不能为空哦...", ???????????title: "提示哦~~~" ?????????}); ???????} ?????}); ?????//回车键 ?????$(".setex").keypress(function(event) { ???????if (event.keyCode == 13) { ?????????$(".send").trigger("click"); ???????} ?????}); ???</script> ?</body></html>
到这里大功告成
聊天方法
- 打开两个窗口输入项目地址进行聊天
- 可以把链接发给朋友打开,进行聊天
来一波截图
移动端
在线演示
PC 端:https://www.ainyi.com/krry_NetChat
移动端:https://www.ainyi.com/krry_NetChatPho
打完收工~
博客地址:https://ainyi.com/#/67
分享基于 websocket 网页端聊天室
原文地址:https://www.cnblogs.com/ainyi/p/10398665.html