QT5中实现TCP协议简单通信

QT版本:QT5.11

其他QT5版本均支持。

1、TCP服务器建立

     首先建立TcpServer工程,涉及到 tcpserver、 tcpclientsocket、server三个文件和main主文件,

在TcpServer.pro中添加如下语句:

QT  +=network

    1)a、头文件“ tcpserver.h”中声明了需要的各种控件,tcpserver继承自QDialog,实现了服务端的对话框显示和控制。

其中具体代码如下:

#include<QDialog>
#include<QListWidget>
#include<QLabel>
#include<QLineEdit>
#include<QPushButton>
#include<QGridLayout>
#include"server.h"

class tcpserver:public QDialog
{
    Q_OBJECT
public:
    tcpserver(QWidget *parent=0,Qt::WindowFlags f=0);

private:
    QListWidget *ContentListWidget;
    QLabel *PortLabel;
    QLineEdit *portLineEdit;
    QPushButton *CreateBtn;
    QGridLayout *mainLayout;

private:
    int port;
    server *server1;
public slots:
    void slotCreateServer();
    void updateServer(QString,int);
};

 

b、在源文件“tcpserver.cpp”中,tcpserver类的构造函数实现窗体个控件的创建、布局等,具体如下:

#include "tcpserver.h"

tcpserver::tcpserver(QWidget *parent,Qt::WindowFlags f):QDialog(parent,f)
{

    setWindowTitle("Tcp Server");
    ContentListWidget = new QListWidget;
    PortLabel = new QLabel(tr("端口: "));
    portLineEdit = new QLineEdit;
    CreateBtn = new QPushButton(tr("创建聊天室"));
    mainLayout =  new QGridLayout(this);
    mainLayout->addWidget(ContentListWidget,0,0,1,2);
    mainLayout->addWidget(PortLabel,1,0);
    mainLayout->addWidget(portLineEdit,1,1);
    mainLayout->addWidget(CreateBtn,2,0,1,2);

    port = 8010;
    portLineEdit->setText(QString::number(port));
    connect(CreateBtn,SIGNAL(clicked(bool)),this,SLOT(slotCreateServer()));
}
void tcpserver::slotCreateServer()
{
    server1 = new server(this,port);
    connect(server1,SIGNAL(updateServer(QString,int)),this,SLOT(updateServer(QString,int)));
    CreateBtn->setEnabled(false);
}
void tcpserver::updateServer(QString msg, int length)
{
    ContentListWidget->addItem(msg.left(length));
}

界面创建图如下:

2)a、头文件“tcpclientsocket.h”的创建,tcpclientsocket继承自QTCPSocket,创建一个TCP套接字,以便在服务器端实现与客户端程序的通信。

具体代码如下:

#include<QTcpSocket>
#include<QObject>
class tcpclientsocket:public QTcpSocket
{
    Q_OBJECT        //添加宏(Q_OBJECT )是为了实现信号与槽的通信
public:
    tcpclientsocket(QObject *parent=0);
signals:
    void updateClients(QString,int);
    void disconnected(int);
protected slots:
    void dataReceived();
    void slotDisconnected();

  };

b、在源文件“tcpclientsocket.cpp”中,构造函数tcpclientsocket的内容如下:

#include "tcpclientsocket.h"

tcpclientsocket::tcpclientsocket(QObject *parent)
{
    connect(this,SIGNAL(readyRead()),this,SLOT(dataReceived()));
    connect(this,SIGNAL(disconnected()),this,SLOT(slotDisconnected()));
}
//当有数据到来时,出发dataReceived()函数,从套接字中将有效的数据读出,然后发出updateClients()信号,

void tcpclientsocket::dataReceived()
{
    while (bytesAvailable()>0) {
        int length = bytesAvailable();
        char buf[1024];
        read(buf,length);
        QString msg = buf;
        //通知服务器向聊天室内的所有成员广播信息
        emit updateClients(msg,length);
    }
}
//进行关闭信号
void tcpclientsocket::slotDisconnected()
{
    emit disconnected(this->socketDescriptor());
}

