QTTCP客户端服务端通信

Qt 网络模块为我们提供了编写 TCP / IP 客户端和服务器的类。它提供了较低级别的类,例
如代表低级网络概念的 QTcpSocket QTcpServer QUdpSocket ,以及诸如 QNetworkRequest
QNetworkReply QNetworkAccessManager 之类的高级类来执行使用通用协议的网络操作。
还提供了诸如 QNetworkConfiguration QNetworkConfigurationManager QNetworkSession 等类,
实现承载管理。
想要在程序中使用 Qt 网络模块,我们需要在 pro 项目配置文件里增加下面的一条语句。
QT += network

TCP介绍

TCP 协议( Transmission Control Protocol )全称是传输控制协议是一种 面向连接的、可靠的、
基于字节流 的传输层通信协议。
TCP 通信必 须先建立 TCP 连接 ,通信端分为客户端和服务端。服务端通过监听某个端口
来监听是否有客户端连接到来,如果有连接到来,则建立新的 socket 连接;客户端通过 ip
port 连接服务端,当成功建立连接之后,就可进行数据的收发了。需要注意的是,在 Qt 中,
Qt socket 当成输入输出流来对待的,数据的收发是通过 read() write() 来进行的,需要与我
们常见的 send() recv() 进行区分。
TCP 客户端与服务端通信示意图如下。

 TCP 服务端应用实例

本例大体流程
首先获取本地 IP 地址。创建一个 tcpSocket 套接字,一个 tcpServer 服务端。点击监听即监听本
地的主机 IP 地址和端口,同时等待服务端的连接。此程序需要结合客户端一起使用,可实现多个客户端的传播。
widget.h
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QTcpServer>
#include <QTcpSocket>
#include <QNetworkInterface>
#include <QDebug>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private:
    Ui::Widget *ui;
    /* tcp 服务器 */
    QTcpServer *tcpServer;
    /* 通信套接字 */
    QTcpSocket *tcpSocket;
    /* 存储本地的 ip 列表地址 */
    QList<QHostAddress> IPlist;
    /* 获取本地的所有 ip */
    void getLocalHostIP();

private slots:
    /* 客户端连接处理槽函数 */
    void clientConnected();
    /* 开始监听槽函数 */
    void startListen();
    /* 停止监听槽函数 */
    void stopListen();
    /* 清除文本框时的内容 */
    void clearTextBrowser();
    /* 接收到消息 */
    void receiveMessages();
    /* 发送消息 */
    void sendMessages();
    /* 连接状态改变槽函数 */
    void socketStateChange(QAbstractSocket::SocketState);

};
#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    tcpServer = new QTcpServer(this);
    tcpSocket = new QTcpSocket(this);
    ui->spinBox->setRange(10000, 99999);
    ui->pushButton_5->setEnabled(false);
    getLocalHostIP();
    /* 信号槽连接 */
    connect(ui->pushButton, SIGNAL(clicked()),this, SLOT(startListen()));
    connect(ui->pushButton_5, SIGNAL(clicked()),this, SLOT(stopListen()));
    connect(ui->pushButton_6, SIGNAL(clicked()),this, SLOT(clearTextBrowser()));
    connect(ui->pushButton_4, SIGNAL(clicked()),this, SLOT(sendMessages()));
    connect(tcpServer, SIGNAL(newConnection()),this, SLOT(clientConnected()));
}

