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

原创 2016年01月17日 14:15:46

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都能够收到彼此发送的消息。




版权声明:本文为博主原创文章,未经博主允许不得转载。

Java Websocket实例【服务端与客户端实现全双工通讯】

Java Websocket实例【服务端与客户端实现全双工通讯】 现很多网站为了实现即时通讯,所用的技术都是轮询(polling)。轮询是在特定的的时间间隔(如每1秒),由浏览器...
  • u013490585
  • u013490585
  • 2017年07月27日 10:14
  • 1726

搭建WebSocket服务器与客户端

市场上有几款比较好的开源库供使用,比如PyWebSocket,WebSocket-Node, LibWebSockets等,这些库文件已经实现了WebSocket数据包的封装和解析,我们可以调用这些接...
  • fengshiguang2012
  • fengshiguang2012
  • 2017年02月17日 15:22
  • 5842

WebSocket浏览器与服务器之间的对话(用于消息推送)

 1.如果加入数据库后,A发消息时客户B未上线,服务端将会把消息存在数据库中,等客户B上线后,在将消息取出发送给客户B 2.服务端也可发送消息到任意客户端上。 程序的运行效果截图如下(在ch...
  • qq_30815929
  • qq_30815929
  • 2015年11月24日 15:47
  • 10538

建立Flex客户端与J2EE服务端于同一(BlazeDS服务)工程

  • 2012年04月03日 02:47
  • 1.4MB
  • 下载

WebSocket客户端和服务端实例源码

  • 2015年08月14日 13:30
  • 4.64MB
  • 下载

WebSocket安卓客户端实现详解(三)–服务端主动通知

  • 2017年08月06日 14:20
  • 103KB
  • 下载

C#语言的websocket服务端和客户端DLL

  • 2017年11月28日 11:38
  • 1.47MB
  • 下载

websocket服务端 客户端源码

  • 2017年11月21日 16:50
  • 11KB
  • 下载

C#实现WebSocket源码(c#写的服务端html写的客户端)

  • 2017年12月21日 17:05
  • 51KB
  • 下载

J2EE技术规范(九)——JMS (JMS客户端)

上篇博客写了JMS的一些内容,后来觉得那篇博客的内容不够阐述JMS的内容,所以这篇博客就继续完善JMS。 在WebLogic Server 环境中配置JMS WebLogic Server...
  • yi_zz
  • yi_zz
  • 2012年12月16日 19:09
  • 3339
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:使用JSR365规范构建J2EE websocket服务端和客户端应用
举报原因:
原因补充:

(最多只允许输入30个字)