Qt网络编程

TCP服务端

TCP通信过程

三次握手 四次挥手

连接:
Client → Server:SYN
Server→Client:SYN、ACK Client→Server:ACK

断开:
主动断开方 :FIN、ACK
被动断开方:ACK
Server→Client:FIN、ACK Client→Server:ACK

要在pro中加入 network,才能使用对应的头文件

QtTcp通信模型

需要掌握的接口
  • connectToHost(const QHostAddress &address, quint16 port,…
  • bool waitForConnected(int msecs = 30000)
  • bool waitForReadyRead(int msecs = 30000)
  • void disconnectFromHost()
  • void connected()
  • void disconnected()
  • void readyRead()
  • void bytesWritten(qint64 bytes)

服务端Demo

服务端

  • widget.h
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QTcpServer>
#include <QTcpSocket>
#include <QNetworkAccessManager> // 找网卡
#include <QNetworkInterface> // 找网卡
#include <QMessageBox>
#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 slots:
    void on_pushButtonListen_clicked();
    void newConnectSlot();
    void readyReadSlot();

private:
    void enumIpAddress();

private:
    Ui::Widget *ui;
    QTcpServer *server;
    QTcpSocket *socket; // socket不是new出来的
};
#endif // WIDGET_H

  • Widget.cpp
#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent),
      ui(new Ui::Widget),
      server(new QTcpServer)
{
    ui->setupUi(this);
    enumIpAddress();
    connect(server,SIGNAL(newConnection()),
            this,SLOT(newConnectSlot()));
}

Widget::~Widget()
{
    delete ui;
}

void Widget::enumIpAddress()
{
    // 枚举网卡
    QList<QHostAddress> list = QNetworkInterface::allAddresses();
    QStringList ipAddress;
    foreach (QHostAddress address, list) {
        if(address.isNull())
        {
            continue;
        }
        // 网络层协议 过滤IPV6
        QAbstractSocket::NetworkLayerProtocol protocol =
                address.protocol();
        if(protocol == QAbstractSocket::IPv4Protocol)
        {
            QHostAddress ipv4 = address;
            qDebug()<< ipv4.toString();
            ipAddress.append(address.toString());
            //            ui->comboBox->addItem(address.toString());
        }
        ui->comboBoxAddress->addItems(ipAddress);
    }
}


void Widget::on_pushButtonListen_clicked()
{
    QString serverAddressStr;
    QHostAddress serverAddress; // 需要监听的网咖ip
    quint16 serverPort;

    serverAddressStr = ui->comboBoxAddress->currentText();
    serverAddress = QHostAddress(serverAddressStr);
    serverPort = ui->lineEditPort->text().toInt();

    // 判断server的状态
    if(!server->isListening())
    {
        // 已经监听的不能在监听
        if(!server->listen(serverAddress,serverPort))
        {
            qDebug()<<"Tcp server listen error!" << server->errorString();
            QMessageBox::warning(this,"",server->errorString());
        }
        else
        {
            qDebug()<<"listen OK!";
            ui->pushButtonListen->setText(("停止监听"));
        }
    }
    else
    {
        server->close();
        ui->pushButtonListen->setText(("启用监听"));
    }
}

void Widget::newConnectSlot()
{
    QHostAddress clientIpAddress; // 客户段地址
    quint16 clientPort;

    // 得到与客户端通信的socket
    socket = server->nextPendingConnection();

    // 得到ip地址
    clientIpAddress= socket->peerAddress();

    // 得到端口
    clientPort = socket->peerPort();

    ui->textBrowserClientInfo->append("client Address" +
                                      clientIpAddress.toString());
    ui->textBrowserClientInfo->append("client Port"+
                                      QString::number(clientPort));

    connect(socket, SIGNAL(readyRead()),
            this,SLOT(readyReadSlot()));
}

void Widget::readyReadSlot()
{
    QByteArray recvData;

    recvData = socket->readAll();

    ui->textBrowserRecv->append(QString(recvData));
}

客户端Demo

客户端

  • widget.h
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QTcpSocket>
#include <QMessageBox>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

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

private slots:
    void on_pushButton_date_clicked();

    void on_pushButton_connect_clicked();

    void connectedSlot();

    void disconnectedSlot();

    void readyReadSlot();

    void bytesWrittenSlot(qint64 bytes);

private:
    Ui::Widget *ui;

    QTcpSocket *  socket;

    bool socketState;
};
#endif // WIDGET_H

  • widget.cpp
#include "widget.h"
#include "ui_widget.h"

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


    connect(socket, SIGNAL(connected()),
            this, SLOT(connectedSlot()));

    connect(socket, SIGNAL(disconnected()),
            this, SLOT(disconnectedSlot()));

    connect(socket, SIGNAL(readyRead()),
            this, SLOT(readyReadSlot()));

    connect(socket, SIGNAL(bytesWritten(qint64)),
            this, SLOT(bytesWrittenSlot(qint64)));
}

Widget::~Widget()
{
    if(socket->isOpen())
        socket->close();
    delete socket;
    delete ui;
}

void Widget::connectedSlot()
{
    qDebug()<<"connectedSlot";

}

void Widget::disconnectedSlot()
{
    qDebug()<<"disconnectedSlot";
    ui->pushButton_connect->setText(QStringLiteral("连接服务器"));
    socketState = false;
}