3)a、头文件“server.h”,server继承自QTcpServer,实现一个TCP协议的服务器。利用QTcpServer,开发者可以监听到指定端口的TCP连接。具体代码如下:

#include<QTcpServer>
#include<QObject>
#include"tcpclientsocket.h"     //  包含TCP套接字

class server:public QTcpServer
{
    Q_OBJECT        //添加宏(Q_OBJECT )是为了实现信号与槽的通信
public:
    server(QObject *parent=0,int port=0);
    //保存与每一个客户端连接的tcpclientsocke
    QList<tcpclientsocket*> tcpClientSocketList;
signals:
    void updateServer(QString,int);
public slots:
    void updateClients(QString,int);
    void slotDisconnected(int);
protected:
    void incomingConnection(int socketDescriptor);

};

b、源文件“server.cpp”,其中具体内容见代码中标注(很详细),代码如下:

#include "server.h"

server::server(QObject *parent,int port):QTcpServer(parent)
{   //在指定的端口对任意地址进行监听
    listen(QHostAddress::Any,port);
}
//当出现一个新的连接时,QTcpServer出发incomingConnection()函数
void server::incomingConnection(int socketDescriptor)
{
    //创建一个新的 tcpclientsocket与客户端通信
    tcpclientsocket *tcpClientSocket = new tcpclientsocket(this);

    //连接 tcpclientsocket的updateClients信号
    connect(tcpClientSocket,SIGNAL(updateClients(QString,int)),this,SLOT(updateClients(QString,int)));

     //连接 tcpclientsocket的disconnected信号
    connect(tcpClientSocket,SIGNAL(disconnected(int)),this,SLOT(slotDisconnected(int)));

    //将新创建的 tcpClientSocket的套接字描述符指定为参数
    tcpClientSocket->setSocketDescriptor(socketDescriptor);

    //将 tcpClientSocket加入客户端套接字列表以便管理
    tcpClientSocketList.append(tcpClientSocket);
}
void server::updateClients(QString msg, int length)
{
    //发出 updateServer信号,用来通知服务器对话框更新相应的显示状态
    emit updateServer(msg,length);
    //实现信息的广播
    for(int i=0;i<tcpClientSocketList.count();i++)
    {
        QTcpSocket *item = tcpClientSocketList.at(i);
        if(item->write(msg.toLatin1(),length)!=length)
        {
            continue;
        }
    }
}

void server::slotDisconnected(int descriptor)
{
    for(int i=0;i<tcpClientSocketList.count();i++)
    {
        QTcpSocket *item = tcpClientSocketList.at(i);
        if(item->socketDescriptor()==descriptor)
        {
            tcpClientSocketList.removeAt(i);
            return;
        }
    }
    return ;
}

4)主函数“main.cpp”如下:

比较简单,不做介绍了。

#include <QtWidgets/QApplication>
#include <QtWidgets/QMainWindow>
#include "tcpserver.h"


int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    tcpserver * tcpServer = new tcpserver();
    QMainWindow window;
    window.setCentralWidget( tcpServer);
    window.show();

    return a.exec();
}

2、TCP客户端建立

首先建立TcpClient工程,涉及到tcpclient和main主文件,

在TcpClient.pro中加入如下代码:

QT+= network

1)a、头文件“tcpclient.h”,其中tcpclient类继承自QDialog类,声明了需要的各种控件,

具体代码如下:

#include<QDialog>
#include<QListWidget>
#include<QLabel>
#include<QLineEdit>
#include<QPushButton>
#include<QGridLayout>

#include<QHostAddress>
#include<QTcpSocket>

class TcpClient:public QDialog
{
        Q_OBJECT
public:
    TcpClient(QWidget *parent=0,Qt::WindowFlags f=0);

private:
    QListWidget *contentListWidget;
    QLineEdit *sendLineEdit;
    QPushButton *sendBtn;
    QLabel *userNameLabel;
    QLineEdit *userNameLineEdit;
    QLabel *serverIPLabel;
    QLineEdit *serverIPLineEdit;
    QLabel *PortLabel;

