简介
WebSocket 是一种常见的用于在 Web 服务器和 Android 客户端之间进行实时通信的协议。它提供了全双工通信通道,允许服务器主动向客户端推送消息,而无需客户端频繁轮询服务器。
注意事项:
- 安全性:在生产环境中,建议使用 wss(WebSocket Secure)而不是 ws,以确保数据传输的安全性。
- 重连机制:在实际应用中,网络状况可能会导致 WebSocket 连接断开,因此需要实现重连守护机制。
- 心跳机制:为了检测连接的有效性,可以实现心跳机制,定期发送心跳包。
服务端
在使用 Spring Boot 构建 Java WebSocket 服务器时,可以利用 Spring Boot 的 WebSocket 支持来实现。以下是具体步骤:
1. 添加依赖
在你的 pom.xml
文件中添加 WebSocket 依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
2. 配置 WebSocket
创建一个配置类,来注册 WebSocket 端点和处理器:
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(new MyWebSocketHandler(), "/websocket")
.setAllowedOrigins("*");
}
}
3. 创建 WebSocket 处理器
创建一个类来处理 WebSocket 消息:
@Service
public class MyWebSocketHandler extends TextWebSocketHandler {
private static List<WebSocketSession> sessions = new ArrayList<>();
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
System.out.println("add: session");
sessions.add(session);
session.sendMessage(new TextMessage("Connection established"));
}
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
System.out.println("Received message: " + message.getPayload());
for (WebSocketSession s : sessions) {
if (s.isOpen()) {
s.sendMessage(message);
}
}
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
System.out.println("remove: session");
sessions.remove(session);
}
public void broadcast(String message) throws IOException {
for (WebSocketSession session : sessions) {
if (session.isOpen()) {
session.sendMessage(new TextMessage(message));
}
}
}
}
4. 在需要时推送消息
你可以在 Spring Boot 应用中的任何地方调用 MyWebSocketHandler
的 broadcast
方法来向所有连接的客户端推送消息。例如,在一个 REST 控制器中:
@RestController
@Api(tags = "WebSocketController")
@RequestMapping("/websocket")
public class WebSocketController {
@Autowired
private MyWebSocketHandler webSocketHandler;
@GetMapping("/send")
public String sendMessage(@RequestParam String message) throws IOException {
webSocketHandler.broadcast(message);
return "Message sent!!";
}
}
客户端实现
使用okhttp
在 Android 端可以使用前面提到的 OkHttp 库实现 WebSocket 客户端。
public class WebSocketClient extends WebSocketListener {
private OkHttpClient client;
private OnMessageListener listener;
public void start() {
client = new OkHttpClient();
Request request = new Request.Builder().url("ws://192.168.222.81:20000/websocket").build();
WebSocket ws = client.newWebSocket(request, this);
// 这行代码在不需要更多HTTP请求的情况下关闭调度器的执行器服务,如果后续只用 websocket 就可以调用
client.dispatcher().executorService().shutdown();
}
@Override
public void onOpen(WebSocket webSocket, okhttp3.Response response) {
webSocket.send("Hello, it's WebSocket Client!");
}
@Override
public void onMessage(WebSocket webSocket, String text) {
System.out.println("Receiving : " + text);
new Handler(Looper.getMainLooper()).post(() -> {
if (listener != null) {
listener.onMessage(text);
}
});
}
@Override
public void onMessage(WebSocket webSocket, ByteString bytes) {
System.out.println("Receiving bytes : " + bytes.hex());
}
@Override
public void onClosing(WebSocket webSocket, int code, String reason) {
webSocket.close(1000, null);
System.out.println("WebSocket is closing : " + code + " cause: " + reason);
}
@Override
public void onFailure(WebSocket webSocket, Throwable t, okhttp3.Response response) {
t.printStackTrace();
}
public void setOnMessageListener(OnMessageListener listener) {
this.listener = listener;
}
public interface OnMessageListener {
void onMessage(String text);
}
}
在 Android 应用中调用 start()
方法来启动 WebSocket 连接:
val client = WebSocketClient()
client.start()
通过以上步骤,就可以实现 Spring Boot 服务端和 Android 客户端之间的 WebSocket 实时通信。
网络配置
在 Android 9.0(API 级别 28)及更高版本中,默认情况下,应用程序不允许进行纯文本(未加密)的 HTTP 通信。为了允许使用 WebSocket 进行未加密的 ws://
通信,需要在 Android 应用的 network_security_config.xml
文件中进行配置,并在 AndroidManifest.xml
中引用这个配置。
1. network_security_config.xml
在 res/xml/
目录下创建一个 network_security_config.xml
文件(如果 xml
目录不存在,则需要先创建它),并添加以下内容:
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">192.168.222.81</domain>
</domain-config>
</network-security-config>
这个配置文件允许与指定的 IP 地址进行纯文本通信。
2. 更新 AndroidManifest.xml
在你的 AndroidManifest.xml
文件中的 <application>
标签内添加对 network_security_config.xml
的引用:
<application
android:networkSecurityConfig="@xml/network_security_config"
... >
...
</application>