

一、项目概述
本文介绍如何使用 Qt 框架开发一个 TCP 服务器,实现与 VisionMaster(VM)视觉检测软件的通信。服务器负责:
- 启动 VisionMaster 进程
- 监听 TCP 端口等待 VM 客户端连接
- 发送触发信号给 VM
- 接收并处理 VM 返回的 OCR 识别结果
二、环境准备
| 工具 | 版本 | 说明 |
|---|---|---|
| Qt | 6.11.1 | C++ GUI 框架 |
| MinGW | 13.1.0 | 编译器 |
| CMake | 3.30+ | 构建工具 |
| VisionMaster | - | 视觉检测软件 |
三、项目结构
VM_test/
├── TcpServer.h # TCP服务器头文件
├── TcpServer.cpp # TCP服务器实现
├── main.cpp # 主入口文件
├── CMakeLists.txt # CMake配置
├── build.bat # 构建脚本
└── run.bat # 运行脚本
四、核心代码解析
4.1 TcpServer.h - 类定义
cpp
class TcpServer : public QTcpServer
{
Q_OBJECT
public:
bool startServer(quint16 port); // 启动服务器
bool startOcrProcess(); // 启动OCR进程
bool sendData(const QString& data); // 发送数据
bool isClientConnected() const; // 检查连接状态
signals:
void clientConnected(); // 客户端连接信号
void dataReceived(const QByteArray& data); // 数据接收信号
private slots:
void onNewConnection(); // 处理新连接
void onReadyRead(); // 处理数据接收
void onDisconnected(); // 处理断开连接
private:
QTcpSocket* m_clientSocket; // 客户端socket
QProcess* m_ocrProcess; // OCR进程
QByteArray m_receivedData; // 接收的数据
};
4.2 TcpServer.cpp - 关键实现
启动服务器:
cpp
bool TcpServer::startServer(quint16 port)
{
if (!listen(QHostAddress::Any, port)) {
qCritical() << "Server start failed:" << errorString();
return false;
}
qInfo() << "Server listening on port" << port;
return true;
}
listen() 开始在指定端口监听,QHostAddress::Any 表示监听所有网络接口。
处理新连接:
cpp
void TcpServer::onNewConnection()
{
QTcpSocket* socket = nextPendingConnection();
if (!socket) return;
if (m_clientSocket) {
socket->close();
socket->deleteLater();
return;
}
m_clientSocket = socket;
connect(m_clientSocket, &QTcpSocket::readyRead,
this, &TcpServer::onReadyRead);
connect(m_clientSocket, &QTcpSocket::disconnected,
this, &TcpServer::onDisconnected);
qInfo() << "Client connected:" << socket->peerAddress().toString();
emit clientConnected();
}
采用单客户端模式,已有连接时拒绝新连接。
接收数据:
cpp
void TcpServer::onReadyRead()
{
QByteArray data = m_clientSocket->readAll();
m_receivedData = data;
emit dataReceived(data);
qInfo() << "Received data:" << data.size() << "bytes";
}
readAll() 读取所有可用数据,返回 QByteArray 类型。
发送数据:
cpp
bool TcpServer::sendData(const QString& data)
{
if (!m_clientSocket) {
qWarning() << "No client connected";
return false;
}
m_clientSocket->write(data.toUtf8());
m_clientSocket->flush();
return true;
}
字符串通过 toUtf8() 转换为字节数组发送。
4.3 main.cpp - 主流程
cpp
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
TcpServer server;
// 连接成功时打印提示
QObject::connect(&server, &TcpServer::clientConnected, []() {
qInfo() << "Client connected";
});
// 接收数据时打印结果
QObject::connect(&server, &TcpServer::dataReceived, [](const QByteArray& data) {
qInfo() << "Received:" << QString::fromUtf8(data);
});
// 启动OCR进程
server.startOcrProcess();
// 启动TCP服务器
server.startServer(7920);
// 15秒后发送触发信号
QTimer::singleShot(15000, [&server]() {
if (server.isClientConnected()) {
server.sendData("1");
}
});
return a.exec();
}
五、工作流程图
┌─────────────────────────────────────────────────────────────┐
│ main.cpp 主流程 │
├─────────────────────────────────────────────────────────────┤
│ 启动程序 │
│ ↓ │
│ 创建 TcpServer 对象 │
│ ↓ │
│ 连接信号槽(clientConnected, dataReceived) │
│ ↓ │
│ startOcrProcess() → 启动 VisionMaster.exe │
│ ↓ │
│ startServer(7920) → 监听端口7920 │
│ ↓ │
│ QTimer::singleShot(15000) → 15秒后触发 │
│ ↓ │
│ a.exec() → 进入事件循环 │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ TcpServer 事件处理 │
├─────────────────────────────────────────────────────────────┤
│ │
│ [新连接] onNewConnection() │
│ ├─> 获取 socket │
│ ├─> 连接信号槽(readyRead, disconnected) │
│ └─> emit clientConnected() │
│ │
│ [数据到达] onReadyRead() │
│ ├─> readAll() → QByteArray │
│ └─> emit dataReceived(data) │
│ │
│ [断开连接] onDisconnected() │
│ └─> 释放 socket,m_clientSocket = nullptr │
│ │
└─────────────────────────────────────────────────────────────┘
六、通信时序
时间轴 →
│
│ 服务器启动,监听7920端口
│ ↓
│ VM客户端连接 → 服务器打印 "Client connected"
│ ↓
│ 等待15秒...
│ ↓
│ 服务器发送 "1" → VM开始OCR识别
│ ↓
│ VM返回OCR结果 → 服务器打印 "Received: ..."
│
七、构建与运行
7.1 构建
cmd
cd VM_test
build.bat
7.2 运行
cmd
cd VM_test\build
ocr_tcp_server.exe
7.3 预期输出
OCR TCP Server started
OCR process started. PID: 12345
Server listening on port 7920
Waiting for VM client...
Client connected: 127.0.0.1:54321
Client connected
Triggering OCR...
Sent: 1
Received: {"result":"识别成功","text":"Hello World"}
八、技术要点总结
| 要点 | 说明 |
|---|---|
| 信号槽机制 | Qt 核心机制,实现对象间松耦合通信 |
| 单客户端模式 | 同一时间只允许一个客户端连接 |
| 事件循环 | a.exec() 启动 Qt 事件循环,处理所有事件 |
| 数据转换 | QString ↔ QByteArray 使用 UTF-8 编码 |
| 进程管理 | 使用 QProcess 启动外部程序 |
九、常见问题
- 连接不上:检查端口是否被占用、防火墙是否拦截
- 乱码 :确认编码格式,尝试
fromLocal8Bit()替代fromUtf8() - VM不返回数据:检查 VM 的 TCP 配置和数据输出设置
这篇博客涵盖了从项目架构到核心代码,再到构建运行的完整流程。