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/

使用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端。

目录结构:

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 	[email protected]	mailto:[email protected]
 * @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 	[email protected]	mailto:[email protected]
 * @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:\n	" + ws.getRemoteSocketAddress() + "\n	" + 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:\n:	" + ws.getRemoteSocketAddress() + ":\n	" + 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:\n" + 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:\n" + ws.getRemoteSocketAddress() + "\n", 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 [email protected] mailto:[email protected]
* @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 [email protected] mailto:[email protected]
* @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 [email protected] mailto:[email protected]
* @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 [email protected] mailto:[email protected]
* @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 [email protected] mailto:[email protected]
* @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 [email protected] mailto:[email protected]
* @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(‘\n‘ + e.data);
};
ws.onclose = function() {
setMsgValue(‘\n‘ + ‘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

时间: 2024-10-29 19:06:51

java websockect的相关文章

Java EE HTML5 WebSocket 示例

http://www.oschina.net/translate/java-ee-html5-websocket-example?cmp HTML5给Web浏览器带来了全双工TCP连接websocket标准服务器的能力. 换句话说,浏览器能够与服务器建立连接,通过已建立的通信信道来发送和接收数据而不需要由HTTP协议引入额外其他的开销来实现. 在本教程中我们将在Java EE环境下实现一个简单的websockect服务器端来和客户端进行数据交互. 本教程需要以下环境: Ubuntu 12.04

Java多线程学习(吐血超详细总结)

林炳文Evankaka原创作品.转载请注明出处http://blog.csdn.net/evankaka 目录(?)[-] 一扩展javalangThread类 二实现javalangRunnable接口 三Thread和Runnable的区别 四线程状态转换 五线程调度 六常用函数说明 使用方式 为什么要用join方法 七常见线程名词解释 八线程同步 九线程数据传递 本文主要讲了java中多线程的使用方法.线程同步.线程数据传递.线程状态及相应的一些线程函数用法.概述等. 首先讲一下进程和线程

Java TM 已被阻止,因为它已过时需要更新的解决方法

公司的堡垒机需要通过浏览器登陆,且该堡垒机的网站需要Java的支持,最近通过浏览器登陆之后总是提示"java TM 已被阻止,因为它已过时需要更新的解决方法"导致登陆之后不能操作, 但是操作系统中确实已经安装了比较新的JDK,安装的JDK版本是jdk-7u67-windows-i586,因为太烦人,所以决定搞清楚报错的原因,一劳永逸,彻底解决这个问题 准备工作:安装JDK,安装版本jdk-7u67-windows-i586.exe,因为机器的Eclipse还依赖64位的JDK,所以另安

Java四种线程池newCachedThreadPool,newFixedThreadPool,newScheduledThreadPool,newSingleThreadExecutor

介绍new Thread的弊端及Java四种线程池的使用,对Android同样适用.本文是基础篇,后面会分享下线程池一些高级功能. 1.new Thread的弊端 执行一个异步任务你还只是如下new Thread吗? Java new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub } }).start(); 1 2 3 4 5 6 7 new Thread(new

由@NotNull 注解引出的关于Java空指针的控制(转)

Java 小技巧和在java应用避免NullPonintException的最佳方法 在java应用程序中,一个NullPonintException(空指针异常)是最好解决(问题)的方法.同时,空指针也是写健壮的顺畅运行的代码的关键.“预防好过治疗”这句话也同样适用于令人不爽的NullPonintException.通过应用防御性的编码技术和在遵守多个部分之间的约定,你可以再很大程度上避免NullPointException.下面的这些java小技巧可以最小化像!=null这种检查的代码.作为

Java注解(2)-注解处理器(运行时|RetentionPolicy.RUNTIME)

如果没有用来读取注解的工具,那注解将基本没有任何作用,它也不会比注释更有用.读取注解的工具叫作注解处理器.Java提供了两种方式来处理注解:第一种是利用运行时反射机制:另一种是使用Java提供的API来处理编译期的注解. 反射机制方式的注解处理器 仅当定义的注解的@Retention为RUNTIME时,才能够通过运行时的反射机制来处理注解.下面结合例子来说明这种方式的处理方法. Java中的反射API(如java.lang.Class.java.lang.reflect.Field等)都实现了接

jvm系列(一):java类的加载机制

java类的加载机制 原文:http://www.cnblogs.com/ityouknow/p/5603287.html 1.什么是类的加载 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装类在方法区内的数据结构.类的加载的最终产品是位于堆区中的Class对象,Class对象封装了类在方法区内的数据结构,并且向Java程序员提供了访问方法区内的数据结构的接口. 类加载器并不需要等到某个

Java注解(1)-注解基础

注解(Annotation)是在JAVA5中开始引入的,它为在代码中添加信息提供了一种新的方式.注解在一定程度上把元数据与源代码文件结合在一起,正如许多成熟的框架(Spring)所做的那样.那么,注解到底可以做什么呢? 1.注解的作用. 提供用来完整地描述程序所需要的信息,如编译期校验程序信息. 生成描述符文件,或生成新类的定义. 减轻编写"样板"代码(配置文件)的负担,可以使用注解自动生成. 更加干净易读的代码. 编译期类型检查. 2.Java提供的注解 Java5内置了一些原生的注

异常笔记--java编程思想

开一个新的系列,主要记一些琐碎的重要的知识点,把书读薄才是目的...特点: 代码少,概念多... 1. 基本概念 异常是在当前环境下无法获得必要的信息来解决这个问题,所以就需要从当前环境跳出,就是抛出异常.抛出异常后发生的几件事: 1.在堆上创建异常对象. 2.当前的执行路径中止                                          3. 当前环境抛出异常对象的引用.                                         4. 异常处理机制接