前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >websocket 原

websocket 原

作者头像
尚浩宇
发布2018-08-17 09:58:58
7560
发布2018-08-17 09:58:58
举报
文章被收录于专栏:杂烩杂烩

     WebSocket protocol 是HTML5一种新的协议。它实现了浏览器与服务器全双工通信(full-duplex)。   

        在浏览器中通过http仅能实现单向的通信,comet可以一定程度上模拟双向通信,但效率较低,并需要服务器有较好的支持; flash中的socket和xmlsocket可以实现真正的双向通信,通过 flex ajax bridge,可以在javascript中使用这两项功能. 可以预见,如果websocket一旦在浏览器中得到实现,将会替代上面两项技术,得到广泛的使用.面对这种状况,HTML5定义了WebSocket协议,能更好的节省服务器资源和带宽并达到实时通讯。

在JavaEE7中也实现了WebSocket协议。

        官方语言结束。

        spring自身支持websocket,有自己的一套流程,这里并不是这样的做的,关于spring的可以自己百度学习一下,另外注意jdk要是1.7的,tomcat要是7.0.51以上的。浏览器的话,ie9我测的是不支持的,其他谷歌火狐肯定支持的。不过html5的东西有句话说的好,叫一段代码,放到ie上不运行,放到其他浏览器上却运行了,那么这段代码就是html5.

        废话不多说,看代码:

        首先要有个扫描注解@ServerEndpoint的驱动器:

WebScoketScanner.java

代码语言:javascript
复制
package com.cmicroentropy.soa.websocket.scanner;

import java.util.HashSet;
import java.util.Set;

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

import org.apache.log4j.Logger;

public class WebScoketScanner implements ServerApplicationConfig{
	private Logger logger=Logger.getLogger(WebScoketScanner.class);
	@Override
	public Set<Class<?>> getAnnotatedEndpointClasses(Set<Class<?>> scanned) {
		logger.info("开始扫描所有websocket服务(注解)");
		Set<Class<?>> res=new HashSet<>();
		for(Class<?> cs:scanned){
			if(cs.getPackage().getName().startsWith("com.cmicroentropy.soa.websocket.servers")){
				res.add(cs);
			}
		}
		return res;
	}

	@Override
	public Set<ServerEndpointConfig> getEndpointConfigs(Set<Class<? extends Endpoint>> arg0) {
		logger.info("开始扫描所有websocket服务(继承)");
		Set<ServerEndpointConfig> res=new HashSet<>();
		/*
	   //使用Programmatic api的服务器地址

		if (scanned.contains(EchoEndpoint.class)) {
            res.add(ServerEndpointConfig.Builder.create(
                    EchoEndpoint.class,
                    "/websocket/echoProgrammatic").build());
        }
        */
		return res;
	}
}

    然后建一个节点类处理请求:

    ChatServer.java

代码语言:javascript
复制
package com.cmicroentropy.soa.websocket.servers.chatserver;

import static com.cmicroentropy.soa.websocket.transform.MessageTransFormUtil.tranOtherMsg;
import static com.cmicroentropy.soa.websocket.transform.MessageTransFormUtil.tranSysMsg;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;

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

import org.apache.log4j.Logger;

import scc.util.SccUtilFactory;

import com.cmicroentropy.soa.websocket.transform.MessageTransFormUtil;

@ServerEndpoint(value = "/ChatServer.do")
// 用了这个之后,你的服务地址为ws://localhost:port/projectName/ChatController
public class ChatServer {
	private Logger logger=Logger.getLogger(ChatServer.class);
	private static final Set<ChatServer> connections = new CopyOnWriteArraySet<ChatServer>();
	private String nickname;
	private Session session;
	private Integer userid;

	public ChatServer() {

	}