    QLineEdit *portLineEdit;
    QPushButton *enterBtn;
    QGridLayout *mainLayout;

    bool status;
    int port;
    QHostAddress *serverIP;
    QString userName;
    QTcpSocket *tcpsocket;
 public slots:
    void slotEnter();
    void slotConnected();
    void slotDisconnected();
    void dataReceived();
    void slotSend();
};

b、源文件“tcpclient.cpp”具体代码如下:

#include "TcpClient.h"
#include<QMessageBox>
#include<QHostInfo>

TcpClient::TcpClient(QWidget *parent,Qt::WindowFlags f):QDialog(parent,f)
{
    ///![1]     完成客户端的界面设计
    setWindowTitle("TCP Client");
    contentListWidget = new QListWidget;
    sendLineEdit = new QLineEdit;
    sendBtn = new QPushButton(tr("发送"));
    userNameLabel = new QLabel(tr("用户名: "));
    userNameLineEdit = new QLineEdit;
    serverIPLabel = new QLabel(tr("服务器地址"));
    serverIPLineEdit = new QLineEdit;
    PortLabel = new QLabel(tr("端口: "));
    portLineEdit = new QLineEdit;
    enterBtn = new QPushButton(tr("进入聊天室"));
    mainLayout = new QGridLayout(this);
    mainLayout->addWidget(contentListWidget,0,0,1,2);
    mainLayout->addWidget(sendLineEdit,1,0);
    mainLayout->addWidget(sendBtn,1,1);
    mainLayout->addWidget(userNameLabel,2,0);
    mainLayout->addWidget(userNameLineEdit,2,1);
    mainLayout->addWidget(serverIPLabel,3,0);
    mainLayout->addWidget(serverIPLineEdit,3,1);
    mainLayout->addWidget(PortLabel,4,0);
    mainLayout->addWidget(portLineEdit,4,1);
    mainLayout->addWidget(enterBtn,5,0,1,2);
    ///![1]

     ///![2]        槽函数slotEnter()实现了进入和离开聊天室的功能
    status = false;
    port = 8010;    //设置端口号
    portLineEdit->setText(QString::number(port));
    serverIP = new QHostAddress();
    connect(enterBtn,SIGNAL(clicked(bool)),this,SLOT(slotEnter()));
    connect(sendBtn,SIGNAL(clicked(bool)),this,SLOT(slotSend()));
    sendBtn->setEnabled(false);
     ///![2]
}

void TcpClient::slotEnter()
{
    //status表示当前的状态,true表示已经进入聊天室,false表示已经离开聊天室
    if(!status)
    {
        /*完成输入合法性检验*/
        QString ip = serverIPLineEdit->text();
        if(!serverIP->setAddress(ip))   //判断给定的ip地址能否被正确解析
        {
            QMessageBox::information(this,tr("error"),tr("server ip address error!"));
            return;
        }
        userName=userNameLineEdit->text();

        /*创建了一个QTcpSocket类对象,并将信号/槽连接起来 */
        tcpsocket = new QTcpSocket(this);
        connect(tcpsocket,SIGNAL(connected()),this,SLOT(slotConnected()));
        connect(tcpsocket,SIGNAL(disconnected()),this,SLOT(slotDisconnected()));
        connect(tcpsocket,SIGNAL(readyRead()),this,SLOT(dataReceived()));
        //与TCP服务器端连接,连接成功后,发出connected()信号
        tcpsocket->connectToHost(*serverIP,port);
        status=true;
    }
    else {
        int length=0;
        QString msg=userName+tr(":Leave Chat Room");
        if((length=tcpsocket->write(msg.toLatin1(),msg.length()))!=msg.length())
        {
            return;
        }
        //与服务器断开连接,断开连接后发出disconnected()信号
        tcpsocket->disconnectFromHost();
        status=false;   //将status状态复位
    }
}

