1. 说明
本文章是接着前篇文章写的,文章中的简单案例是实现了服务端和客户端之间的通信,发送的消息比较单一,可以在此基础上进行扩展,做成聊天的小工具。
效果展示:
TCP简单通信
2. 实现步骤:
第一步:
在服务端加入数据读取函数,当服务端连接到新的客户端后,会触发newConnection()信号,此时应在其槽函数中进行响应,获取客户端的tcpSocket,当这个tcpSocket发送了消息时,会触发***readyRead()信号,此时应再设置槽函数,在这个槽函数中使用tcpSocket->readAll()***函数接收发送过来的数据,具体代码如下:
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端调用启动监听
Q_INVOKABLE void sendMsg();//供QML端调用发送数据
signals:
void sendConnectSuc(QString mStr);//连接成功时发送该信号,QML端会进行响应
void sendRecivedMsg(QString mData);//接收到数据时发送该信号,QML端会进行响应
public slots:
void newConnect();
void readFromClient();
private:
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);
//有新的连接后,执行newConnect槽函数
connect(tcpSever,SIGNAL(newConnection()),this,SLOT(newConnect()));
emit sendConnectSuc("listening....");
}
void TcpSever::sendMsg()
{
//QML端的按钮调用该函数,发送单一数据
tcpSocket->write("123");
}
void TcpSever::newConnect()
{
//获取连接成功的tcpSocket
tcpSocket = tcpSever->nextPendingConnection();
QString ip = tcpSocket->peerAddress().toString();
quint16 port = tcpSocket->peerPort();
if(port){
QString temp = QString::fromLocal8Bit("sucess connected...");
emit sendConnectSuc(temp); //发送连接成功信号
}
//当检测到有新数据传输过来时,执行readFromClient槽函数
connect(tcpSocket,SIGNAL(readyRead()),this,SLOT(readFromClient()));
}
void TcpSever::readFromClient()
{
//读取客户端发送过来的数据
QString array = QString(tcpSocket->readAll());
emit sendRecivedMsg(array); //读取到数据后,发送该信号,将数据发送的QML端进行使用
}
第二步:
在客户端加入数据读取函数,当客户端与服务端连接成功之后,即可使用***tcpSocket.write()函数向服务端发送数据。同样,服务端也能向客户端发送数据,当客户端监测到有新数据传输过来时,会触发readyRead()信号,此时应再设置槽函数,在这个槽函数中使用tcpSocket->readAll()***函数接收发送过来的数据,具体代码如下:
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调用
Q_INVOKABLE void sendMsg();//向服务端发送数据,供QML调用
signals:
void sendAskCommand(QString mStr);//请求发送后,发射此信号
void sendReceivedMsg(QString arr);//接收到服务端传输过来的数据后,发送此信号,将接收的数据发送到QML中进行使用
public slots:
void receiveMsg();//客户端检测到有数据从服务端传输过来时,触发readyRead()信号,并执行receiveMsg()槽函数
private:
QTcpSocket *tcpSocket;
};
#endif // TCPSOCKET_H
tcpSocket.cpp:
#include "Tcpsocket.h"
TcpSocket::TcpSocket(QObject *parent) : QObject(parent)
{
tcpSocket = new QTcpSocket(this);
connect(tcpSocket,SIGNAL(readyRead()),this,SLOT(receiveMsg()));//当有数据发送过来时,执行槽函数receiveMsg()
}
void TcpSocket::askConnect()
{
tcpSocket->connectToHost(QHostAddress("127.0.0.1"),6666);//请求连接服务端
emit sendAskCommand("asking.....");
}
void TcpSocket::sendMsg()
{
tcpSocket->write("456");//向服务端发送数据
}
void TcpSocket::receiveMsg()
{
QString data = QString(tcpSocket->readAll());//读取服务端发送过来的数据
emit sendReceivedMsg(data);//将数据发送到QML端进行使用
}
第三步:
在main.cpp文件中,将上面的自定义类注册到QML的上下文背景中进行使用,代码如下:
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "tcpsever.h"
#include "Tcpsocket.h"
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
const QUrl url(QStringLiteral("qrc:/main.qml"));
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
&app, [url](QObject *obj, const QUrl &objUrl) {
if (!obj && url == objUrl)
QCoreApplication::exit(-1);
}, Qt::QueuedConnection);
engine.load(url);
//注册自定义类到QML中进行使用
TcpSever tcp;
engine.rootContext()->setContextProperty("tcp",&tcp);
TcpSocket tcpsocket;
engine.rootContext()->setContextProperty("tcpSocket",&tcpsocket);
return app.exec();
}
第四步:
在main.qml文件中调用上面的函数,界面设计相对简单,包含一些按钮和两个ListView,用于显示发送的数据,类似于微信聊天对话的形式,代码如下:
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
property var i: 1
onSendConnectSuc:{
severModel.append({str:mStr})
}
onSendRecivedMsg:{
severModel.append({str:mData})
}
}
Connections{
target: tcpSocket
property var j: 1
onSendAskCommand:{
socketModel.append({index:j++,str:mStr})
}
onSendReceivedMsg:{
socketModel.append({index:j++,str:arr})
}
}
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:sendBtn_server
width: 100
height: 50
anchors.left: parent.left
anchors.top: listenBtn.bottom
anchors.topMargin: 10
anchors.leftMargin: 10
text:"SendMsg"
onClicked: {
tcp.sendMsg()
}
}
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()
}
}
Button{
id:sendBtn_Socket
width: 100
height: 50
anchors.right: parent.right
anchors.rightMargin:10
anchors.top: askConnect.bottom
anchors.topMargin: 10
text: "SendMsg"
onClicked: {
tcpSocket.sendMsg()
}
}
ListView{
id:severView
anchors.top: listenBtn.top
anchors.left: listenBtn.right
anchors.leftMargin: 5
anchors.right: parent.horizontalCenter
height: parent.height
clip:true
spacing:20
model:ListModel{
id:severModel
}
delegate: Rectangle{
width: parent.width
height: 10
Image{
id:severImg
width: parent.height*1.5
height: parent.height*2
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
source: "qrc:/images/boy.jpeg"
}
Text{
id:severcontent
height: parent.height
anchors.left: severImg.right
anchors.leftMargin: 5
anchors.verticalCenter: severImg.verticalCenter
text: str
}
}
}
ListView{
id:socketView
anchors.top: askConnect.top
anchors.right: askConnect.left
anchors.rightMargin: 5
width: 200
height: parent.height
clip:true
spacing:20
model:ListModel{
id:socketModel
}
delegate: Rectangle{
width: parent.width
height: 10
Image{
id:socketImg
width: parent.height*1.5
height: parent.height*2
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
source: "qrc:/images/girl.jpeg"
}
Text{
id:socketcontent
height: parent.height
anchors.right: socketImg.left
anchors.rightMargin: 5
anchors.verticalCenter: socketImg.verticalCenter
text: str
color: "red"
}
}
}
}