zoukankan      html  css  js  c++  java
  • java websockect

    https://github.com/TooTallNate/Java-WebSocket (websockect类库包)

    http://blog.openlg.net/index.php/archives/129(实例篇)

    http://my.oschina.net/yushulx/blog/298140 (使用Jetty搭建Java Websocket Server,实现图像传输)

    http://linxh83.iteye.com/blog/1466017 (jWebSocket使用指南)

    http://findhy.com/blog/2014/06/12/java-websocket/(Java-WebSocket)

    http://tomcat.apache.org/ (7.0.26支持websocket)

    http://java-websocket.org/ (A barebones WebSocket client and server implementation written in 100% Java.)

    使用WebSocket技术实现浏览器和服务器的双向通信(一)

    WebSocket 规范的目标是在浏览器中实现和服务器端双向通信。双向通信可以拓展浏览器上的应用类型,例如实时的数据推送(股票行情)、游戏、聊天等.

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

    WebSocket protocol 是HTML5一种新的协议(protocol)。它是实现了浏览器与服务器全双工通信(full-duplex)。
    现在,很多网站为了实现即时通讯(real-time),所用的技术都是轮询(polling)。轮询是在特定的的时间间隔(time interval)(如每1秒),由浏览器对服务器发出HTTP request,然后由服务器返回最新的数据给客服端的浏览器。这种传统的HTTP request d的模式带来很明显的缺点 – 浏览器需要不断的向服务器发出请求(request),然而HTTP request 的header是非常长的,里面包含的数据可能只是一个很小的值,这样会占用很多的带宽。
    而最比较新的技术去做轮询的效果是Comet – 用了AJAX。但这种技术虽然可达到全双工通信,但依然需要发出请求(reuqest)。
    在 WebSocket API,浏览器和服务器只需要要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。在此WebSocket 协议中,为我们实现即使服务带来了两大好处:
    1. Header
    互相沟通的Header是很小的-大概只有 2 Bytes
    2. Server Push
    服务器可以主动传送数据给客户端
     
    明天为大家分享如何使用Java实现WebSocket Server端。

    目录结构:

    Screenshot from 2013-01-24 21:11:08

    1.WebSocket Server服务抽象类WSServer.java:
    package com.hisense.romeo.websocket.server;
    
    /**
     * 
     * WebSocket Server服务抽象类
     * 	自定义处理WebSocket客户端请求的服务:
     * 	1.继承并实现此类抽象方法
     * 	2.修改配置文件/WEB-INF/conf/spring/applicationContext-websocket.xml,给wsServerDispatcher添加处理
     * 		例如:实现一个简单的聊天室,在配置文件中添加
     * 			{@code
     * 				
     * 			}
     * 		当客户端请求ws://127.0.0.1:8089/chat时,系统会自动将请求分派给com.hisense.romeo.websocket.server.dispatcher.ChatWSServer处理
     * 	3.如需发送消息可以直接调用wsServerDispatcher.sendMessage方法
     * 
     * 
     * @see com.hisense.romeo.websocket.server.IWSServerDispatcher
     * 
     * @author 	lirufei@lg	mailto:lirufei0808@gmail.com
     * @version	v0.0.1
     */
    public abstract class WSServer implements IWSServer {
    	
    	/**
    	 * 当前调度WebSocket请求的服务,实现者可以用它进行向客户但发送消息
    	 */
    	protected IWSServerDispatcher wsServerDispatcher;
    
    	/**
    	 * 注册当前WebSocket服务调度员的方法
    	 * 
    	 * @param wsServerDispatcher
    	 */
    	public void registerWSServerDispatcher(IWSServerDispatcher wsServerDispatcher) {
    		this.wsServerDispatcher = wsServerDispatcher;
    	}
    }
    
     2.WebSocket请求调度工作WSServerDispatcher.java:
    package com.hisense.romeo.websocket.server;
    
    import java.net.InetSocketAddress;
    import java.net.UnknownHostException;
    import java.util.Collection;
    import java.util.HashMap;
    import java.util.HashSet;
    import java.util.Map;
    import java.util.Set;
    
    import org.apache.log4j.Level;
    import org.apache.log4j.Logger;
    import org.java_websocket.WebSocket;
    import org.java_websocket.WebSocketServer;
    import org.java_websocket.handshake.ClientHandshake;
    import org.springframework.beans.factory.DisposableBean;
    import org.springframework.beans.factory.InitializingBean;
    
    /**
     * 
     * 实现WebSocket请求调度工作
     * 	根据客户端请求地址中的请求资源进行调度
     * 	例如:Address: ws://127.0.0.1:8089/chat
     * 		程序会获取address中的chat进行分发请求。
     * 
     * @author 	lirufei@lg	mailto:lirufei0808@gmail.com
     * @version	
     *
     */
    public class WSServerDispatcher extends WebSocketServer implements IWSServerDispatcher, InitializingBean, DisposableBean{
    	
    	/**
    	 * Log4j
    	 */
    	private Logger logger = Logger.getLogger(this.getClass());
    	
    	private Map<string, iwsserver=""> wsServers;
    	
    	private static int port = 8089;
    	
    	public WSServerDispatcher() throws UnknownHostException {
    		this(new InetSocketAddress(port));
    	}
    	
    	public WSServerDispatcher(InetSocketAddress address){
    		super(address);
    		logger.debug("default using port '" + address.getPort() + "' to startup the WebSocket Server." );
    	}
    
    	/**
    	 * 建立新连接时自动调用此方法
    	 * 
    	 * @see org.java_websocket.WebSocketServer#onOpen(org.java_websocket.WebSocket, org.java_websocket.handshake.ClientHandshake)
    	 */
    	@Override
    	public void onOpen(WebSocket ws, ClientHandshake clientHandData) {
    		ws.setHandshakedata(clientHandData);
    		logger.debug("new Client:
    	" + ws.getRemoteSocketAddress() + "
    	" + clientHandData.getResourceDescriptor());
    	}
    
    	/**
    	 * 当接收到新消息时调用此方法
    	 * 
    	 * @see org.java_websocket.WebSocketServer#onMessage(org.java_websocket.WebSocket, java.lang.String)
    	 */
    	@Override
    	public void onMessage(WebSocket ws, String message) {
    		logger.debug("new Message:
    :	" + ws.getRemoteSocketAddress() + ":
    	" + message);
    		String resource = getResourceDescriptor(ws);
    		if(resource != null && resource.trim().length()!=0){
    			IWSServer listener = wsServers.get(resource);
    			if(listener != null)
    				listener.onMessage(ws, message);
    			else
    				logger.error("请求资源" + resource + "不存在!");
    		} else
    			logger.error("请求资源不能为空!");
    	}
    
    	/**
    	 * 连接关闭时自动调用此方法
    	 * 
    	 * @see org.java_websocket.WebSocketServer#onClose(org.java_websocket.WebSocket, int, java.lang.String, boolean)
    	 */
    	@Override
    	public void onClose(WebSocket ws, int arg1, String arg2, boolean arg3) {
    		logger.debug("client close:
    " + ws.getRemoteSocketAddress());
    	}
    
    	/**
    	 * 当连接出现错误时自动调用此方法
    	 * 
    	 * @see org.java_websocket.WebSocketServer#onError(org.java_websocket.WebSocket, java.lang.Exception)
    	 */
    	@Override
    	public void onError(WebSocket ws, Exception e) {
    		logger.error("client error:
    " + ws.getRemoteSocketAddress() + "
    ", e);
    	}
    	
    	/**
    	 * 根据请求资源导航串获取所有的客户端
    	 * 
    	 * @param navigation
    	 * @return
    	 */
    	@Override
    	public Set getClientByNavigation(String navigation){
    		if( navigation == null)
    			return null;
    		
    		Set wss = new HashSet();
    		Set conections = this.connections();
    		for (WebSocket webSocket : conections) {
    			String resource = this.getResourceDescriptor(webSocket);
    			if(resource != null && resource.equals(navigation))
    				wss.add(webSocket);
    		}
    		return wss;
    	}
    	
    	/**
    	 * 获取客户端数量
    	 * @see com.hisense.romeo.websocket.server.IWSSendMessage#getClientCount(java.lang.String)
    	 */
    	@Override
    	public int getClientCount(String name){
    		Set set = this.getClientByNavigation(name);
    		if(set != null)
    			return set.size();
    		return 0;
    	}
    	
    	/**
    	 * 给${navigation}的所有客户段发送消息${message}
    	 * 
    	 * @param message	
    	 * @param navigation	Not Null
    	 */
    	public void sendMessage(String message, String navigation){
    		this.sendMessage(this.getClientByNavigation(navigation), message);
    	}
    	
    	/**
    	 * 发送消息给所有客户端
    	 * 
    	 * @param message
    	 */
    	public void sendMessageToAll(String message){
    		this.sendMessage(this.connections(), message);
    	}
    	
    	/**
    	 * 发送消息给wss
    	 * 
    	 * @param wss
    	 * @param message
    	 */
    	public void sendMessage(Set wss, String message){
    		if( wss != null)
    			for (WebSocket webSocket : wss) {
    				webSocket.send(message);
    			}
    	}
    
    	/**
    	 * 当服务器退出时调用此方法
    	 * 
    	 * @see org.springframework.beans.factory.DisposableBean#destroy()
    	 */
    	@Override
    	public void destroy() throws Exception {
    		logger.info("Stop web socket server...");
    		super.stop();
    		if( wsServers != null && !wsServers.isEmpty()){
    			Set set = wsServers.keySet();
    			for (String key : set) {
    				wsServers.get(key).destroy();
    			}
    		}
    	}
    
    	/**
    	 * 当服务器启动时调用此方法
    	 * 
    	 * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
    	 */
    	@Override
    	public void afterPropertiesSet() throws Exception {
    		logger.info("**Startup web socket server,listening on port <" + port + ">.**");
    		
    		if(wsServers == null )
    			wsServers = new HashMap<string, iwsserver="">();
    		
    		try {
    			WebSocket.DEBUG = Logger.getLogger("com.hisense.romeo.websocket.server").getLevel().toInt() == Level.DEBUG_INT;
    			
    			this.start();
    			
    			logger.debug("**Initialization dispatchers.**");
    			Collection collection = wsServers.values();
    			for (IWSServer wsServerListener : collection) {
    				wsServerListener.registerWSServerDispatcher(this);
    			}
    			
    			logger.info("**WebSocket server has started.**");
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    	}
    	
    	/**
    	 * 获取客户端webSocket请求的资源
    	 * 
    	 * @param webSocket
    	 * @return
    	 */
    	private String getResourceDescriptor(WebSocket webSocket){
    		if(webSocket != null && webSocket.getHandshakedata() != null){
    			String resource = webSocket.getHandshakedata().getResourceDescriptor();
    			if(resource != null && resource.length() > 0)
    				return resource.substring(1);
    			else
    				return resource;
    		} else
    			return null;
    	}
    
    	/**
    	 * 设置WebSocket服务的监听端口
    	 * 
    	 * @param port
    	 */
    	public void setPort(int port) {
    		WSServerDispatcher.port = port;
    		this.setAddress(new InetSocketAddress(port));
    		logger.debug("Update port to '" + port + "' ant startup the WebSocket Server." );
    	}
    	
    	public int getPort(){
    		return super.getPort();
    	}
    
    	public Map<string, iwsserver=""> getWsServers() {
    		return wsServers;
    	}
    
    	public void setWsServers(Map<string, iwsserver=""> wsServers) {
    		this.wsServers = wsServers;
    	}
    	
    }
    
    3.接口IWSServerDispatcher.java:
    package com.hisense.romeo.websocket.server;
    
    import java.util.Set;
    
    import org.java_websocket.WebSocket;
    
    /**
    * <pre>
    * getClientByNavigation(String navigation) 根据请求资源导航串获取所有的客户端
    * sendMessage(String message, String navigation) 给请求${navigation}的所有客户段发送消息${message}
    * sendMessage(Set<WebSocket> wss, String message) 发送消息给${wss}
    * sendMessageToAll(String message) 发送消息给所有客户端
    * </pre>
    * @author lirufei@lg mailto:lirufei0808@gmail.com
    * @version v0.0.1
    *
    */
    public interface IWSServerDispatcher extends IWSSendMessage{
    
    /**
    * 根据请求资源导航串获取所有的客户端
    *
    * @param navigation
    * @return
    */
    public Set<WebSocket> getClientByNavigation(String navigation);
    }
    4.接口IWSServer.java:
    package com.hisense.romeo.websocket.server;
    
    import org.java_websocket.WebSocket;
    
    /**
    *
    *
    * @author lirufei@lg mailto:lirufei0808@gmail.com
    * @version
    *
    */
    public interface IWSServer {
    
    /**
    * 注册当前WebSocket服务调度员的方法
    *
    * @param wsServerDispatcher
    */
    public void registerWSServerDispatcher(IWSServerDispatcher wsServerDispatcher);
    
    /**
    * 当接收到客户端消息时,会调用这个方法
    *
    * @param ws 客户端信息
    * @param msg 接收到的消息
    */
    public abstract void onMessage(WebSocket ws, String msg);
    
    /**
    * 销毁方法,当服务器停止时调用这个方法
    */
    public abstract void destroy();
    }
    5.接口IWSSendMessage.java:
    package com.hisense.romeo.websocket.server;
    
    import java.util.Set;
    
    import org.java_websocket.WebSocket;
    
    /**
    * 定义使用WebSocket向客户端发送消息的方法
    *
    * @author lirufei@lg mailto:lirufei0808@gmail.com
    * @version
    *
    */
    public interface IWSSendMessage {
    
    /**
    * 给请求${navigation}的所有客户段发送消息${message}
    *
    * @param message 要发送的消息
    * @param navigation Not Null
    */
    public void sendMessage(String message, String navigation);
    
    /**
    * 发送消息给<code>wss</code>
    *
    * @param wss
    * @param message
    */
    public void sendMessage(Set<WebSocket> wss, String message);
    
    /**
    * 发送消息给所有客户端
    *
    * @param message
    */
    public void sendMessageToAll(String message);
    
    /**
    * 根据名字查询客户端数量
    *
    * @param name
    */
    public int getClientCount(String name);
    }
    6.消息值对象:MessageEntity.java
    package com.hisense.romeo.websocket.common;
    
    import java.io.Serializable;
    
    /**
    * @author lirufei@lg mailto:lirufei0808@gmail.com
    * @version v0.0.1
    *
    */
    public class MessageEntity implements Serializable{
    
    /**
    *
    */
    private static final long serialVersionUID = 1L;
    
    /**
    * 用户名
    */
    private String user;
    
    /**
    * 密码
    */
    private String pass;
    
    /**
    * 目标模块
    */
    private String target;
    
    /**
    * 消息
    */
    private String message;
    
    /**
    * 是否成功
    */
    private boolean success = true;
    
    public String getUser() {
    return user;
    }
    
    public void setUser(String user) {
    this.user = user;
    }
    
    public String getPass() {
    return pass;
    }
    
    public void setPass(String pass) {
    this.pass = pass;
    }
    
    public String getTarget() {
    return target;
    }
    
    public void setTarget(String target) {
    this.target = target;
    }
    
    public String getMessage() {
    return message;
    }
    
    public void setMessage(String message) {
    this.message = message;
    }
    
    public boolean getSuccess() {
    return success;
    }
    
    public void setSuccess(boolean success) {
    this.success = success;
    }
    
    }
    7.业务值对象:RefreshVO.java
    package com.hisense.romeo.websocket.common;
    
    /**
    * <pre>
    * 值对象
    * 用于WebSocket推送数据变化的进行数据刷新的值对象
    * </pre>
    * @author lirufei@lg mailto:lirufei0808@gmail.com
    * @version
    *
    */
    public class RefreshVO extends MessageEntity {
    
    /**
    *
    */
    private static final long serialVersionUID = 1L;
    
    /**
    * 变化的表名称
    */
    private String[] tables;
    
    public String[] getTables() {
    return tables;
    }
    
    public void setTables(String[] tables) {
    this.tables = tables;
    }
    }
    8.用于聊天的服务端程序ChatWSServer.java
    package com.hisense.romeo.websocket.server.dispatcher;
    
    import org.java_websocket.WebSocket;
    
    import com.hisense.romeo.websocket.server.WSServer;
    
    /**
    * 实现简单聊天室
    *
    * @author lirufei@lg mailto:lirufei0808@gmail.com
    * @version
    *
    */
    public class ChatWSServer extends WSServer{
    
    /**
    * @see com.hisense.romeo.websocket.server.IWSServer#onMessage(org.java_websocket.WebSocket, java.lang.String)
    */
    @Override
    public void onMessage(WebSocket ws, String msg) {
    if(wsServerDispatcher != null )
    wsServerDispatcher.sendMessage(ws.getRemoteSocketAddress().getHostName() + "说:" + msg, "chat");
    }
    
    /**
    * @see com.hisense.romeo.websocket.server.IWSServer#destroy()
    */
    @Override
    public void destroy() {
    
    }
    
    }
    9.用于发送和接收消息的客户端代码chat.js:
    // Write your code in the same way as for native WebSocket:
    var hostname = location.hostname,
    ws = new WebSocket('ws://' + hostname + ':8089/chat'),
    msg = document.getElementById('msg'),
    text = document.getElementById('text'),
    btn = document.getElementById('button');
    
    setMsgValue = function(val){
    msg.value = msg.value + val;
    if(msg.scrollByLines)
    msg.scrollByLines(5);
    else
    msg.scrollTop = msg.value.length;
    };
    
    ws.onopen = function() {
    setMsgValue('open');
    };
    ws.onmessage = function(e) {
    setMsgValue('
    ' + e.data);
    };
    ws.onclose = function() {
    setMsgValue('
    ' + 'close');
    };
    
    btn.onclick = function(){
    ws.send(text.value);
    text.value='';
    };
    text.onkeyup = function(e){
    if(/(m|M)(s|S)(i|I)(e|E)/.test(navigator.userAgent))
    e = window.event;
    if(e.keyCode === 13){
    ws.send(text.value);
    text.value='';
    }
    }

    源码下载:http://42.96.146.196/share/ws.7z

  • 相关阅读:
    Chrome插件开发,美化网页上的文件列表。chrome-extension,background
    Chrome插件开发,美化网页上的文件列表。chrome-extension,content-scripts
    ASP.NET MVC 常用扩展点:过滤器、模型绑定等
    Windows下Redis缓存服务器的使用 .NET StackExchange.Redis Redis Desktop Manager
    企业号微信支付 公众号支付 H5调起支付API示例代码 JSSDK C# .NET
    分享一个html+js+ashx+easyui+ado.net权限管理系统
    ASP.NET MVC Filters 4种默认过滤器的使用【附示例】
    ASP.NET MVC Controllers and Actions
    玩转控件:Fucking ERP之流程图
    玩转控件:对Dev的GridControl控件扩展
  • 原文地址:https://www.cnblogs.com/fx2008/p/4094181.html
Copyright © 2011-2022 走看看