void TcpClient::slotConnected()
{
    sendBtn->setEnabled(true);
    enterBtn->setText("离开");
    int length=0;
    //构造一条进入聊天室的消息
    QString msg=userName+tr(":Enter Char Room");
     if((length=tcpsocket->write(msg.toLatin1(),msg.length()))!=msg.length())
     {
         return;
     }
}

void TcpClient::slotSend()
{
    if(sendLineEdit->text()=="")
    {
        return;
    }
    QString msg=userName+":"+sendLineEdit->text();
    tcpsocket->write(msg.toLatin1(),msg.length());
    sendLineEdit->clear();
}

void TcpClient::slotDisconnected()
{
    sendBtn->setEnabled(false);
    enterBtn->setText(tr("进入聊天室"));

}

//当有数据到来时,触发dataReceived()函数,从套接字中将有效数据取出并显示。
void TcpClient::dataReceived()
{
    while (tcpsocket->bytesAvailable()>0) {
        QByteArray datagram;
        datagram.resize(tcpsocket->bytesAvailable());
        tcpsocket->read(datagram.data(),datagram.size());
        QString msg=datagram.data();
        contentListWidget->addItem(msg.left(datagram.size()));
    }
}

界面如下:

2)主函数“main.cpp”如下:

#include <QtWidgets/QApplication>
#include <QtWidgets/QMainWindow>
#include "TcpClient.h"


int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    TcpClient *tcpClient = new TcpClient();

    QMainWindow window;
    window.setCentralWidget(tcpClient);
    window.show();

    return a.exec();
}

3、工作界面如下:

 

其中,默认的服务器是 127.0.0.1,可以创建多个客户端窗口,进行交互。

工程下载地址:

https://download.csdn.net/download/jamin_liu_90/10762945

  • 3
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Modbus TCP协议是一种基于TCP/IP协议的工业通信协议,可用于工业自动化领域的数据采集、监控和控制。在QT实现Modbus TCP协议,可以使用第三方库QModbus。 QModbus是一个开源的Qt Modbus库,提供了Modbus TCP和RTU协议实现。下面是一个简单的Modbus TCP讯的示例代码: ```c++ #include <QCoreApplication> #include <QDebug> #include <QModbusTcpClient> int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); // 创建Modbus TCP客户端 QModbusTcpClient *client = new QModbusTcpClient(&a); // 连接到Modbus TCP服务器 client->setConnectionParameter(QModbusDevice::NetworkPortParameter, 502); client->setConnectionParameter(QModbusDevice::NetworkAddressParameter, "192.168.1.100"); client->connectDevice(); // 检查连接是否成功 if (!client->isConnected()) { qDebug() << "Modbus TCP连接失败:" << client->errorString(); return a.exec(); } // 读取Modbus寄存器的值 QModbusDataUnit readUnit(QModbusDataUnit::HoldingRegisters, 0, 1); if (auto *reply = client->sendReadRequest(readUnit, 1)) { // 等待响应 while (!reply->isFinished()) { qApp->processEvents(); } // 处理响应 if (reply->error() == QModbusDevice::NoError) { qDebug() << "Modbus寄存器值:" << reply->resultAt(0); } else { qDebug() << "读取Modbus寄存器失败:" << reply->errorString(); } // 释放响应 reply->deleteLater(); } else { qDebug() << "发送Modbus读取请求失败:" << client->errorString(); } // 断开连接 client->disconnectDevice(); delete client; return a.exec(); } ``` 上面的示例代码,首先创建了一个QModbusTcpClient客户端,然后连接到Modbus TCP服务器。连接成功后,使用sendReadRequest()方法读取Modbus寄存器的值,并等待响应。如果响应无错误,则打印读取到的寄存器值。最后断开连接并释放客户端对象。 需要注意的是,QModbusTcpClient是异步的,需要等待响应才能处理结果。因此,在等待响应期间需要调用qApp->processEvents()方法处理事件队列。 除了读取寄存器的值,QModbus还提供了其他的Modbus TCP讯方法,例如写入寄存器的值、读取线圈状态等。具体的使用方法可以参考QModbus的文档。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值