Qt TCP 服务器开发实战:与 VisionMaster OCR 通信

一、项目概述

本文介绍如何使用 Qt 框架开发一个 TCP 服务器,实现与 VisionMaster(VM)视觉检测软件的通信。服务器负责:

  1. 启动 VisionMaster 进程
  2. 监听 TCP 端口等待 VM 客户端连接
  3. 发送触发信号给 VM
  4. 接收并处理 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 启动外部程序

九、常见问题

  1. 连接不上:检查端口是否被占用、防火墙是否拦截
  2. 乱码 :确认编码格式,尝试 fromLocal8Bit() 替代 fromUtf8()
  3. VM不返回数据:检查 VM 的 TCP 配置和数据输出设置

这篇博客涵盖了从项目架构到核心代码,再到构建运行的完整流程。

相关推荐
Julien20049 小时前
控制 SELinux 文件上下文
linux·运维·服务器
sulikey9 小时前
Linux Core Dump 完全指南:从原理到实战的崩溃调试手册。什么是core dump?程序报错core dumped怎么办?
linux·服务器·操作系统·调试·coredump
Lifangyun_WD9 小时前
第一次租 GPU 服务器怎么开始?镜像、SSH、数据存储和停机前要做什么
服务器·云计算·gpu算力·gpu算力租赁
机器视觉知识推荐、就业指导9 小时前
为什么老说“纯 Qt 没啥就业市场”?
开发语言·qt
telepan9 小时前
Qt 开发避坑与性能指南:如何优雅、安全地定义全局常量字符串?
开发语言·qt
小灰灰搞电子10 小时前
完全驾驭 Qt 与数据库:C++ ORM 框架 QxOrm 原理与实践指南
数据库·c++·qt
QT界面美化性能优化10 小时前
QT+AI:使用AI技术为QT应用程序赋能
c++·人工智能·qt·opencv·qt教程·qt6.3
m0_6952514910 小时前
Qt MaintenanceTool 使用国内镜像加速下载(超详细教程)
开发语言·qt
DevLoom_10 小时前
SD卡插电脑提示:驱动器中的磁盘未被格式化?恢复数据正确处理步骤
运维·服务器·电脑
yyuuuzz12 小时前
记一次 VPS 性能排查:共享 CPU 突发额度导致的限流
运维·服务器·人工智能