Java WebSocket 实践1-基于javax
webSocket 的定义
- WebSocket 是一种全双工的通信协议,基于Http之上,可以实现服务端和客户端之间建立一个长连接 ,实现服务端主动向客户端推送消息,客户端也可以主动向服务端发送消息的功能。
- 常见的使用场景就是:客户端需要高频率的向服务端发起同一个Http请求,类似于轮询的方式,这种解决方案的缺陷主要有两个方面:
- 消息不及时
- 浪费大量的带宽和服务器资源。
这种情况下,websocket就派上用场了。
webSocket 中的概念
webSocket 和单纯的Http请求最大不同,就是webSocket 是双向的通信,http是单向的,所以websocket中会存在一些基本的生命周期的概念。作为一个协议,各种不同的编程语言都有不同的实现形式,但是都是围绕这些中心的生命周期来的。
- connect : 客户端同服务端发起连接。 连接需要用到一个URL :
- URL : webSocket 的URL 以ws作为开头,中间和http一样是host和端口port,后边加上服务端定义的请i去路径。不同的是这个URL 只是用来建立连接的,建立连接之后,就是双方互相通信了。就像是两个人打电话,拨通电话时候用到的电话号码就是这儿的这个URL ,电话接通了,两个人就可以说话了。
webSocket 在java 中的实现方式。
基于javax的服务端实现:
- 导入依赖包
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
</dependencies>
这里直接使用了spring-boot-starter-websocket ,这个starter中已经包含了javax的依赖,所以不需要重复引入javax-websoket 的相关jar包了。
- 配置EndPoint ,实现服务端websocket 的主要业务。
package com.example.demo.service;
import org.springframework.stereotype.Service;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
@Service
// 定义了服务端webSoket的访问地址
@ServerEndpoint("/test/websocket")
public class MyEndPoint {
private Session session;
@OnOpen
public void myOnOpen (Session session) {
this.session = session;
System.out.println("客户端已经链接");
}
@OnMessage
public String myOnMessage (String txt) throws IOException {
System.out.println(txt);
return "服务端收到并返回";
}
@OnClose
public void myOnClose (CloseReason reason) {
System.out.println ("Closing a WebSocketConfig due to "+reason.getReasonPhrase());
}
@OnError
public void onError(Throwable throwable){
System.out.println("连接已经关闭");
}
}
注解说明:
@ServerEndpoint("/test/websocket")
用来声明这是一个服务端的websoket 。
@Open
方法名随便定义,需要一个Session 对象作为参数。 可以在这里定义一些连接后的逻辑
@Message
处理收到websocekt 消息后的业务逻辑,return 要返回的消息即可。当然也可以用open时候获取到的那个Session,手动发送。具体方法是:session.getBasicRemote().sendText();
@OnClose
: 处理连接后的事务
@OnError
: 处理连接失败的情况
- 配置webSoket : 这里向Spring中注册一个ServerEndpointExporter 对象。
package com.example.demo.service;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
到此,一个服务端的demo就ok 了。
基于javax的客户端实现
- 客户端实现,处理和服务端建立连接后的业务逻辑。
package com.example.demo.service;
import org.springframework.stereotype.Service;
import javax.websocket.*;
import java.io.IOException;
@Service
@ClientEndpoint
public class MyClientEndPoint {
private Session session;
@OnOpen
public void onOpen(Session session) {
this.session = session;
System.out.println ("WebSocketConfig opened: "+session.getId());
System.out.println("服务端链接成功");
try {
this.sendMessage();
} catch (IOException e) {
e.printStackTrace();
}
}
@OnMessage
public String onMessage(String txt) throws IOException, InterruptedException {
System.out.println(txt);
Thread.sleep(1000);
return "客户端收到";
}
@OnClose
public void onClose(CloseReason reason) {
System.out.println ("Closing a WebSocketConfig due to "+reason.getReasonPhrase());
}
@OnError
public void onError(Throwable throwable){
System.out.println("连接已经关闭");
}
public void sendMessage() throws IOException {
this.session.getBasicRemote().sendText("客户端发送");
}
}
- 配置类代码和服务端一致。
- 启动类代码:
package com.example.demo;
import com.example.demo.service.MyClientEndPoint;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import javax.websocket.ContainerProvider;
import javax.websocket.DeploymentException;
import javax.websocket.WebSocketContainer;
import java.io.IOException;
import java.net.URI;
/**
* @author duanqichao
*/
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) throws IOException, DeploymentException {
SpringApplication.run(DemoApplication.class, args);
// 这里需要使用一个WebSoketContainer 对象来和服务端的连接
WebSocketContainer container = ContainerProvider.getWebSocketContainer();
String uri = "ws://localhost:8080/test/websocket";
// 连接服务端的地址和处理类信息
container.connectToServer(MyClientEndPoint.class, URI.create(uri));
}
}
至此,一个webSoket的小demo 就可以运行了。
webSocket 如何测试:
Http 接口通常可以使用postman这类工具来模拟请求,类似的,也有一些websocket 的工具可以用来做webSocket 的客户端,推荐两个:
- 一个网址:http://websoket-test.com
- chrome 浏览器插件 : 去chrome 市场去看一下,直接搜索websoket client ,随便选一个都可以。