websocket实践

服务端以jetty8做容器,参考

http://wiki.eclipse.org/Jetty/Feature/WebSockets

http://dev.w3.org/html5/websockets/

如果用maven需要jetty-webapp和jetty-websocket依赖:

<dependency>
			<groupId>org.eclipse.jetty</groupId>
			<artifactId>jetty-webapp</artifactId>
			<version>8.1.2.v20120308</version>
		</dependency>
		<dependency>
        	<groupId>org.eclipse.jetty</groupId>
        	<artifactId>jetty-websocket</artifactId>
        	<version>8.1.2.v20120308</version>
    	</dependency>

注意jetty8实现的是servlet-api-3.0,所以要排除对servlet-api-2.5的依赖。否则会报Java SecurityException : signer information does not match 的错误。

在此jetty版本下webservletsocket代码为:

package kzg.html5.websocket;

import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import javax.servlet.http.HttpServletRequest;

import net.sf.json.JSONObject;

import org.eclipse.jetty.websocket.WebSocket;
import org.eclipse.jetty.websocket.WebSocketServlet;

@SuppressWarnings("serial")
public class DebugLogWsSocket extends WebSocketServlet
{

	@Override
	public WebSocket doWebSocketConnect(HttpServletRequest request, String protocol)
	{
		LogService.debug("websocket request protocol:" + protocol);

		return new TestSocket();
	}

	private static class TestSocket implements WebSocket.OnTextMessage
	{
		ExecutorService service;
		Connection conn;

		private boolean clientStop = false;

		@Override
		public void onClose(int code, String message)
		{
			LogService.debug("websocket close:" + code + ":" + message);
			setClientStop(true);
			if (null != service)
			{
				service.shutdown();
			}
		}

		private void sendData(Object data)
		{
			JSONObject respj = new JSONObject();
			respj.put("status", "ok");
			respj.put("data", data);
			if (null == conn || !conn.isOpen())
			{
				return;
			}
			try
			{
				conn.sendMessage(respj.toString());
			}
			catch (IOException e)
			{
				LogService.error("websocket send data error:", e);
			}
		}

		@Override
		public void onOpen(final Connection aconn)
		{
			this.conn = aconn;
			LogService.debug("websocket open:" + conn.getProtocol());

			service = Executors.newSingleThreadExecutor();
			service.execute(new Runnable() {

				@Override
				public void run()
				{

					while (!isClientStop())
					{
						sendData(System.currentTimeMillis());
						try
						{
							TimeUnit.SECONDS.sleep(1);
						}
						catch (InterruptedException e)
						{
							return;
						}
					}
				}
			});
		}

		@Override
		public void onMessage(final String message)
		{
			LogService.debug("websocket incomming message:" + message);
			sendData("server got message:" + message);
		}

		public synchronized boolean isClientStop()
		{
			return clientStop;
		}

		public synchronized void setClientStop(boolean clientStop)
		{
			this.clientStop = clientStop;
		}

	}

}


大家可能看到与之前的api有些变化,最新的api用法还是要看http://wiki.eclipse.org/Jetty/Feature/WebSockets 这里。

web.xml配置:

<!DOCTYPE web-app PUBLIC
	 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
	 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
	
  <servlet>
    <servlet-name>DebugLogServlet</servlet-name>
    <servlet-class>kzg.html5.websocket.DebugLogWsSocket</servlet-class>
  </servlet>

  <servlet-mapping>
    <servlet-name>DebugLogServlet</servlet-name>
    <url-pattern>/dlog/</url-pattern>
  </servlet-mapping>	
</web-app>

可看到与之前的servlet没什么区别。

客户端部分代码:

function strat_socket() {
		var error_count = 0;
		var url = 'ws://' + document.location.host + '/dlog/';
		ws = new WebSocket(url);
		ws.onopen = function() {
			log('ws open');
		};
		ws.onerror = function(e) {
			log('ws error');
		};
		ws.onclose = function() {
			log('ws close');
		};
		ws.onmessage = function(msg) {
			log('ws message:');
			log(msg);
			var d = $.parseJSON(msg.data);
			if (!d || 'error' == d.status) {
				error_count++;

				if (error_count > 3) {
					alert('poll error many times.');

					return;
				}

				return;
			}

			process_log(d.data,true);
		};
	}

开始我还对ws://这个url有些疑惑,实践中没有针对它的特殊配置。浏览器和web容器自会处理。

下面是我从firebug中查看到的onmessage事件中msg对象值:

data
	"{"status":"ok","data":1334634452781}"
	
defaultPrevented
	false
	
lastEventId
	""
	
origin
	"ws://localhost:20090"
	
source
	null
	
initMessageEvent
	initMessageEvent()
	
stopImmediatePropagation
	stopImmediatePropagation()
	
bubbles
	false
	
cancelable
	false
	
constructor
	MessageEvent {}
	
currentTarget
	WebSocket { url="ws://localhost:20090/dlog/", readyState=3, bufferedAmount=0, more...}
	
eventPhase
	2
	
explicitOriginalTarget
	WebSocket { url="ws://localhost:20090/dlog/", readyState=3, bufferedAmount=0, more...}
	
isTrusted
	true
	
originalTarget
	WebSocket { url="ws://localhost:20090/dlog/", readyState=3, bufferedAmount=0, more...}
	
target
	WebSocket { url="ws://localhost:20090/dlog/", readyState=3, bufferedAmount=0, more...}
	
timeStamp
	1334634452921000
	
type
	"message"

客户端关闭:

//1000 or 3000-4999
ws.close(3001,'my close');

依据文档如果code 不是1000或是3000-4999则会抛异常。第二个参数不能超过123字节,具体见http://dev.w3.org/html5/websockets/#dom-websocket-close

当然还有客户端发送:

ws.send('hello');

测试在chrome18和FF11,Safari5.0.5都运行正常。

说到Safari,又话来长,因为我发现tomcat7作为服务端的话就不能与Safari的websocket建立连接。

起因是这样的,我使用tomcat7建立的websocket工程在FF和chrome下都运行的好好的,但是在safari浏览器下建立不了连接,一开始就是个onclose事件。

目前最稳定的还是jetty8,见http://jfarcand.wordpress.com/2012/05/16/safaris-websocket-implementation-and-java-problematic/

 

WebServersVersionSpecificationSafari Stability
Tomcat7.0.27 and uphybi-13 and upNOT SUPPORTED
Jetty7.0 to 7.4.5Up to hybi-12UNSTABLE: Server suffer High CPU when Safari’s WebSocket connection get closed.
Jetty7.5.x to 7.6.2Up to hybi-12UNSTABLE: Server suffer High CPU when Safari’s WebSocket connection get closed.
Jetty7.5.x to 7.6.2Up to hybi-13UNSTABLE: Server suffer High CPU when Safari’s WebSocket connection get closed.
Jetty8.x to 8.1.2Up to hybi-13UNSTABLE: Server suffer High CPU when Safari’s WebSocket connection get closed.
Jetty7.6.3All hybi versionSTABLE
Jetty8.1.3All hybi versionSTABLE
GlassFish3.1.1All hybi versionUNSTABLE: Suffer many API bugs
GlassFish3.1.2All hybi versionSTABLE
NettoSphere (based on Netty Framework)1.xAll hybi versionSTABLE

Total views.

© 2013 - 2024. All rights reserved.

Powered by Hydejack v6.6.1