本帖最后由 小手凉凉 于 2024-5-25 11:29 编辑

目录:
* 硬件外设连接
* UI显示介绍
* 软件部分


正文:
硬件外设连接
首先外设部分type-c口接入5V供电,HDMI口连接显示屏,usb口分别接入鼠标和键盘。以及连接串口,方便电脑看开机打印信息
image.png

UI显示介绍:
1. 开机后页面如下,首先是系统设置,需要设置打开wifi,连接按钮预先设定了wifi加入的两个接口。连接wifi后点击时间同步,即可请求网络时间来更新系统时间显示。wifi连接ok后会有wifi图标显示
image.png
2. 操作同步时间信息,同步完成后会弹框提示,效果如下
image.png
3. 在TCP通讯页面左侧为服务器端,右侧为测试客户端。
服务端会动态添加连接客户端id加入列表中,点击监听即可;使用键盘改掉客户端连接ip,ip为要连接的服务器ip,修改端口对应,点击连接即可看到服务器端列表中的连接,并弹框提示连接ok
image.png
4. 连接ok后点击发送信息,服务器端会显示出来接受数据。服务器端发送则客户端接收到
image.png
5. 电脑连接的wifi和RemiPi板子处于同一个wifi下,使用电脑测试工具连板子的客户端,效果如下:
使用电脑上tcp助手发送数据如下,可以在服务器端收到
image.png
同样,在点击服务器上发送数据可以在电脑tcp工具上接收到数据
image.png

  软件部分
1.  Qt app启动后在mainwindows构造方法中创建p_Tcpserver = new QTcpServer();
服务端设置监听,获取ui上设置的ip 端口等信息,调用listen监听
void MainWindow::on_btnServeListen_clicked()
{
    QString strText = ui->btnServeListen->text();
    if (strText == "监听")
    {
        ui->btnServeListen->setText("停止");
        flag_bIsServeOnListen = true;
    }
    else
    {
        ui->btnServeListen->setText("监听");
        flag_bIsServeOnListen = false;
    }

    if (flag_bIsServeOnListen)
    {
        // 从输入端获取端口号
        int port = ui->editServePort->text().toInt(0, 10);

        // 侦听指定的端口
        if(!p_Tcpserver->listen(QHostAddress::Any, port))
        {
            // 若出错,则输出错误信息
            QMessageBox::information(this, tr("错误"), p_Tcpserver->errorString(), QMessageBox::Yes);
            return;
        } else
        {
            qlab_serstate.setColor(QPalette::WindowText, Qt::red);
            ui->label_SeverState->setPalette(qlab_serstate);
            ui->label_SeverState->setText("服务器运行中...");
        }
    }
    else
    {
        // 如果正在连接......
        if(pserver_socket->state() == QAbstractSocket::ConnectedState)
        {
            // 关闭连接
            pserver_socket->disconnectFromHost();
        }
        // 取消侦听
        p_Tcpserver->close();

        qlab_serstate.setColor(QPalette::WindowText, Qt::red);
        ui->label_SeverState->setPalette(qlab_serstate);
        ui->label_SeverState->setText("服务器未打开");
        this->MainClearServerListTab();
    }
}

