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 配置和数据输出设置

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

相关推荐
wuqingshun3141597 小时前
说说TCP的3次握手?为什么需要三次握手?
服务器·网络协议·tcp/ip
CHANG_THE_WORLD7 小时前
1.简单的服务端和客户端(仅作为内容补充)
linux·服务器·网络
无锡耐特森8 小时前
解决网关数据异常EtherNetIP 转Modbus TCP专用动态监测
网络·网络协议·tcp/ip
CodexDave8 小时前
数据库连接池耗尽:排查顺序与三层兜底
服务器·前端·数据库·git·云原生·容器·kubernetes
weixin_307779138 小时前
Linux下Jenkins数据故障的系统化排查Shell脚本
linux·运维·服务器·jenkins
荒--8 小时前
Burp Suite(二)
linux·运维·服务器
土星云SaturnCloud9 小时前
MP_SENet轻量语音降噪模型在土星云边缘设备的部署实战
服务器·人工智能·ai·边缘计算·语音识别
internet Boy9 小时前
服务器机房硬件入门教程
运维·服务器
2401_873479409 小时前
爬虫IP怎么防?IP离线库四层识别+日志留存,反爬留证两不误
爬虫·网络协议·tcp/ip·ip