WebSocket实战

1)  什么是websocket?

websocket是一个基于HTML5的双向的通讯协议,它建立在TCP之上,和HTTP一样通过TCP来传输数据。在浏览器与服务器之间建立了一条管道 - - -  不可轻易关闭

webSocket以字符串、文本传输数据   socket以 io流传输

2)    websocket原理概述:

websocket在TCP之上定义了帧协议,从而能够支持双向的通信。由于websocket本质上是一个基于TCP的协议,在建立Websocket连接前,浏览器或者其他客户端需要向服务

器发起请求,服务器解析请求后产生应答信息返回给,客户端,由此客户端与服务端的websocket连接建立成功,客户端和服务器都可以通过这条连接主动传递信息直至某一方主动关闭连接。

这次连接就是一次握手过程:

一、Websocket客户端首先发起一个请求。请求数据中包括服务器的IP和端口号、以及客户端随机生成的key等。

二、服务器端根据客户端的key生成密钥,并将密钥返回给客户端,握手成功。

3)                   其他通讯方案:

1、轮询

客户端以一定的时间间隔向服务器发送请求,以频繁请求方式来保持客户端和服务器端的数据同步。

轮询缺点:当客户端以固定频率向服务器发送请求时,服务器的数据可能并没有更新,这样会带来很多多余的请求,浪费宽带、效率低

2、长轮询

是对定时轮询的改进和提高,同时是为了降低无效的网络传输。当服务器端没有数据更新的时候,连接会保持一段时间周期,直到数据或状态改变或者时间过期。通过这种机制来减少无效的客户端的服务器间的交互。

长轮询缺点:如果服务器的数据变更非常频繁的话,没有明显的提高。

3、流

在客户端的页面使用一个隐藏的窗口向服务端发出一个长连接的请求,服务器端接到这个请求后作出反应并不断更新连接状态以保证客户端和服务器端的连接不过期

流 缺点:需要针对不同的浏览器设计不同的方案来改进用户体验,同时这种机制在并发比较大的情况下,对服务器端的资源是一个极大考验。

4、基于Flash的实时通讯方式

Flash有自己的socket实现,可以利用Flash完成数据交换,再利用Flash暴露出相应的接口,方便javascript调用来达到实时传输数据的目的

4)             websocket优势:

由于websocket的连接本质是一个TCP连接,所以与传统的轮询方式比,这种方式对于数据传输的稳定性和数量大小方面都有一定的优势,在流量比较大的情况下 使用websocket具有很大的性能优势

实现简单的通道连接和关闭

<span style="font-size:18px;">package com.ws.config;

import java.util.Set;

import javax.websocket.Endpoint;
import javax.websocket.server.ServerApplicationConfig;
import javax.websocket.server.ServerEndpointConfig;

public class WebSocketConfig implements ServerApplicationConfig{

<span style="white-space:pre">	</span>//实现了ServerApplicationConfig接口后,在项目启动时,此类自动执行,这样随着Tomcat的启动来启动WebSocket
<span style="white-space:pre">	</span>
<span style="white-space:pre">	</span>//注解方式的启动
<span style="white-space:pre">	</span>@Override
<span style="white-space:pre">	</span>public Set<Class<?>> getAnnotatedEndpointClasses(Set<Class<?>> scan) {
<span style="white-space:pre">		</span>
<span style="white-space:pre">		</span>//输出被扫描到的带注解的类的个数
<span style="white-space:pre">		</span>System.out.println("config....."+scan.size());
<span style="white-space:pre">		</span>
<span style="white-space:pre">		</span>//返回被扫描到的所有带@ServerEndpoint注解的类 方便服务器端注册websocket server
<span style="white-space:pre">		</span>return scan;
<span style="white-space:pre">	</span>}

<span style="white-space:pre">	</span>//接口方式的启动
<span style="white-space:pre">	</span>@Override
<span style="white-space:pre">	</span>public Set<ServerEndpointConfig> getEndpointConfigs(Set<Class<? extends Endpoint>> arg0) {
<span style="white-space:pre">		</span>
<span style="white-space:pre">		</span>return null;
<span style="white-space:pre">	</span>}

}</span>
<span style="font-size:18px;">package com.bwie.socket;