Widget::~Widget()
{
    delete ui;
}
/* 新的客户端连接 */
void Widget::clientConnected()
{
    /* 获取客户端的套接字 */
    tcpSocket = tcpServer->nextPendingConnection();
    /* 客户端的 ip 信息 */
    QString ip = tcpSocket->peerAddress().toString();
    /* 客户端的端口信息 */
    quint16 port = tcpSocket->peerPort();
    /* 在文本浏览框里显示出客户端的连接信息 */
    ui->textBrowser->append("客户端已连接");
    ui->textBrowser->append("客户端 ip 地址:" + ip);
    ui->textBrowser->append("客户端端口:" + QString::number(port));
    
    connect(tcpSocket, SIGNAL(readyRead()),this, SLOT(receiveMessages()));
    connect(tcpSocket,SIGNAL(stateChanged(QAbstractSocket::SocketState)),this,
            SLOT(socketStateChange(QAbstractSocket::SocketState)));
}
void Widget::getLocalHostIP()
{
    QList<QNetworkInterface> list= QNetworkInterface::allInterfaces();
 
    /* 遍历 list */
    foreach (QNetworkInterface interface, list) {
 
        /* QNetworkAddressEntry 类存储 IP 地址子网掩码和广播地址 */
        QList<QNetworkAddressEntry> entryList= interface.addressEntries();
   
        /* 遍历 entryList */
        foreach (QNetworkAddressEntry entry, entryList) {
            /* 过滤 IPv6 地址,只留下 IPv4 */
            if (entry.ip().protocol() == QAbstractSocket::IPv4Protocol) {
            
                ui->comboBox->addItem(entry.ip().toString());
                /* 添加到 IP 列表中 */
                IPlist<<entry.ip();
             }
        }
     }
}
/* 开始监听槽函数 */
void Widget::startListen()
{
    /* 需要判断当前主机是否有IP项 */
    if (ui->comboBox->currentIndex() != -1) {
        qDebug()<<"start listen"<<endl;
        tcpServer->listen(IPlist[ui->comboBox->currentIndex()],ui->spinBox->value());

        /* 设置按钮与下拉列表框的状态 */
        ui->pushButton->setEnabled(false);
        ui->pushButton_5->setEnabled(true);
        ui->comboBox->setEnabled(false);
        ui->spinBox->setEnabled(false);

        /* 在文本浏览框里显示出服务端 */
        ui->textBrowser->append("服务器IP地址:"+ ui->comboBox->currentText());
        ui->textBrowser->append("正在监听端口:"+ ui->spinBox->text());
    }
}
/* 停止监听槽函数 */
void Widget::stopListen()
{
    qDebug()<<"stop listen"<<endl;
    /* 停止监听 */
    tcpServer->close();

    /* 如果是连接上了也应该断开,如果不断开客户端还能继续发送信息,
     * 因为socket未断开,还在监听上一次端口 */
    if (tcpSocket->state() == tcpSocket->ConnectedState)
        tcpSocket->disconnectFromHost();

    /* 设置按钮与下拉列表框的状态  */
    ui->pushButton_5->setEnabled(false);
    ui->pushButton->setEnabled(true);
    ui->comboBox->setEnabled(true);
    ui->spinBox->setEnabled(true);

    /* 将停止监听的信息添加到文本浏览框中 */
    ui->textBrowser->append("已停止监听端口:" + ui->spinBox->text());
}
/* 清除文本框时的内容 */
void Widget::clearTextBrowser()
{
    /* 清除文本浏览器的内容 */
    ui->textBrowser->clear();
}
 /* 接收到消息 */
void Widget::receiveMessages()
{
    /* 读取接收到的消息 */
    QString messages = "客户端:" + tcpSocket->readAll();
    ui->textBrowser->append(messages);
}
/* 发送消息 */
void Widget::sendMessages()
{
    QList <QTcpSocket *> socketList=tcpServer->findChildren<QTcpSocket *>();
    qDebug()<<"tcpSocket 数量: "<<socketList.count()<<endl;

    if(socketList.count()== 0){
        ui->textBrowser->append("请先与客户端连接!");
        return;
    }
    foreach(QTcpSocket *tmpTcpSocket,socketList){
        tmpTcpSocket->write(ui->lineEdit->text().toUtf8());
    }
    ui->textBrowser->append("服务端 "+ui->lineEdit->text());
}
/* 连接状态改变槽函数 */
void Widget::socketStateChange(QAbstractSocket::SocketState state)
{
    switch (state) {
    case QAbstractSocket::UnconnectedState:
        ui->textBrowser->append("scoket状态:客户端断开连接");
        tcpSocket->deleteLater();
        break;
    case QAbstractSocket::ConnectedState:
        ui->textBrowser->append("scoket状态:客户端已连接");
        break;
    case QAbstractSocket::ConnectingState:
        ui->textBrowser->append("scoket状态:ConnectingState");
        break;
    case QAbstractSocket::HostLookupState:
        ui->textBrowser->append("scoket状态:HostLookupState");
        break;
    case QAbstractSocket::ClosingState:
        ui->textBrowser->append("scoket状态:ClosingState");
        break;
    case QAbstractSocket::ListeningState:
        ui->textBrowser->append("scoket状态:ListeningState");
        break;
    case QAbstractSocket::BoundState:
        ui->textBrowser->append("scoket状态:BoundState");
        break;
    default:
        break;
    }
}

 TCP 客户端应用实例