void Widget::readyReadSlot()
{
    qDebug()<<"readyReadSlot";

    QByteArray dataBa = socket->readAll();
    int recvNum = dataBa.size();

    ui->textBrowserRecv->append(QString(dataBa));
    ui->lineEditRecvTotal->setText(QString::number(recvNum));
}

/* 统计写了多少数据 */
void Widget::bytesWrittenSlot(qint64 bytes)
{
    qDebug()<<"bytesWrittenSlot";

    ui->lineEditSendTotal->setText(QString::number(bytes));
}

void Widget::on_pushButton_date_clicked()
{
    QString dataStr = ui->textEditSend->toPlainText();
    QByteArray data = dataStr.toUtf8();

    if(socket->isOpen() && socket->isValid())
    {
        socket->write(data);
    }
    else
    {
        QMessageBox::warning(this, "socket  error", socket->errorString());
    }
}


void Widget::on_pushButton_connect_clicked()
{
    QString ipAddressStr = ui->lineEditAddress->text();
    qint16 port = ui->lineEditPort->text().toInt();

    if(!socketState)
    {
        socket->connectToHost(ipAddressStr, port);
        if(socket->waitForConnected(1000))
        {
            qDebug()<<"Connect2Server Ok";
            ui->pushButton_connect->setText(QStringLiteral("断开连接"));
            socketState = true;
        }
        else
        {
            qDebug()<<socket->errorString();
            //
            return;
        }
    }
    else
    {
        socket->close();
    }
}


信号与槽的最后一个参数(信号与槽的连接方式)

方式描述
Qt::AutoConnection0默认参数;自动连接, 自动选择是Direct或者Queued
Qt::DirectConnection1槽函数立即执行,槽与信号在同一线程中执行
Qt::QueuedConnection2槽函数排队执行,槽函数在接收方的对象所在的线程中执行
Qt::BlockingQueuedConnection3阻塞式排队连接
Qt::UniqueConnection4一对一的自动连接

UDP

单播

发送数据不用绑定,只要知道接收端的IP和端口即可;
接收数据一定要绑定;

QString str = QString("[%1 : %2 : %3]")
.arg(sender.toString())
.arg(port)
.arg(dataBuf);

广播

255.255.255.255

组播Demo

服务端

组播地址是D类地址
1、绑定 2、加入组播 3、接收

  • widget.h
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QUdpSocket>
#include <QNetworkAccessManager>  //找网卡
#include <QNetworkInterface> //找网卡
#include <QHostAddress>
#include <QDebug>

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();

private:
    void enumIpAddress();

public slots:
    void processRecvGroupSlot();
private slots:
    void on_pushButtonBind_clicked();

private:
    Ui::Widget *ui;

    QUdpSocket *udpSocket;
    QHostAddress localAddress;
    quint16 localPort;
};

#endif // WIDGET_H

  • widget.cpp
#include "widget.h"
#include "ui_widget.h"

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

    this->enumIpAddress();

}

void Widget::enumIpAddress()
{
    QList<QHostAddress> list = QNetworkInterface::allAddresses();
    QStringList addrList;
    foreach (QHostAddress address, list)
    {
        if(address.isNull())
            continue;

        //网络层协议 过滤只剩下IPV4的地址
        QAbstractSocket::NetworkLayerProtocol protocol = address.protocol();
        if(protocol != QAbstractSocket::IPv4Protocol)
            continue;

        QHostAddress ipAddress =  address;
        qDebug() << ipAddress.toString();
        addrList.append(ipAddress.toString());
    }

    ui->comboBoxLocalAddress->addItems(addrList);
}

void Widget::processRecvGroupSlot()
{
    QHostAddress remoteIpAddress;
    quint16 remotePort;
    QByteArray recvData;
    while (udpSocket->hasPendingDatagrams())
    {
        remoteIpAddress = udpSocket->peerAddress();
        remotePort = udpSocket->peerPort();
        ui->lineEditRemoteIpAddress->setText(remoteIpAddress.toString());
        ui->lineEditPort->setText(QString::number(remotePort));

        recvData = udpSocket->readAll();
        qDebug() << "data in..." << recvData;
    }
}


Widget::~Widget()
{
    delete ui;
}

void Widget::on_pushButtonBind_clicked()
{
    localAddress = QHostAddress(ui->comboBoxLocalAddress->currentText());
    localPort = ui->lineEditPort->text().toInt();

    if(!udpSocket->bind(localAddress, localPort))
    {
        qDebug()<<"udpSocket->bind"<<udpSocket->errorString();
        return;
    }

    connect(udpSocket, SIGNAL(readyRead()),
            this, SLOT(processRecvGroupSlot()));
}

客户端

  • widget.h
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QUdpSocket>

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();

private slots:
    void on_pushButton_clicked();

private:
    Ui::Widget *ui;
    QUdpSocket udpSocket;
};

#endif // WIDGET_H
  • widget.cpp
#include "widget.h"
#include "ui_widget.h"

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

Widget::~Widget()
{
    delete ui;
}

void Widget::on_pushButton_clicked()
{
    //((const char *)&m_HeadBits,QHostAddress(MCAST_ADDR), STATUS_PORT);
    udpSocket.writeDatagram("www.baidu.com",
                            QHostAddress(ui->lineEditSenderIpAddress->text()),
                            ui->lineEditSenderPort->text().toInt());

}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

√沫影

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

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

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

打赏作者

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

抵扣说明:

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

余额充值