import java.io.IOException;

import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

/**
 * @author MSH
 *
 *
 */
@ServerEndpoint("/echo")//前台请求地址
public class EchoSocket {
	public EchoSocket(){
		System.out.println("echoSocket.EchoSocket()");
	}
	//前台访问后台新建一个session,相当于打开一条管道
	@OnOpen
	public void open (Session session){
		System.out.println("sessionid"+session.getId());
	}
	//前台退出,session关闭,通道关闭
	@OnClose
	public void close(Session session){
		System.out.println("sessionid"+session.getId()+"关闭了");
	}
	//开启通道,前后台响应传输信息,相当于一次握手
	@OnMessage
	public void message(Session session,String msg){
		System.out.println("客户端:"+msg );
		try {
			session.getBasicRemote().sendText("服务器:nihao too");
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}</span><span style="font-size:24px;">
</span>
<span style="font-size:18px;"><%@ page language="java" contentType="text/html; charset=UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
<script type="text/javascript">
	var ws;
	//访问后台地址
	var target="ws://localhost:8080/webSocket_01/echo";
	function subOpen(){
		//进入聊天页面,就打开socket通道
   	 	// 判断浏览器是IE还是火狐
		 if ('WebSocket' in window) {
             ws = new WebSocket(target);
         } else if ('MozWebSocket' in window) {
             ws = new MozWebSocket(target);
         } else {
             alert('WebSocket is not supported by this browser.');
             return;
         }
		 ws.onmessage=function(event){
			 var dv=document.getElementById("dv");
			 dv.innerHTML+=event.data;
		 };
	}
	function subSend(){
		 var msg=document.getElementById("msg").value;
		 ws.send(msg);//向后台发送消息
		 document.getElementById("msg").value="";
	}

</script>
</head>
<body>
<button onclick="subOpen()">open</button>
<input id="msg"><button onclick="subSend()">send</button>
<span id="dv"></span>
</body>
</html></span>

一个通信管道 发送多次消息,消息内容不一样!

消息   结构化对消息进行分类 : type : ‘公告’,通知,聊天内容

对消息进行包装:xml  json  {type:‘聊天内容‘,from:‘laotie‘,to:‘wangshuai‘,content:‘nihao‘,date:‘2016-0624‘}

websocket实现广播群聊单聊

<span style="font-size:18px;"><%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
     <form action="<%=request.getContextPath() %>/LoginServlet" method="get">
                  用户名:<input type="text" name="username">
       <input type="submit" value="登录">
     </form>
</body>
</html></span>
<span style="font-size:18px;">package com.ws.servlet;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/LoginServlet")
public class LoginServlet extends HttpServlet {

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{

		//前台获取登录名
		String username = request.getParameter("username");
		//将登录名放入session中
		request.getSession().setAttribute("username", username);
		//跳转到聊天页面
		response.sendRedirect("chat.jsp");
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{

		doGet(request, response);
	}

}</span>
<span style="font-size:18px;">package com.ws.socket;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

import com.google.gson.Gson;
import com.ws.bean.Content;
import com.ws.bean.Message;

@ServerEndpoint("/chatSocket")
public class ChatSocket {

	//用户名
	private String username; 

	//session集合
	private static List<Session> sessions = new ArrayList<>();

	//用户列表集合
	private static List<String> names = new ArrayList<String>();

	//用户名与session的Map
	private static Map<String,Session> map = new HashMap<String,Session>();

	@OnOpen
	public void open(Session session) throws UnsupportedEncodingException{

		//当前websocket的session对象,不是servlet的session,这里的一个session代表一个通信会话!
		 String queryString = session.getQueryString();

		//获取当前登录的用户名
		 username = queryString.split("=")[1];

		//将用户名放入用户列表集合
		 this.names.add(username);

		//将当前session放入session集合
		 this.sessions.add(session);

		//将用户名和对应session放入map中
		 map.put(username, session);

		//进入聊天室欢迎语
		 String msg = "欢迎"+this.username+"进入聊天室!!<br/>";

		//创建message对象
		 Message message = new Message();
		 message.setWelcome(msg);
		 message.setUsernames(this.names);

		//广播
		 this.broadcast(sessions, message.toJson());
	}

	//创建Gson对象
	private static Gson gson = new Gson();

	@OnMessage
	public void message(Session session,String json){

		//将json串转成java对象
		Content content = gson.fromJson(json, Content.class);

		if(content.getType()==1){
			//广播
			 Message message = new Message();
			 message.setUsernames(this.names);
			 message.setContent(this.username,content.getMsg());

			 broadcast(this.sessions,message.toJson());
		}else{
			//单聊
			//根据username找到对应的session对象
			String chatToWho = content.getChatToWho();
			Session to_session = map.get(chatToWho);

			 Message message = new Message();
			 message.setUsernames(this.names);
			 message.setContent(this.username,"<font color='red'>"+content.getMsg()+"</font>");

			 //向目标发送信息
			 try {
				to_session.getBasicRemote().sendText(message.toJson());
			} catch (IOException e) {

				e.printStackTrace();
			}
		}

	}

	@OnClose
	public void close(Session session){

		//session集合清除当前用户
		sessions.remove(session);

		//用户列表集合清除当前用户
		names.remove(username);

		//退出聊天室提示语
        String msg = username+"退出聊天室!!<br/>";

        //创建message对象
		 Message message = new Message();
		 message.setWelcome(msg);
		 message.setUsernames(this.names);

        //广播
		 broadcast(this.sessions,message.toJson());
	}

	public void broadcast(List<Session> ss,String msg){

		//遍历session集合
		for (Session session : ss) {
			try {
				//服务端向客户端发送消息
				session.getBasicRemote().sendText(msg);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}</span>
<span style="font-size:18px;"><%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<script type="text/javascript" src="<%=request.getContextPath()%>/jquery/jquery.min.js"></script>
<script type="text/javascript">

  //获取用户名
  var username = "${sessionScope.username}";
  //一个ws对象就是一个通信管道
  var ws;
  //服务器端EndPoint的URL
  var target="ws://169.254.187.126:8080/chat/chatSocket?username="+username;

    window.onload=function(){
    	//进入聊天页面,就打开socket通道
    	 // 判断浏览器是IE还是火狐
    		   if ('WebSocket' in window) {
    	                ws = new WebSocket(target);
    	            } else if ('MozWebSocket' in window) {
    	                ws = new MozWebSocket(target);
    	            } else {
    	                alert('WebSocket is not supported by this browser.');
    	                return;
    	            }

    	      ws.onmessage=function(event){

    	    	 //将gson转成字符串
    	    	  eval("var msg="+event.data+";");

    	    	 //进入聊天室的欢迎语
    	    	  if(undefined!=msg.welcome){
    	    		  $("#content").append(msg.welcome)
    	    	  }

    	    	 //用户列表
    	    	  if(undefined!=msg.usernames){
    	    		  $("#userList").html("");
    	    		  $(msg.usernames).each(function(){

    	    			  $("#userList").append("<input type='checkbox' value='"+this+"'>"+this+"<br/>")
    	    		  })
    	    	  }

    	    	 //服务端 发送到客户端的内容
    	    	  if(undefined!=msg.content){
    	    		  $("#content").append(msg.content)
    	    	  }
    	      }
    	  }

    //发送方法
    function subSend(){

    	var ss = $("#userList :checked");
    	var msg = $("#msg").val();

    	var obj = null;
    	if(ss.size()==0){
    		obj={
    				msg:msg,
    				type:1 //1 广播 2 单聊
    		}
    	}else{
    		var chatToWho = $("#userList :checked").val();
    		obj={
    				chatToWho:chatToWho,
    				msg:msg,
    				type:2  //1 广播 2 单聊
    		}
    	}

    	//将js对象转成json串
    	var str = JSON.stringify(obj);

    	ws.send(str);
    	$("#msg").val("");
    }

    //退出方法
    function exit(){
    	location.href="<%=request.getContextPath()%>/login.jsp";
    }

</script>
</head>
<body>
   <div id="container" style="border:1px solid black; width:400px; height:400px; float:left;">
       <div id="content" style="height:350px;"></div>
       <div style="border-top:1px solid black; width:400px; height:50px;">
           <input id="msg"/><button onclick="subSend();">发送</button>
           <button onclick="exit();">退出</button>
       </div>
   </div>
   <div id="userList" style="border:1px solid black; width:100px; height:400px; float:left;"></div>
</body>
</html></span>
package com.ws.bean;

import java.util.Date;
import java.util.List;

import com.google.gson.Gson;

public class Message {

	//第一句欢迎语
	private String welcome;

	//进入聊天室的用户列表
	private List<String> usernames;

	//聊天内容(发送者,发送时间,内容)
	private String content;

	public String getContent() {
		return content;
	}

	public void setContent(String content) {
		this.content = content;
	}

	public void setContent(String name,String msg) {
		this.content = name +" "+new Date().toLocaleString()+"<br/>"+msg+"<br/>";
	}

	public String getWelcome() {
		return welcome;
	}

	public void setWelcome(String welcome) {
		this.welcome = welcome;
	}

	public List<String> getUsernames() {
		return usernames;
	}

	public void setUsernames(List<String> usernames) {
		this.usernames = usernames;
	}

	//创建Gson对象
	private static Gson gson = new Gson();

	//将java对象转成json串
	public String toJson(){

		String json = gson.toJson(this);
		return json;
	}
}

package com.ws.bean;

public class Content {

	//单聊时 信息发送的目标
	private String chatToWho;

	//聊天内容
	private String msg;

	//聊天类型(群聊或者单聊)
	private Integer type;

	public String getChatToWho() {
		return chatToWho;
	}
	public void setChatToWho(String chatToWho) {
		this.chatToWho = chatToWho;
	}
	public String getMsg() {
		return msg;
	}
	public void setMsg(String msg) {
		this.msg = msg;
	}
	public Integer getType() {
		return type;
	}
	public void setType(Integer type) {
		this.type = type;
	}
}

时间: 2024-10-13 00:25:24

WebSocket实战的相关文章

websocket实战(3) 错误处理及配置管理

回顾 websocket实战(1) 入门 websocket实战(2) 信息处理发送.接收和编码 通过前面说明,已经轻松构建一个简单的websocket ServerEndPoint了.可以为EndPoint加上解码器,编码器,为EndPoint提供支持.但是,作为一个服务器,遇到错误怎么办?websocket作为一个简单的容器组件,也具备简单配置管理功能. 1.错误处理 [email protected] 其实很简单,就是在ServerEndPoint类中,添加一个方法,要求该方法被@onEr

websocket实战(4) websocket版贪食蛇游戏(tomcat官方自带)

websocket实战(1) 入门 websocket实战(2) 信息处理发送.接收和编码 websocket实战(3) 错误处理及配置管理 通过前面3篇的阐述,相信可以构建一个简单的socket应用了.当然,也会遗漏了许多知识点,相信会在以后分享的实例中捎带说明下. 本文的主要是分析下tomcat官方自带的贪食蛇游戏.为什么选择分析这个项目呢. 贪食蛇游戏规则,人人明白,业务方面不需要过多解释(当然这款websocket版的游戏规则也有一定特色). 游戏设计简单,一个对象足以完成游戏,但不涉及

C# WebApi+Task+WebSocket实战项目演练(四)

一.课程介绍 本次分享课程属于<C#高级编程实战技能开发宝典课程系列>中的第四部分,阿笨后续会计划将实际项目中的一些比较实用的关于C#高级编程的技巧分享出来给大家进行学习,不断的收集.整理和完善此系列课程!本高级系列课程适合人群如下: 1.有一定的NET开发基础并对WebApi.Task.WebSocket技术有一定了解和认识. 2.喜欢阿笨的干货分享课程的童鞋们. 希望大家在选择阿笨的 C#高级编程实战技能开发宝典课程系列的时候,根据自身的情况进行选择,由于本次课程不是零基础教学课程系列,所

websocket实战(1) 入门

1.WebSocket介绍 1.1 概念 WebSocket是HTML5中一系列新的API,或者说新规范,新技术.支持页面上使用Web Socket协议与远程主机进行全双工的通信.它引入了WebSocket接口并且定义了一个全双工的通信通道,通过一个单一的套接字在Web上进行操作. 1.2 websocket vs HTTP 首先,web技术发展经历了以下阶段. 静态页面(html) 动态页面(cgi,j2ee,php...) Ajax技术 comet技术(轮询) 1.2.1 实现方案对比 举个

SpringAOP+RabbitMQ+WebSocket实战

背景 最近公司的客户要求,分配给员工的任务除了有微信通知外,还希望PC端的网页也能实时收到通知.管理员分配任务是在我们的系统A,而员工接受任务是在系统B.两个系统都是现在已投入使用的系统. 技术选型 根据需求我们最终选用SpringAOP+RabbitMQ+WebSocket. SpringAOP可以让我们不修改原有代码,直接将原有service作为切点,加入切面.RabbitMQ可以让A系统和B系统解耦.WebSocket则可以达到实时通知的要求. SpringAOP AOP称为面向切面编程,

WebSocket实战之——携带Token验证绑定clientId到uid(微信)

HTML代码:通过为. <!DOCTYPE> <html> <meta charset="utf-8"/> <title>WebSocket Test</title> <script src="http://cdn.bootcss.com/jquery/2.1.3/jquery.min.js" type="text/javascript"></script> &l

WebSocket 实战

http://www.ibm.com/developerworks/cn/java/j-lo-WebSocket/ 本文介绍了 HTML5 WebSocket 的由来,运作机制及客户端和服务端的 API 实现,重点介绍服务端(基于 Tomcat7)及客户端(基于浏览器原生 HTML5 API)实现的详细步骤:并通过实际客户案例描述了客户端如何在 WebSocket 架构下使用 HTTP 长连接与服务器实现实时通信及消息推送的功能,读者通过阅读本文中案例示例代码的实现,能够更深刻理解 WebSoc

websocket实战(2) 信息处理发送、接收和编码

websocket 和传统意义上的socket编程虽然存在差别,但也存在相通概念,也分服务端和客户端. 主要区别 对于websocket,客户端的编写方式是通过JS编写回调函数完成交互:而传统socket,则需要连接端口,通过输入输出流来传递信息,完成交互: 传统的socket,服务端则需要绑定端口,通过accept 方法,等待客户端的连接.websocket 规范则把处理细节由web服务器来完成. 数据处理是websocket的一项主要工作.按工作阶段划分,主要包括以下方面. 信息发送 信息解

WebSocket实战之——JavaScript例子

源码地址:https://github.com/Tinywan/PHP_Experience 一.详细代码案例 详细解读一个简单html5 WebSocket的Js实例教程,附带完整的javascript websocket实例源码,以及实例代码效果演示页面,并对本实例的核心代码进行了深入解读.从WebSocket通讯三个阶段(打开握手.数据传递.关闭握手)进行了探讨,各阶段中浏览器和服务器做了些什么事情也有所涉及. //检查浏览器是否支持WebSocket if(window.WebSocke