1. 说明
一般QT/QML用来开发桌面程序或者嵌入式软件,作为上位机开发时,还需要与下位机进行通讯才能实现控制,一般多用于机器人行业当中。实现通讯的方式有很多种,比较常见的包括串口通信和TCP网络通信等,本文将简要介绍TCP通讯方式。
效果展示:
TCP通讯连接
2. 实现步骤
TCP通信需要使用的QT当中的QTcpServer和QTcpSocket两个类
第一步:
创建tcpServer类,属于服务端,用于监听客户端的请求连接,详看注释,代码如下:
tcpServer.h:
#ifndef TCPSEVER_H
#define TCPSEVER_H
#include <QObject>
#include <QDebug>
#include <QTcpServer>
#include <QTcpSocket>
#include <QByteArray>
class TcpSever : public QObject
{
Q_OBJECT
public:
explicit TcpSever(QObject *parent = nullptr);
Q_INVOKABLE void startListen();//此函数用于QML端调用,启动监听
signals:
void sendConnectSuc(QString mStr);
public slots:
void newConnect();//监听启动后,发现新的连接后,触发这个槽函数
private:
//服务端既需要tcpServer也需要tcpSocket
QTcpServer *tcpSever;
QTcpSocket *tcpSocket;
QByteArray m_data;
};
#endif // TCPSEVER_H
tcpServer.cpp:
#include "tcpsever.h"
TcpSever::TcpSever(QObject *parent) : QObject(parent)
{
}
void TcpSever::startListen()
{
tcpSever = new QTcpServer(this);
tcpSever->listen(QHostAddress::Any,6666); //启动监听
//TcpServer端检测到新的连接请求后,会发射newConnection()信号
connect(tcpSever,SIGNAL(newConnection()),this,SLOT(newConnect()));//绑定信号槽
emit sendConnectSuc("listening....");
}
void TcpSever::newConnect()
{
tcpSocket = tcpSever->nextPendingConnection();//当连接成功后,获取客户端套接字,其中包含了一些ip/port信息
QString ip = tcpSocket->peerAddress().toString();//获取ip地址
quint16 port = tcpSocket->peerPort();//获取端口号
QString temp = QString::fromLocal8Bit("[%1:%2]:sucess connected...").arg(ip).arg(port);
emit sendConnectSuc(temp);
}
第二步:
创建tcpSocket类,属于客户端,用于向服务端发送连接请求,详看注释,代码如下:
tcpSocket.h:
#ifndef TCPSOCKET_H
#define TCPSOCKET_H
#include <QObject>
#include <QTcpSocket>
#include <QHostAddress>
class TcpSocket : public QObject
{
Q_OBJECT
public:
explicit TcpSocket(QObject *parent = nullptr);
Q_INVOKABLE void askConnect();//供QML端调用,用于向客户端发送连接请求
signals:
void sendAskCommand(QString mStr);
private:
//客户端不需要监听,只需要tcpSocket即可
QTcpSocket *tcpSocket;
};
#endif // TCPSOCKET_H
tcpSocket.cpp:
#include "Tcpsocket.h"
TcpSocket::TcpSocket(QObject *parent) : QObject(parent)
{
tcpSocket = new QTcpSocket(this);//创建对象
}
void TcpSocket::askConnect()
{
//调用connectToHost(ip,port)函数,向服务端请求连接
//ip,port值是客户端这边决定的
tcpSocket->connectToHost(QHostAddress("127.0.0.1"),6666);
emit sendAskCommand("asking.....");
}
第三步:
在main.cpp文件中,将上面两个类注册到QML的上下文背景中,以方便在QML中进行调用,代码如下:
#include <QQmlContext>
#include "tcpsever.h"
#include "Tcpsocket.h"
TcpSever tcp;
engine.rootContext()->setContextProperty("tcp",&tcp);
TcpSocket tcpsocket;
engine.rootContext()->setContextProperty("tcpSocket",&tcpsocket);
第四步:
在main.qml文件中设置两个按钮,调用上面的函数,先启动监听,再进行连接请求。
import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Controls 2.1
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Connections{
target: tcp //响应tcpSever中的信号
property var i: 1
onSendConnectSuc:{
severModel.append({index:i++,str:mStr})
}
}
Connections{
target: tcpSocket //响应tcpSocket中的信号
property var j: 1
onSendAskCommand:{
socketModel.append({index:j++,str:mStr})
}
}
Button{
id:listenBtn //启动监听按钮
width: 100
height: 50
anchors.left: parent.left
anchors.top: parent.top
anchors.topMargin: 10
anchors.leftMargin: 10
text:"StartListen"
onClicked: {
tcp.startListen();
}
}
Button{
id:askConnect //请求连接按钮
width: 100
height: 50
anchors.right: parent.right
anchors.rightMargin:10
anchors.top: parent.top
anchors.topMargin: 10
text: "AskConnect"
onClicked: {
tcpSocket.askConnect()
}
}
ListView{
id:severView //显示服务端信息的view视图
anchors.top: listenBtn.top
anchors.left: listenBtn.right
anchors.leftMargin: 5
anchors.right: parent.horizontalCenter
height: parent.height
clip:true
model:ListModel{
id:severModel
// ListElement{
// index:"1"
// str:"the first data..."
// }
}
delegate: Rectangle{
width: parent.width
height: 10
Text{
id:severxuhao
width: 50
height: parent.height
anchors.verticalCenter: parent.verticalCenter
text: index
}
Text{
id:severcontent
height: parent.height
anchors.left: severxuhao.right
anchors.leftMargin: 5
anchors.verticalCenter: parent.verticalCenter
text: str
}
}
}
ListView{
id:socketView //显示客户端信息的view视图
anchors.top: askConnect.top
anchors.right: askConnect.left
anchors.rightMargin: 5
width: 200
height: parent.height
clip:true
model:ListModel{
id:socketModel
// ListElement{
// index:"1"
// str:"the first data..."
// }
}
delegate: Rectangle{
width: parent.width
height: 10
Text{
id:socketxuhao
width: 7
height: parent.height
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
text: index
color: "red"
}
Text{
id:socketcontent
height: parent.height
anchors.left: parent.left
anchors.leftMargin: 5
anchors.verticalCenter: parent.verticalCenter
text: str
color: "red"
}
}
}
}