2. 客户连接列表设置为槽函数,构造方法中初始化时绑定信号量和槽连接
connect(p_Tcpserver, &QTcpServer::newConnection, this, &MainWindow::server_New_Connect);
在有连接事件时,更新列表状态
void MainWindow::server_New_Connect()
{
    // 获取客户端连接
    pserver_socket = p_Tcpserver->nextPendingConnection();
    clientSocket.append(pserver_socket);

    //    this->MainClearServerListTab();

    // 把连接到的客户端添加入 tableWidgetServer 中
    int currentRow = ui->tableWidgetServer->rowCount();
    ui->tableWidgetServer->insertRow(currentRow);
    QTableWidgetItem *item_num = new QTableWidgetItem();
    QTableWidgetItem *item_ip = new QTableWidgetItem();
    QTableWidgetItem *item_port = new QTableWidgetItem();
    QTableWidgetItem *item_status = new QTableWidgetItem();
    item_num->setText(tr("00%1").arg(QString::number(ui->tableWidgetServer->rowCount())));
    item_ip->setText(clientSocket[currentRow]->peerAddress().toString()/*.mid(7)*/);
    item_port->setText(QString::number(clientSocket[currentRow]->peerPort()));
    item_status->setText("在线");

    qDebug() << "[long] Ip: " << clientSocket[currentRow]->peerAddress().toString();
    qDebug() << "[long] port: " << clientSocket[currentRow]->peerPort();

    ui->tableWidgetServer->setItem(currentRow, 0, item_num);
    ui->tableWidgetServer->setItem(currentRow, 1, item_ip);
    ui->tableWidgetServer->setItem(currentRow, 2, item_port);
    ui->tableWidgetServer->setItem(currentRow, 3, item_status);

    // 连接QTcpSocket的信号槽,以读取新数据
    connect(pserver_socket, SIGNAL(readyRead()), this, SLOT(Read_serverData()));
    connect(pserver_socket, SIGNAL(disconnected()), this, SLOT(disConnected()));
}
3. 客户端点击连接则创建实例pclient_socket = new QTcpSocket(); 获取ui上设置的要连接的服务器ip和端口,调用connectToHost,并连接状态改变,接收数据 以及错误状态的信号到对应的槽函数
void MainWindow::on_btnClientConnect_clicked()
{
    QString strText = ui->btnClientConnect->text();
    if (strText == "连接")
    {
        ui->btnClientConnect->setText("断开");
        m_bIsConnectClient = true;
    }
    else
    {
        ui->btnClientConnect->setText("连接");
        m_bIsConnectClient = false;
    }
    if (pclient_socket == NULL)
    {
        pclient_socket = new QTcpSocket();
    }
    if (m_bIsConnectClient && (pclient_socket->state() != QTcpSocket::ConnectedState))
    {
        //获取IP地址
        QString clientIP = ui->editClientIp->text();
        //获取端口号
        int port = ui->editClientPort->text().toInt(0, 10);
        qDebug() << "客户端端口 :" << port;

        connect(pclient_socket, &QTcpSocket::readyRead, this, &MainWindow::Read_clientData);
        connect(pclient_socket, &QTcpSocket::stateChanged, this, &MainWindow::onStateChanged);
        connect(pclient_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onErrorOccurred()));

        //取消原有连接
        pclient_socket->abort();
        //连接服务器
        pclient_socket->connectToHost(clientIP, port);

        //等待连接成功
        if(!pclient_socket->waitForConnected(3000))
        {
            return;
        }
        else {
            QMessageBox::information(this, "提示", "连接成功", QMessageBox::Yes);
        }
    }
    else
    {
        //断开连接
        pclient_socket->disconnectFromHost();
    }
}
4. 发送数据按钮函数则将要发送的内容按空格截取并转化为byte数据发送
void MainWindow::on_btnSeriverSend_clicked()
{
    // 获取选中的行
    int row = ui->tableWidgetServer->currentRow();
    QString data = ui->lineEditServer->text();

    //    QByteArray sendData = data.toLatin1();
    QByteArray sendData = GetBytesTranData(&data);

    if (data.isEmpty())
    {
        QMessageBox::information(this, "提示", "请输入发送内容!", QMessageBox::Yes);
    }
    else
    {
        if (row >= 0)
        {
            for (int i = 0; i < clientSocket.length(); ++i)
            {
                if (QString::number(clientSocket->peerPort()) == ui->tableWidgetServer->item(row, 2)->text())
                {
                    //以ASCII码形式发送文本框内容
                    clientSocket->write(sendData);
                }
            }
        }
        else
        {
            pserver_socket->write(sendData);
        }
    }
}