本例大体流程:
首先获取本地 IP 地址。创建一个 tcpSocket 套接字,然后用 tcpSocket 套接字使用 connectToHost 函数连接服务端的主机 IP 地址和端口,即可相互通信。

 widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QTcpServer>
#include <QTcpSocket>
#include <QNetworkInterface>
#include <QDebug>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private:
    Ui::Widget *ui;
    /* 通信套接字 */
    QTcpSocket *tcpSocket;

    /* 存储本地的ip列表地址 */
    QList<QHostAddress> IPlist;

    /* 获取本地的所有ip */
    void getLocalHostIP();
private slots:
    /* 连接 */
    void toConnect();

    /* 断开连接 */
    void toDisConnect();

    /* 已连接 */
    void connected();

    /* 已断开连接 */
    void disconnected();

    /* 清除文本框时的内容 */
    void clearTextBrowser();

    /* 接收到消息 */
    void receiveMessages();

    /* 发送消息 */
    void sendMessages();

    /* 连接状态改变槽函数 */
    void socketStateChange(QAbstractSocket::SocketState);
};
#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    /* tcp套接字 */
    tcpSocket = new QTcpSocket(this);
    /* 设置端口号的范围,注意不要与主机的已使用的端口号冲突 */
    ui->spinBox->setRange(10000, 99999);
    /* 设置断开连接状态不可用 */
    ui->pushButton_2->setEnabled(false);

    /* 获取本地 ip */
    getLocalHostIP();
    /* 信号槽连接 */
    connect(ui->pushButton, SIGNAL(clicked()),this, SLOT(toConnect()));
    connect(ui->pushButton_2, SIGNAL(clicked()),this, SLOT(toDisConnect()));
    connect(ui->pushButton_3, SIGNAL(clicked()),this, SLOT(clearTextBrowser()));
    connect(ui->pushButton_4, SIGNAL(clicked()),this, SLOT(sendMessages()));
    connect(tcpSocket, SIGNAL(connected()),this, SLOT(connected()));
    connect(tcpSocket, SIGNAL(disconnected()),this, SLOT(disconnected()));
    connect(tcpSocket, SIGNAL(readyRead()),this, SLOT(receiveMessages()));
    connect(tcpSocket,SIGNAL(stateChanged(QAbstractSocket::SocketState)),this,
           SLOT(socketStateChange(QAbstractSocket::SocketState)));
}

Widget::~Widget()
{
    delete ui;
}
void Widget::toConnect()
{
    /* 如果连接状态还没有连接 */
    if (tcpSocket->state() != tcpSocket->ConnectedState) {
        /* 指定IP地址和端口连接 */
        tcpSocket->connectToHost(IPlist[ui->comboBox->currentIndex()],ui->spinBox->value());
    }
}

void Widget::toDisConnect()
{
    /* 断开连接 */
    tcpSocket->disconnectFromHost();

    /* 关闭socket*/
    tcpSocket->close();
}

void Widget::connected()
{
    /* 显示已经连接 */
    ui->textBrowser->append("已经连上服务端");

    /* 设置按钮与下拉列表框的状态 */
    ui->pushButton->setEnabled(false);
    ui->pushButton_2->setEnabled(true);
    ui->comboBox->setEnabled(false);
    ui->spinBox->setEnabled(false);
}

void Widget::disconnected()
{
    /* 显示已经断开连接 */
    ui->textBrowser->append("已经断开服务端");

    /* 设置按钮与下拉列表框的状态  */
    ui->pushButton_2->setEnabled(false);
    ui->pushButton->setEnabled(true);
    ui->comboBox->setEnabled(true);
    ui->spinBox->setEnabled(true);
}

