- 在同步模式下请求 WebSocket 服务端
java
复制代码
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.WebSocket;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
public class WebSocketSyncClientExample {
private static final String WS_SERVER_URI = "ws://echo.websocket.events"; // 替换为你的WebSocket服务端地址
private static CountDownLatch latch; // 用于同步等待事件发生
public static void main(String[] args) {
System.out.println("尝试连接 WebSocket 服务端: " + WS_SERVER_URI);
latch = new CountDownLatch(1); // 初始化计数器,等待连接建立
HttpClient httpClient = HttpClient.newHttpClient();
try {
// 构建WebSocket连接并传入自定义的监听器
// buildAsync 返回一个 CompletionStage,表示异步连接过程
CompletionStage<WebSocket> wsFuture = httpClient.newWebSocketBuilder()
.buildAsync(URI.create(WS_SERVER_URI), new CustomWebSocketListener());
// 阻塞主线程,直到WebSocket连接成功建立(或超时)
WebSocket webSocket = wsFuture.get(10, TimeUnit.SECONDS); // 最多等待10秒
System.out.println("WebSocket 连接已建立。");
// 发送一条消息
String messageToSend = "Hello WebSocket Server!";
System.out.println("发送消息: " + messageToSend);
webSocket.sendText(messageToSend, true); // true表示这是最后一部分消息
// 再次初始化latch,等待接收消息或连接关闭
latch = new CountDownLatch(1);
latch.await(15, TimeUnit.SECONDS); // 等待接收消息或超时
// 关闭连接
System.out.println("准备关闭 WebSocket 连接...");
webSocket.sendClose(WebSocket.NORMAL_CLOSURE, "客户端主动关闭").join(); // join() 阻塞直到关闭完成
System.out.println("WebSocket 连接已关闭。");
} catch (Exception e) {
System.err.println("WebSocket 连接或通信过程中发生错误: " + e.getMessage());
e.printStackTrace();
}
}
// 自定义WebSocket监听器
private static class CustomWebSocketListener implements WebSocket.Listener {
@Override
public void onOpen(WebSocket webSocket) {
System.out.println("WebSocket: 连接已打开。");
// 当连接打开时,减少latch计数,解除主线程的阻塞
latch.countDown();
// 可以在这里发送初始消息
// webSocket.sendText("Client connected!", true);
}
@Override
public CompletionStage<?> onText(WebSocket webSocket, CharSequence data, boolean last) {
System.out.println("WebSocket: 收到文本消息: " + data);
// 收到消息后,减少latch计数,解除主线程的阻塞
latch.countDown();
return WebSocket.Listener.super.onText(webSocket, data, last);
}
@Override
public CompletionStage<?> onBinary(WebSocket webSocket, java.nio.ByteBuffer data, boolean last) {
System.out.println("WebSocket: 收到二进制消息 (长度: " + data.remaining() + ")");
latch.countDown();
return WebSocket.Listener.super.onBinary(webSocket, data, last);
}
@Override
public CompletionStage<?> onPing(WebSocket webSocket, java.nio.ByteBuffer message) {
System.out.println("WebSocket: 收到 Ping 帧。");
return WebSocket.Listener.super.onPing(webSocket, message);
}
@Override
public CompletionStage<?> onPong(WebSocket webSocket, java.nio.ByteBuffer message) {
System.out.println("WebSocket: 收到 Pong 帧。");
return WebSocket.Listener.super.onPong(webSocket, message);
}
@Override
public CompletionStage<?> onClose(WebSocket webSocket, int statusCode, String reason) {
System.out.println("WebSocket: 连接已关闭。状态码: " + statusCode + ", 原因: " + reason);
// 连接关闭时,减少latch计数,解除主线程的阻塞
latch.countDown();
return WebSocket.Listener.super.onClose(webSocket, statusCode, reason);
}
@Override
public void onError(WebSocket webSocket, Throwable error) {
System.err.println("WebSocket: 发生错误: " + error.getMessage());
error.printStackTrace();
// 发生错误时,减少latch计数,解除主线程的阻塞
latch.countDown();
}
}
}
- 在这个异步版本中,主线程不会阻塞等待连接建立或消息收发。所有的操作都通过
CompletionStage 和 WebSocket.Listener 回调来处理。为了确保主线程不会在异步操作完成前退出,我们仍然会使用一个 CountDownLatch 来等待整个通信过程结束。
java
复制代码
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.WebSocket;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
public class WebSocketAsyncClientExample {
private static final String WS_SERVER_URI = "ws://echo.websocket.events"; // 替换为你的WebSocket服务端地址
private static final CountDownLatch appShutdownLatch = new CountDownLatch(1); // 用于控制主线程何时退出
public static void main(String[] args) {
System.out.println("尝试异步连接 WebSocket 服务端: " + WS_SERVER_URI);
HttpClient httpClient = HttpClient.newHttpClient();
// 异步构建WebSocket连接
CompletableFuture<WebSocket> webSocketFuture = httpClient.newWebSocketBuilder()
.buildAsync(URI.create(WS_SERVER_URI), new CustomAsyncWebSocketListener());
// 使用thenAccept处理连接成功后的逻辑
webSocketFuture.thenAccept(webSocket -> {
System.out.println("WebSocket 连接已成功建立。");
// 连接成功后,异步发送一条消息
String messageToSend = "Hello from Async Client!";
System.out.println("异步发送消息: " + messageToSend);
webSocket.sendText(messageToSend, true)
.thenRun(() -> System.out.println("消息发送完成。"))
.exceptionally(ex -> {
System.err.println("消息发送失败: " + ex.getMessage());
return null;
});
// 可以在这里设置一个定时器,在一段时间后关闭连接
// 或者等待接收到特定消息后关闭
// 为了示例,我们让它运行一段时间,然后通过监听器的onClose或onError触发appShutdownLatch
}).exceptionally(ex -> {
System.err.println("WebSocket 连接失败: " + ex.getMessage());
appShutdownLatch.countDown(); // 连接失败,立即释放主线程
return null;
});
System.out.println("主线程继续执行,等待WebSocket通信完成...");
try {
// 阻塞主线程,直到appShutdownLatch计数为0(即WebSocket通信结束或出错)
appShutdownLatch.await(30, TimeUnit.SECONDS); // 最多等待30秒
System.out.println("主线程检测到WebSocket通信结束或超时,程序退出。");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.err.println("主线程等待被中断: " + e.getMessage());
}
}
// 自定义异步WebSocket监听器
private static class CustomAsyncWebSocketListener implements WebSocket.Listener {
private WebSocket currentWebSocket; // 保存WebSocket实例,以便在其他方法中使用
@Override
public void onOpen(WebSocket webSocket) {
this.currentWebSocket = webSocket;
System.out.println("Listener: WebSocket 连接已打开。");
// 在这里可以发送欢迎消息等
}
@Override
public CompletionStage<?> onText(WebSocket webSocket, CharSequence data, boolean last) {
System.out.println("Listener: 收到文本消息: " + data);
// 收到消息后,可以根据业务逻辑决定是否关闭连接
// 例如,如果收到特定消息,就关闭
if (data.toString().contains("close")) {
System.out.println("Listener: 收到 'close' 消息,准备关闭连接。");
return webSocket.sendClose(WebSocket.NORMAL_CLOSURE, "收到关闭指令")
.thenRun(() -> System.out.println("Listener: 连接关闭指令已发送。"));
}
return WebSocket.Listener.super.onText(webSocket, data, last);
}
@Override
public CompletionStage<?> onBinary(WebSocket webSocket, java.nio.ByteBuffer data, boolean last) {
System.out.println("Listener: 收到二进制消息 (长度: " + data.remaining() + ")");
return WebSocket.Listener.super.onBinary(webSocket, data, last);
}
@Override
public CompletionStage<?> onPing(WebSocket webSocket, java.nio.ByteBuffer message) {
System.out.println("Listener: 收到 Ping 帧。");
return WebSocket.Listener.super.onPing(webSocket, message);
}
@Override
public CompletionStage<?> onPong(WebSocket webSocket, java.nio.ByteBuffer message) {
System.out.println("Listener: 收到 Pong 帧。");
return WebSocket.Listener.super.onPong(webSocket, message);
}
@Override
public CompletionStage<?> onClose(WebSocket webSocket, int statusCode, String reason) {
System.out.println("Listener: WebSocket 连接已关闭。状态码: " + statusCode + ", 原因: " + reason);
appShutdownLatch.countDown(); // 连接关闭,释放主线程
return WebSocket.Listener.super.onClose(webSocket, statusCode, reason);
}
@Override
public void onError(WebSocket webSocket, Throwable error) {
System.err.println("Listener: WebSocket 发生错误: " + error.getMessage());
error.printStackTrace();
appShutdownLatch.countDown(); // 发生错误,释放主线程
}
}
}