webSocket一对一 、一对多通信

最近趁着空闲时间,搭建了一套webSocket的demo,以做备用,那么我们先来简单的说一下什么是webSocket?

它的最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送技术的一种。

其他特点包括:
(1)建立在 TCP 协议之上,服务器端的实现比较容易。
(2)与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。
(3)数据格式比较轻量,性能开销小,通信高效。
(4)可以发送文本,也可以发送二进制数据。
(5)没有同源限制,客户端可以与任意服务器通信。
(6)协议标识符是ws(如果加密,则为wss),服务器网址就是 URL。

如果说刚毕业的你可能对于java socket不太理解,不用担心,webSocket还是很好理解的,需要你自己动手去敲代码,研究每一部分的作用与意义,毕竟实战是最好的老师!

首先我们新建一个maven的web工程,在webApp下建立两个jsp文件


此处贴出我们的js代码,你可以画个简单的页面去调用

var websocket = null;
	//判断当前浏览器是否支持WebSocket
	if ('WebSocket' in window) {
		var url = "ws://" + window.location.host +"/webSocket/webSocketOneToOne/1,123"
		websocket = new WebSocket(url);
	} else {
		alert('当前浏览器 Not support websocket')
	}
	//连接发生错误的回调方法
	websocket.onerror = function() {
		setMessageInnerHTML("WebSocket连接发生错误");
	};
	//连接成功建立的回调方法
	websocket.onopen = function() {
		setMessageInnerHTML("WebSocket连接成功");
	}
	//接收到消息的回调方法
	websocket.onmessage = function(event) {
		console.log("回调信息",event.data)
		setMessageInnerHTML(event.data);
	}
	//连接关闭的回调方法
	websocket.onclose = function() {
		setMessageInnerHTML("WebSocket连接关闭");
	}
	//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
	window.onbeforeunload = function() {
		closeWebSocket();
	}
	//将消息显示在网页上
	function setMessageInnerHTML(innerHTML) {
		document.getElementById('message').innerHTML += innerHTML + '
'; } //关闭WebSocket连接 function closeWebSocket() { websocket.close(); } //发送消息 function send() { var message = document.getElementById('text').value; //message作为发送的信息,role作为发送的对象标识,socketId是此次会话的标识 websocket.send(JSON.stringify({'message':message,'role':'2','socketId':"123"})); }

	
	
	


user_2.jsp和1类似,需要你修改的就是 webSocket对象地址后的标识发送的对象标识

后台语言我们用的是java,编写代码前我们需要在pom.xml中引入如下依赖包


		
			javax
			javaee-api
			7.0
			provided
		
接下来我们就可以着手编写java代码了,具体的用法我都打注释了

package com.webSocket;

import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;

import net.sf.json.JSONObject;

/**
 * @ServerEndpoint 注解是一个类层次的注解,它的功能主要是将目前的类定义成一个websocket服务器端,
 *                 注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端
 */
@ServerEndpoint(value = "/webSocketOneToOne/{param}")
public class WebSocketOneToOne {
	// 静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
	private static int onlineCount;
	//实现服务端与单一客户端通信的话,可以使用Map来存放,其中Key为用户标识
	private static Map connections = new ConcurrentHashMap<>();
	// 与某个客户端的连接会话,需要通过它来给客户端发送数据
	private Session session;
	private String role;
	private String socketId;

	/**
	 * 连接建立成功调用的方法
	 * 
	 * @param session
	 *            可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据
	 */
	@OnOpen
	public void onOpen(@PathParam("param") String param,Session session) {
		this.session = session;
		String[] arr = param.split(",");
        this.role = arr[0];             //用户标识
        this.socketId = arr[1];         //会话标识
		connections.put(role,this);     //添加到map中
		addOnlineCount();               // 在线数加
		System.out.println("有新连接加入!新用户:"+role+",当前在线人数为" + getOnlineCount());
	}

	/**
	 * 连接关闭调用的方法
	 */
	@OnClose
	public void onClose() {
		connections.remove(role);  // 从map中移除
		subOnlineCount();          // 在线数减
		System.out.println("有一连接关闭!当前在线人数为" + getOnlineCount());
	}

	/**
	 * 收到客户端消息后调用的方法
	 * 
	 * @param message
	 *            客户端发送过来的消息
	 * @param session
	 *            可选的参数
	 */
	@OnMessage
	public void onMessage(String message, Session session) {
		System.out.println("来自客户端的消息:" + message);
		JSONObject json=JSONObject.fromObject(message);
		String string = null;  //需要发送的信息
		String to = null;      //发送对象的用户标识
		if(json.has("message")){
			 string = (String) json.get("message");
		}
		if(json.has("role")){
			 to = (String) json.get("role");
		}
		send(string,role,to,socketId);
	}

	/**
	 * 发生错误时调用
	 * 
	 * @param session
	 * @param error
	 */
	@OnError
	public void onError(Session session, Throwable error) {
		System.out.println("发生错误");
		error.printStackTrace();
	}

	
	//发送给指定角色
	public static void send(String msg,String from,String to,String socketId){
    	try {
    		//to指定用户
    		WebSocketOneToOne con = connections.get(to);
			if(con!=null){
				if(socketId==con.socketId||con.socketId.equals(socketId)){
					con.session.getBasicRemote().sendText(from+"说:"+msg);	
				}
	
			}
			//from具体用户
			WebSocketOneToOne confrom = connections.get(from);
			if(confrom!=null){
				if(socketId==confrom.socketId||confrom.socketId.equals(socketId)){
					confrom.session.getBasicRemote().sendText(from+"说:"+msg);	
				}
	
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    }

	public static synchronized int getOnlineCount() {
		return onlineCount;
	}

	public static synchronized void addOnlineCount() {
		WebSocketOneToOne.onlineCount++;
	}

	public static synchronized void subOnlineCount() {
		WebSocketOneToOne.onlineCount--;
	}
}

如果你想在此基础上扩展群聊,其实出去用户标识就可以了,只建立一个会话标识,也可以此作为邀请码,模仿邀请用户进入聊天

至此,一个简单的webSocket就搭建好了,可移植性高,你可以集成到你的项目里尽情的玩耍了,也可发挥你的想象去扩展!





你可能感兴趣的:(webSocket,websocket,通信,socket,web,app,web)