/* 获取本地IP */
void Widget::getLocalHostIP()
{
    // /* 获取主机的名称 */
    // QString hostName = QHostInfo::localHostName();

    // /* 主机的信息 */
    // QHostInfo hostInfo = QHostInfo::fromName(hostName);

    // /* ip列表,addresses返回ip地址列表,注意主机应能从路由器获取到
    // * IP,否则可能返回空的列表(ubuntu用此方法只能获取到环回IP) */
    // IPlist = hostInfo.addresses();
    // qDebug()<<IPlist<<endl;

    // /* 遍历IPlist */
    // foreach (QHostAddress ip, IPlist) {
    //      if (ip.protocol() == QAbstractSocket::IPv4Protocol)
    //          comboBox->addItem(ip.toString());
    //    }

    /* 获取所有的网络接口,
     * QNetworkInterface类提供主机的IP地址和网络接口的列表 */
    QList<QNetworkInterface> list = QNetworkInterface::allInterfaces();

    /* 遍历list */
    foreach (QNetworkInterface interface, list) {

        /* QNetworkAddressEntry类存储IP地址子网掩码和广播地址 */
        QList<QNetworkAddressEntry> entryList = interface.addressEntries();

        /* 遍历entryList */
        foreach (QNetworkAddressEntry entry, entryList) {
            /* 过滤IPv6地址,只留下IPv4 */
            if (entry.ip().protocol() == QAbstractSocket::IPv4Protocol) {
                ui->comboBox->addItem(entry.ip().toString());
                /* 添加到IP列表中 */
                IPlist<<entry.ip();
            }
        }
    }
}

/* 清除文本浏览框里的内容 */
void Widget::clearTextBrowser()
{
    /* 清除文本浏览器的内容 */
    ui->textBrowser->clear();
}

/* 客户端接收消息 */
void Widget::receiveMessages()
{
    /* 读取接收到的消息 */
    QString messages = tcpSocket->readAll();
    ui->textBrowser->append("服务端:" + messages);
}

/* 客户端发送消息 */
void Widget::sendMessages()
{
    if(NULL == tcpSocket)
        return;

    if(tcpSocket->state() == tcpSocket->ConnectedState) {
        /* 客户端显示发送的消息 */
        ui->textBrowser->append("客户端:" + ui->lineEdit->text());

        /* 发送消息 */
        tcpSocket->write(ui->lineEdit->text().toUtf8().data());
    }
}

/* 客户端状态改变 */
void Widget::socketStateChange(QAbstractSocket::SocketState state)
{
    switch (state) {
    case QAbstractSocket::UnconnectedState:
        ui->textBrowser->append("scoket状态:与服务端未连接");
        tcpSocket->deleteLater();
        break;
    case QAbstractSocket::ConnectedState:
        ui->textBrowser->append("scoket状态:与服务端已连接");
        break;
    case QAbstractSocket::ConnectingState:
        ui->textBrowser->append("scoket状态:ConnectingState");
        break;
    case QAbstractSocket::HostLookupState:
        ui->textBrowser->append("scoket状态:HostLookupState");
        break;
    case QAbstractSocket::ClosingState:
        ui->textBrowser->append("scoket状态:ClosingState");
        break;
    case QAbstractSocket::ListeningState:
        ui->textBrowser->append("scoket状态:ListeningState");
        break;
    case QAbstractSocket::BoundState:
        ui->textBrowser->append("scoket状态:BoundState");
        break;
    default:
        break;
    }
}

运行结果:

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Qt是一个跨平台的C++应用程序框架,它提供了丰富的库和工具来帮助开发者创建各种类型的应用程序,包括网络通信应用。 在Qt中实现TCP服务端客户端通信非常简单。首先,我们需要创建一个QTcpServer对象来作为服务端,该对象负责监听客户端的连接请求。接下来,我们需要为QTcpServer对象绑定一个IP地址和端口号,以便客户端能够连接到该地址和端口。当有新的客户端连接时,QTcpServer对象会发出newConnection()信号。 在服务端的槽函数中,我们可以使用QTcpServer的nextPendingConnection()函数获取新连接的QTcpSocket对象,该对象用于和客户端进行通信。我们可以在该对象上发送和接收数据,以实现服务端客户端之间的数据交互。 接下来,我们需要创建一个QTcpSocket对象作为客户端,该对象负责和服务端建立连接。我们需要使用connectToHost()函数来指定要连接的服务端的IP地址和端口号。一旦连接成功,QTcpSocket对象会发出connected()信号。 在客户端的槽函数中,我们可以使用QTcpSocket对象发送和接收数据。我们可以使用write()函数发送数据,使用readyRead()信号和read()函数接收数据。 通过这种方式,我们可以在服务端客户端之间进行双向的数据通信服务端可以同时接受多个客户端的连接,每个客户端都可以和服务端进行独立的数据交互。 总的来说,使用Qt实现TCP服务端客户端通信非常方便。通过使用QTcpServer和QTcpSocket类,我们可以轻松地建立连接,发送和接收数据。这种通信方式可以应用于多种场景,如实时聊天、远程控制等。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陈学弟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值