我正在尝试使用 spring 和 java/web 应用程序实现 websockets,以允许它与使用 qt (以及其中的 websockets 库)用 c++ 编写的应用程序交换消息。
我在我的 java/spring 应用程序中具有以下配置:
WebScoketConfig.java
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(new SocketHandler(), "/name");
}
}
SocketHandler.java
@Component
public class SocketHandler extends TextWebSocketHandler {
List<WebSocketSession> sessions = new CopyOnWriteArrayList<>();
@Override
public void handleTextMessage(WebSocketSession session, TextMessage message) throws InterruptedException, IOException {
Map<String, String> value = new Gson().fromJson(message.getPayload(), Map.class);
session.sendMessage(new TextMessage("Hello " + value.get("name") + " !"));
}
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
sessions.add(session);
}
}
我创建了一个非常简单的 qt-creator 项目,其中包含一个 main
函数和一个类 MainWindow
,以及两个对象:一个 lineEdit
,用户在其中键入一条要发送到服务器的消息,以及一个pushButton
,以继续发送数据。
在我的 MainWindow
类中,我实现了这个槽来处理数据交换:
void MainWindow::on_pushButton_clicked()
{
QString message = this->ui->lineEdit->text();
QWebSocket m_webSocket;
m_webSocket.open(QUrl(QStringLiteral("ws://localhost:8080/name")));
m_webSocket.sendTextMessage("Hello " + message + " !");
m_webSocket.close();
}
但是当我执行这两个应用程序并尝试为 java/web 应用程序发送消息时,什么也没有发生。我很确定我犯的错误是在 c++/qt 方面,因为在 java/spring 方面我有一个 html/javascript 代码,它允许我测试消息交换,并且工作正常。
谁能告诉我我在这里做错了什么?
更新:最小的可重现示例 - java/spring
可以使用start.spring.io生成项目,仅使用spring-websocket作为依赖。除了我上面已经添加的 2 个文件之外,该项目还将具有:
resources/static/index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Hello WebSocket</title>
<link href="/main.css" rel="stylesheet">
</head>
<body>
<table>
<tr>
<td>
<button id="connect" type="button" onclick="connect();">Connect</button>
<button id="disconnect" type="button" disabled="disabled" onclick="disconnect();">Disconnect</button>
</td>
<td>
<label for="name">What is your name?</label>
<input type="text" id="name" placeholder="Your name here...">
<button id="send" type="button" onclick="send();">Send</button>
</td>
</tr>
</table>
<hr>
<table id="conversation" border="2">
<thead>
<tr>
<th>Greetings</th>
</tr>
</thead>
<tbody id="greetings">
</tbody>
</table>
<script src="/app.js"></script>
</body>
</html>
资源/app.js
var ws;
function connect() {
ws = new WebSocket('ws://localhost:8080/name');
ws.onmessage = function(text) {
var tr = document.createElement("tr");
var td = document.createElement("td");
td.innerText = text.data;
tr.appendChild(td);
document.querySelector("#greetings").appendChild(tr);
}
document.querySelector("#connect").setAttribute("disabled", "disabled");
document.querySelector("#disconnect").removeAttribute("disabled");
document.querySelector("#conversation").style.display = 'block';
document.querySelector("#greetings").innerHTML = "";
}
function disconnect() {
if (ws != null)
ws.close();
document.querySelector("#connect").removeAttribute("disabled");
document.querySelector("#disconnect").setAttribute("disabled", "disabled");
document.querySelector("#conversation").style.display = 'none';
document.querySelector("#greetings").innerHTML = "";
}
function send() {
var name = document.querySelector("#name");
var data = JSON.stringify({'name': name.value});
ws.send(data);
}
使用mvn package
构建后,只需使用java -jar target/app.jar
运行。
更新:最小可重现示例 - c++/qt
项目是使用 qt-creator 创建的,类型为 qt-widget。它将创建一个包含 5 个文件的项目:websocket.pro
、mainwindow.ui
、mainwindow.h
、mainwindow.cpp
和 main.cpp
。
打开mainwindow.ui
并从工具栏中添加lineEdit
和pushButton
。右键单击按钮并选择Go to slot
,然后选择clicked()
。添加上面的代码。
更新2
void MainWindow::on_pushButton_clicked()
{
QString message = ui->lineEdit->text();
connect(&m_webSocket, &QWebSocket::connected, [this, message](){
QJsonObject object
{
{"name", message}
};
QJsonDocument d(object);
m_webSocket.sendTextMessage(d.toJson().toStdString().c_str());
m_webSocket.close();
});
m_webSocket.open(QUrl(QStringLiteral("ws://localhost:8080/name")));
}
最佳答案
问题是您在未验证连接是否成功的情况下尝试发送文本。解决方案是使用连接信号,此外还按照注释中的建议使 m_webSocket 成为该类的成员:
*.h
private:
Ui::MainWindow *ui;
QWebSocket m_webSocket;
*.cpp
void MainWindow::on_pushButton_clicked()
{
QString message = ui->lineEdit->text();
connect(&m_webSocket, &QWebSocket::connected, [this, message](){
m_webSocket.sendTextMessage("Hello " + message + " !");
m_webSocket.close();
});
m_webSocket.open(QUrl(QStringLiteral("ws://localhost:8080/name")));
}
更新:
在您的项目中我注意到以下错误:
由于某种原因,当我使用 Google Chrome 进行测试时,我无法连接,因此我添加了
registry.addHandler(new SocketHandler(), "/name").setAllowedOrigins("*");
到配置。变量“session”仅处理向套接字发送数据,如果您想将该信息发送到所有套接字(js 和 qt),那么您必须迭代。
当 session 断开连接时,请勿将其从“ session ”中删除,否则可能会导致错误。您必须在
afterConnectionClosed
方法中删除 session 。在您的代码中,您正在调用连接到与连接信号关联的插槽中的服务器,这是愚蠢的,因为该插槽是在连接后调用的,为此您应该首先调用 open 方法。无论如何,打开连接、等待连接建立、发送消息并关闭连接都不是一个好主意,最好在发送消息之前打开连接并在必要时关闭连接(例如关闭 GUI 或用户想要像在 js 中那样关闭它,因为信息的发送不是即时的而是异步的)。
完整代码为here .
关于java - java/spring 和 c++/qt 应用程序之间使用 websockets 进行通信,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61127606/