本文整理了3
种 Java 语言实现 WebSocket 客户端的方式,分别是使用Javax.websocket-api
、Java-WebSocket
和Jakarta WebSocket
,三种方法达到的效果一致,都能与 Websocket 服务端完成良好通信。
注意:要进行 WebSocket 通信,必须首先启动 WebSocket 服务端,再启动客户端。
方法1:使用 javax.websocket-api
javax.websocket-api
提供了 websocket 通信的规范,定义了一些抽象类,只有部分实现,另外一部分需要手动实现或者通过引入其他依赖来解决,比如javax.websocket.ContainerProvider
,所以不能直接用。 否则会报错:
java.lang.RuntimeException: Could not find an implementation class.
at javax.websocket.ContainerProvider.getWebSocketContainer(ContainerProvider.java:73)
at com.awaimai.Client1.<init>(Client1.java:13)
at com.awaimai.Client1Test.sendMessage(Client1Test.java:11)
...
- 下面的
3
个依赖都包含了实现javax.websocket-api
抽象方法的类,引入其中一个就能使用 Websocket 客户端了。
<!-- 具体实现类是:org.eclipse.jetty.websocket.jsr356.JettyClientContainerProvider -->
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>javax-websocket-client-impl</artifactId>
<version>9.4.43.v20210629</version>
</dependency>
<!-- 具体实现类是:org.apache.tomcat.websocket.WsContainerProvider -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
<version>2.5.4</version>
</dependency>
<!-- 具体实现类是:org.apache.tomcat.websocket.WsContainerProvider,其实上面的 spring-boot-starter-websocket 用的就是这个依赖,所以我们其实可以直接用,避免引入其他不必要的组建。但是!!注意!!,这个依赖10.xx版本之后已经不包含 Websocket 组件,最多可用到 9.0.52 版本 -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-websocket</artifactId>
<version>9.0.52</version>
</dependency>
- 定义客户端代码如下,我们命名它为
Client1
。该类的作用是:当它从Websocket server接收到信息时,在终端中直接打印出来,如果调用sendMessage()
方法,则会向 server 发送指定的文本消息。
package com.awaimai;
import javax.websocket.*;
import java.io.IOException;
import java.net.URI;
@ClientEndpoint
public class Client1 {
private Session session;
public Client1(URI uri) {
try {
session = ContainerProvider.getWebSocketContainer().connectToServer(this, uri);
} catch (DeploymentException | IOException e) {
e.printStackTrace();
}
}
@OnMessage
public void onMessage(String message) {
System.out.println(message);
}
public void sendMessage(String str) {
session.getAsyncRemote().sendText(str);
}
}
- 测试类,测试类的作用是:每隔
1
秒钟向服务端发送内容为Hello
的消息。
package com.awaimai;
import org.junit.jupiter.api.Test;
import java.net.URI;
import java.net.URISyntaxException;
class Client1Test {
@Test
void sendMessage() throws InterruptedException, URISyntaxException {
Client1 client1 = new Client1(new URI("ws://localhost:9999"));
while (true) {
client1.sendMessage("Hello");
Thread.sleep(1000);
}
}
}
先打开 Websocket 服务端,再运行测试类,就能看到终端不断的收到自己发到服务器,再从服务端反回来的消息了(当然,这里需要服务端要广播自己收到的信息)。
方法2:使用 Java-WebSocket
Java-WebSocket 是一套完整的实现了 Websocket Client 和 Server 的组件,使用使用也比较简单。
- 首先,添加依赖:
<dependency>
<groupId>org.java-websocket</groupId>
<artifactId>Java-WebSocket</artifactId>
<version>1.5.2</version>
</dependency>
- 编写实现类
Client2
:
package com.awaimai;
import java.net.URI;
import java.net.URISyntaxException;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;
public class Client2 extends WebSocketClient {
public Client2(URI serverURI) {
super(serverURI);
}
@Override
public void onOpen(ServerHandshake serverHandshake) {
}
@Override
public void onMessage(String message) {
System.out.println(message);
}
@Override
public void onClose(int i, String s, boolean b) {
}
@Override
public void onError(Exception e) {
}
}
- 测试类,功能和上面的例子一样,每隔
1
秒钟向服务端发送一条消息。
package com.awaimai;
import org.junit.jupiter.api.Test;
import java.net.URI;
import java.net.URISyntaxException;
class Client2Test {
@Test
void sendMessage() throws InterruptedException, URISyntaxException {
Client2 client2 = new Client2(new URI("ws://localhost:9999"));
client2.connect();
while (true) {
if (client2.isOpen()) {
client2.send("Hello");
}
Thread.sleep(1000);
}
}
}
测试方法同上,先打开 Websocket 服务端,再运行测试方法。
方法3: 使用 Jakarta WebSocket
Jakarta WebSocket 用法和 javax.websocket-api 几乎是一样的,它有一套自己的接口,还有一套实现。
- 引入接口依赖和实现依赖:
<dependency>
<groupId>jakarta.platform</groupId>
<artifactId>jakarta.jakartaee-api</artifactId>
<version>9.1.0</version>
</dependency>
<dependency>
<groupId>org.glassfish.tyrus.bundles</groupId>
<artifactId>tyrus-standalone-client</artifactId>
<version>2.0.0</version>
</dependency>
- 编写实现类
Client3
,可以对比一下 javax.websocket-api,使用方式是一样的:
package com.awaimai;
import jakarta.websocket.*;
import java.io.IOException;
import java.net.URI;
@ClientEndpoint
public class Client3 {
Session session = null;
public Client3(URI endpointURI) {
try {
session = ContainerProvider.getWebSocketContainer().connectToServer(this, endpointURI);
} catch (Exception e) {
e.printStackTrace();
}
}
@OnMessage
public void onMessage(String message) {
System.out.println(message);
}
public void sendMessage(String message) {
try {
this.session.getBasicRemote().sendText(message);
} catch (IOException e) {
e.printStackTrace();
}
}
}
- 测试类
package com.awaimai;
import org.junit.jupiter.api.Test;
import java.net.URI;
import java.net.URISyntaxException;
class Client3Test {
@Test
void sendMessage() throws URISyntaxException, InterruptedException {
Client3 client3 = new Client3(new URI("ws://localhost:9999"));
while (true) {
client3.sendMessage("Hello");
Thread.sleep(1000);
}
}
}
运行后,效果跟上面是一样的。