aty

虽有嘉肴,弗食,不知其旨也;虽有至道,弗学,不知其善也。是故学然后知不足,教然后知困。知不足,然后能自反也;知困,然后能自强也。...

使用JSR365规范构建J2EE websocket服务端和客户端应用

JSR365是java制定的websocket编程规范,属于Java EE 7的一部分。下面这段描述摘录自官网对JSR365的说明:

JSR 356, Java API for WebSocket, specifies the API that Java developers can use when they want to integrate WebSockets into their applications—both on the server side as well as on the Java client side. Every implementation of the WebSocket protocol that claims to be compliant with JSR 356 must implement this API. As a consequence, developers can write their WebSocket-based applications independent of the underlying WebSocket implementation. This is a huge benefit, because it prevents a vendor-lock and allows for more choices and freedom of libraries and application servers.

JSR 356 is a part of the upcoming Java EE 7 standard; hence, all Java EE 7–compliant application servers will have an implementation of the WebSocket protocol that adheres to the JSR 356 standard. Once they are established, WebSocket client and server peers are symmetrical. The difference between a client API and a server API is, therefore, minimal. JSR 356 defines a Java client API as well, which is a subset of the full API required in Java EE 7.

websocket和socket一样,既有客户端编程,也有服务端编程,JSR365制定了websocket客户端和服务端编程常用的API。我的另一篇文章介绍了使用Tomcat自己的websocket也能够实现web推送,但是那篇文章中的代码只能运行在tomcat容器。我们使用JSR365编写的websocket程序,能够在所有web容器中运行,只要这个容器实现了J2EE 7规范。我使用的是Tomcat7.0.62,这个版本的Tomcat实现了J2EE 7规范。


为了使用JSR365,我们需要在pom.xml加入编译期的依赖:

<dependency>
	<groupId>javax.websocket</groupId>
	<artifactId>javax.websocket-api</artifactId>
	<version>1.1</version>
	<scope>provided</scope>
</dependency>


Tomcat等web容器自带的有JSR365的API,这个很JSP/Servlet是一样的,我们的web项目只是编译期需要这个依赖,运行的时候并不需要。


JSR365编程可以参考这篇文章,下面我们以interface-driven风格为例,编写一个websocket服务端程序。

package net.aty.javawebsocket;

import javax.websocket.CloseReason;
import javax.websocket.Endpoint;
import javax.websocket.EndpointConfig;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

@ServerEndpoint("/websocket")
public class MyOwnEndpoint extends Endpoint {

	@Override
	public void onOpen(Session session, EndpointConfig config) {
		System.out.println("websocket connection is opened.");
		session.addMessageHandler(new MyMessageListener(session));
	}

	@Override
	public void onClose(Session session, CloseReason closeReason) {
		System.out.println("websocket connection is closed." + closeReason);
	}

	@Override
	public void onError(Session session, Throwable thr) {
		System.out.println("websocket connection is error." + thr);
	}
}
package net.aty.javawebsocket;

import java.io.IOException;
import java.util.Set;

import javax.websocket.MessageHandler;
import javax.websocket.Session;

public class MyMessageListener implements MessageHandler.Whole<String> {

	private Session session;

	public MyMessageListener(Session session) {
		this.session = session;
	}