	@OnOpen
	public void start(Session session) {
		this.session = session;
		Map<String, String> paras = SccUtilFactory.instanceString().getParameterFromUri(session.getRequestURI());
		if (null == nickname)
			nickname = paras.get("username");
		if (null == userid)
			userid = Integer.valueOf(paras.get("userid"));
		connections.add(this);
		logger.info(new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss").format(new Date())+" 用户:[" + nickname + "]登录系统.");
		broadcast(new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss").format(new Date())+" 用户:[" + nickname + "]登录系统.", 1);
	}

	@OnClose
	public void end() {
		connections.remove(this);
		logger.info(new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss").format(new Date())+" 用户:[ " + nickname + "]退出系统.");
		broadcast(new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss").format(new Date())+" 用户:[ " + nickname + "]退出系统.",1);
	}

	@OnMessage
	public void receive(String message) {
		broadcast("<font style='color:#FE4D00'>["+nickname + "-"+new SimpleDateFormat("HH:mm").format(new Date())+"]:</font>" + message,2);
	}

	public Integer getUserid() {
		return this.userid;
	}

	private void broadcast(String msg, Integer type) {
		switch (type) {
		// 1是系统消息
		case 1:
			msg = tranSysMsg(msg);
			for (ChatServer client : connections) {
				try {
					client.session.getBasicRemote().sendText(msg);
				} catch (IOException e) {
					connections.remove(client);
					try {
						client.session.close();
					} catch (IOException e1) {
						e1.printStackTrace();
					}
					continue;
				}
			}
			break;
		case 2:
			for (ChatServer client : connections) {
				try {
					if(client.getUserid().equals(this.userid)){
						client.session.getBasicRemote().sendText(MessageTransFormUtil.tranSelfMsg(msg));
					}else{
						client.session.getBasicRemote().sendText(tranOtherMsg(msg));
					}
				} catch (IOException e) {
					connections.remove(client);
					try {
						client.session.close();
					} catch (IOException e1) {
						e1.printStackTrace();
					}
					continue;
				}
			}
			break;
		}
		
	}
}

    静态引入MessageTransFormUtil类是一个返回字符串封装的格式工具类,代码如下:

    MessageTransFormUtil.java

代码语言:javascript
复制
package com.cmicroentropy.soa.websocket.transform;

public class MessageTransFormUtil {
	public static String tranSysMsg(String word){
		StringBuilder sb=new StringBuilder();
		sb.append("<div><div class='tuling-sys'><span >");
		sb.append(word);
		sb.append("</span></div></div>");
		return sb.toString();
	}
	public static String tranSelfMsg(String word){
		StringBuilder sb=new StringBuilder();
		sb.append("<div class='tuling-mn'><img src='images/proexp_014.jpg' class='pull-right'><span class='pull-right tuling tuling2'>");
		sb.append(word);
		sb.append("</span></div>");
		return sb.toString();
	}
	public static String tranOtherMsg(String word){
		StringBuilder sb=new StringBuilder();
		sb.append("<div><div class='tuling-mn'><img src='images/proexp_011.jpg' class='pull-left'><span class='pull-left tuling'>");
		sb.append(word);
		sb.append("</span></div></div>");
		return sb.toString();
	}
}

特别注意的是@ServerEndpoint后的值,我这里springmvc拦截的以.do结尾的请求。所以在value里也以.do结尾。如果启动后发现访问不了请检查一下是不是没有走进去。

最后是页面:

代码语言:javascript
复制
function initchat(){
	//显示消息记录
    Console.log = (function(message) {
    	var size=$("#chatbox>div>div:first>div").size();
    	if(size==0){
    		   $("#chatbox").mCustomScrollbar({
    				 autoHideScrollbar : true,
    				 theme : "dark-thin"
    			 });
    	}else{
    		var divheight=$("#chatbox>div>div:first").height();
    		if(size>300&&divheight>9900){
    			$("#chatbox>div>div:first>div:lt(1)").remove();
    			$("#chatbox").mCustomScrollbar("update");
    		}
    	}
    	$("#chatbox>div>div:first").append(message);
    	$("#chatbox").mCustomScrollbar("update");
	    $("#chatbox").mCustomScrollbar("scrollTo","last");
    	/* while ($("#chatbox>div").size() > 500) {
    		 $("#chatbox>div:first").remove();
            }
    	 $("#chatbox")[0].scrollTop = $("#chatbox")[0].scrollHeight;*/
    });
    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('错误: 聊天室 不支持此浏览器请更换成谷歌或火狐浏览器、360浏览器、360极速浏览器等高版本浏览器');
            return;
        }
		//建立连接触发事件
        Chat.socket.onopen = function () {
            Console.log("<div><div class='tuling-sys'><span >信息: 聊天室服务器 链接成功.</span></div></div>");
            $("#sendchattext").keydown(function(event){
            	if(event.keyCode==13&& event.ctrlKey) {
                    Chat.sendMessage();
    		     }
        	});
        };
		//关闭连接触发事件
        Chat.socket.onclose = function () {
        	$("#sendchattext").unbind("keydown");
            Console.log("<div><div class='tuling-sys'><span >信息: 聊天室服务器 已关闭.</span></div></div>");
        };
		//接收消息触发事件
        Chat.socket.onmessage = function (message) {
        	if(message.data.indexOf("pull-right")==-1)
        		setchatMsgnum();
            Console.log(message.data);
        };
    });
  //发送聊天信息方法
    Chat.sendMessage = (function() {
        var message = $("#sendchattext").val();
        if (message != ''&&message.length<500) {
            Chat.socket.send(message);
            $("#sendchattext").val("");
            $("#sendchattext").focus();
        }else{
        	alertMsg("您输入的字数过多(>500),请拆分后发送!");
        	$("#sendchattext").focus();
        }
    });
	//初始化聊天对象方法,注意URL中的项目名称和Servlet名称
    Chat.initialize = function() {
        if (window.location.protocol == 'http:') {
            Chat.connect('ws://' + window.location.host + '/sjws_soa_product/ChatServer.do?username='+username+'&userid='+userid);
        } else {
            Chat.connect('wss://' + window.location.host + '/sjws_soa_product/ChatServer.do?username='+username+'&userid='+userid);
        }
    };
    Chat.initialize();
}
function sendchatMessage(){
	Chat.sendMessage();
}

如果直接copy页面代码因为没有样式等可能看不到实际效果,下面给出一个当初学习websocket借鉴的项目,名字记不得了,感谢前人馈赠!百度网盘地址http://pan.baidu.com/s/1g2V3C

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2015/05/05 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档