	@Override
	public void onMessage(String message) {

		System.out.println("i receive a message=" + message);

		Set<Session> openSessions = session.getOpenSessions();

		for (Session each : openSessions) {
			try {
				each.getBasicRemote().sendText(message);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

	}
}


Endpoint负责建立websocket连接,MessageHandler负责处理通过websocket发送的消息。上面代码我们在Endpoint打开连接的时候,注册MessageHandler;在MessageHandler中,将接收到的消息广播发送给所有websocket客户端。


现在我们看下websocket客户端编程,我们使用Chrome浏览器,chrome支持HTML5 Websocket规范。

<script>
	var socket = new WebSocket('ws://localhost:8080/JavaWebsocket/websocket');

	socket.onopen = function(event) {
		console.log("onopen:" + event.data);
	};

	socket.onmessage = function(event) {
		console.log("onmessage:" + event.data);
	};

	socket.onclose = function(event) {
		console.log("onclose:" + event.data);
	};

	socket.onerror = function(event) {
		console.log("onerror:" + event.data);
	};
	
	function send()
	{
		socket.send(document.getElementById("content").value);
	}
</script>

<body>

	<textarea rows="5" cols="100" id="content"></textarea>

	<input type="button" value="send" onclick="send()" />
</body>


启动tomcat后,通过chrome浏览器访问http://localhost:8080/JavaWebsocket/index.html,打开2个客户端,可以看到2个客户端都能够收到彼此发送的消息。





上面我们使用JSR365编写了服务端websocket,并放在了JSR365的实现Tomcat7中运行;客户端编程使用的是Chrome浏览器。下面我们用JSR365客户端编程:

package net.aty.javawebsocket.client;

import javax.websocket.ClientEndpoint;
import javax.websocket.CloseReason;
import javax.websocket.Endpoint;
import javax.websocket.EndpointConfig;
import javax.websocket.Session;

@ClientEndpoint
public class MyClientEndpoint extends Endpoint {

	@Override
	public void onOpen(Session session, EndpointConfig config) {
		System.out.println("websocket connection is opened.");
		session.addMessageHandler(new MyClientMessageListener());
	}

	@Override
	public void onClose(Session session, CloseReason closeReason) {
		System.out.println("websocket connection is closed." + closeReason);
	}

	@Override
	public void onError(Session session, Throwable thr) {
		System.out.println("websocket connection is error." + thr);
	}

}
package net.aty.javawebsocket.client;

import javax.websocket.MessageHandler;

public class MyClientMessageListener implements MessageHandler.Whole<String> {

	@Override
	public void onMessage(String message) {
		System.out.println("i receive a message=" + message);
	}
}


可以看到这和websocket服务端编程很像,差别在于MyClientEndpoint只负责建立与websocket服务端的连接:
The main difference between @ClientEndpoint and a ServerEndpoint is that the ClientEndpoint does not accept a path value element, because it is not listening to incoming requests.

服务端的MessageHandler接收到消息后需要将消息广播发送给所有客户端,而客户端的MessageHandler只是处理自己的消息即可。


现在websocket编程结束了,同服务端编程一样,JSR365仅仅是一个规范。服务端websocket我们使用的是实现者Tomcat,现在我们需要挑选websocket client的实现者。在maven仓库搜索websocket,可以找到很多的实现者。



我选用的客户端实现者是jetty,在pom.xml中加入:

<dependency>
	<groupId>org.eclipse.jetty.websocket</groupId>
	<artifactId>javax-websocket-client-impl</artifactId>
	<version>9.2.14.v20151106</version>
</dependency>


下面是我们使用jetty实现的,websocket客户端的测试代码:

package net.aty.javawebsocket.client;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URI;

import javax.websocket.ContainerProvider;
import javax.websocket.Session;
import javax.websocket.WebSocketContainer;

public class TestUseJetty {

	public static void main(String[] args) throws Exception {
		WebSocketContainer container = ContainerProvider
				.getWebSocketContainer();

		Session session = container.connectToServer(MyClientEndpoint.class,
				new URI("ws://localhost:8080/JavaWebsocket/websocket"));

		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

		while (true) {
			String input = br.readLine();

			if (input.equals("exit")) {
				break;
			}
			session.getBasicRemote().sendText(input);
		}
	}
}


运行效果如下:可以看到java main和chrome都能够收到彼此发送的消息。




阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/aitangyong/article/details/50531622
个人分类: 推送 HTML5
上一篇使用maven构建XML风格的Spring4 MVC应用
下一篇javascript捕获浏览器窗口关闭事件
想对作者说点什么? 我来说一句

WebSocket客户端服务端实例源码

2015年08月14日 4.64MB 下载

没有更多推荐了,返回首页

关闭
关闭