Qt 网络编程
QT 网络编程
TCP 编程
模块引入
QT += network

头文件
#include <QTcpServer> // TCP服务器端使用
#include <QTcpSocket> // TCP服务器和客户端都使用
编程流程
服务端
1)实例化 QTcpServer 对象 -----------------------------> socket
 2)进入监听状态 ----> listen(QTcpServer类) // 不需要再绑定了----------->bind + listen
 3)监测客户端连接 ---- newConnection 信号(QTcpServer类)
 ----------------> 有新连接过来,server 就能收到 newConnection 信号
 4)QTcpSocket *client <---- 获得连接 ---- nextPendingConnection(QTcpServer类) ---->accept
 5)连接对端接收信号 ------ readyRead(QTcpSocket类)
 ---------------------->如果对端有数据发送,server 就能收到 readyRead 信号
 6)读取客户端消息 ------ readAll(QTcpSocket类) --------------------------> recv:读取数据
 7)发送数据 ------ write(QTcpSocket类) ----> send:发数据
 8)关闭连接 ------ disconnectFromHost() -------------------> close
 
 
 
客户端
1)实例化 QTcpSocket 对象;
 2)连接服务器 ------ connectToHost ------> 接下来使用 waitForConnected 来判断是否连接成功
 3)连接对端接收信号 ------ readyRead 信号
 4)发送数据 ------ write()
 5)关闭连接 ------ disconnectFromHost()
 
 
💡 客户端实现
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QtWidgets>
#include <QTcpSocket>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
    Q_OBJECT
public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();
private slots:
    void on_connectBtn_clicked();
    void recvSlot();
    void on_sendBtn_clicked();
//    void whetherConnectedSlot();		// 判断是否连接成功,方法二
private:
    Ui::Widget *ui;
    QTcpSocket *client;
    bool flag;
};
#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);
    this->setWindowTitle("客户端");
    client = new QTcpSocket(this);
    QObject::connect(client, SIGNAL(readyRead()), this,  SLOT(recvSlot()));
// 判断是否连接成功,方法二
//    QObject::connect(client, SIGNAL(connected()), this,  SLOT(whetherConnectedSlot()));
}
Widget::~Widget()
{
    delete ui;
}
// void Widget::whetherConnectedSlot()			// 判断是否连接成功,方法二
// {
//     flag = true;
// }
void Widget::on_connectBtn_clicked()
{
    client->connectToHost(ui->ipEdit->text(), ui->portEdit->text().toShort());
	// 判断是否连接成功,方法一
    if (!client->waitForConnected(1000))           
    {
        qDebug() << "Failed to connect. ";
        return ;
    }
    qDebug() << "Connected successfully! ";
    ui->connectBtn->setText("断开");
}
void Widget::recvSlot()
{
    QByteArray buffer = client->readAll();
    ui->recvEdit->setText(QString::fromLocal8Bit(buffer));
}
void Widget::on_sendBtn_clicked()
{
    QString buffer = ui->sendEdit->toPlainText();
    client->write(buffer.toLocal8Bit());
}

💡 服务器实现
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QtWidgets>
#include <QTcpServer>
#include <QTcpSocket>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
    Q_OBJECT
public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();
private slots:
    void on_connectBtn_clicked();
    void connectSlot();
    void recvSlot();
    void on_sendBtn_clicked();
private:
    Ui::Widget *ui;
    QTcpServer *server;
    QTcpSocket *client;
};
#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);
    server = new QTcpServer(this);
    this->setWindowTitle("服务器");
    // 这个信号触发,代表有客户端连接
    QObject::connect(server, SIGNAL(newConnection()), this,  SLOT(connectSlot()));
}
Widget::~Widget()
{
    delete ui;
}
void Widget::on_connectBtn_clicked()
{
    // 监听是否有客户端连入,不阻塞等待
    if (!server->listen(QHostAddress::Any, ui->portEdit->text().toUShort()))
    {
        qDebug() << "Failed to listen. ";
        return ;
    }
    ui->connectBtn->setText("关闭");
}
void Widget::connectSlot()
{
    // 接受新的客户端连接
    client = server->nextPendingConnection();
    if (client == 0)
    {
        qDebug() << "There are no pending connections. ";
        return ;
    }
    // 一定要等到接受连接后,再去做客户端的信号连接
    QObject::connect(client, SIGNAL(readyRead()), this,  SLOT(recvSlot()));
}
void Widget::recvSlot()
{
    QByteArray buffer = client->readAll();
    // 编码转换:对方必须按照 GBK 格式发送
    ui->recvEdit->setText(QString::fromLocal8Bit(buffer));
}
void Widget::on_sendBtn_clicked()
{
    QString buffer = ui->sendEdit->toPlainText();	// 从textEdit中获取的内容一定是utf8编码
    client->write(buffer.toLocal8Bit());
}

💡 服务器与客户端交互

UDP 编程
模块引入
QT += network

头文件
#include
编程流程
1)实例化 QUdpSocket 对象 ------------------------------------------> socket
 2)绑定地址、端口 ------ bind(QHostAddress::LocalHost,8888) -----> bind
 3)收发报文 ------ readDatagram、writeDatagram ------------------> recvfrom/sendto
 
// 类和接口
bool 	QUdpSocket::hasPendingDatagrams() const;
qint64 	QUdpSocket::readDatagram(char * data, qint64 maxSize, QHostAddress * address = 0, quint16 * port = 0);
qint64 	QUdpSocket::writeDatagram(const char * data, qint64 size, const QHostAddress & address, quint16 port);
实现一个聊天功能,使用 UDP 通信。首先通过一个登录界面,输入服务器的 IP 和端口,点击登录后,将 IP 和端口传到聊天界面,然后通过 UDP 进行聊天(服务器)。
💡 服务器实现

chatpage.h
#ifndef CHATPAGE_H
#define CHATPAGE_H
#include <QtWidgets>
#include <QUdpSocket>
#include "globalvalue.h"
namespace Ui {
class ChatPage;
}
class ChatPage : public QWidget
{
    Q_OBJECT
public:
    explicit ChatPage(QWidget *parent = 0);
    ~ChatPage();
private:
    Ui::ChatPage *ui;
    QUdpSocket *socket;
    QHostAddress sender;        // 定义对端的地址,以便后续发送使用
    quint16 senderPort;
private slots:
    void readPendingDatagrams();
    void on_sendBtn_clicked();
};
#endif // CHATPAGE_H
chatpage.cpp
#include "chatpage.h"
#include "ui_chatpage.h"
ChatPage::ChatPage(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::ChatPage)
{
    ui->setupUi(this);
    this->setWindowTitle("聊天");
    // 初始化一个 QUdpSocket 对象
    socket = new QUdpSocket(this);
    // 绑定服务器的地址和IP,客户端省略此句
    socket->bind(QHostAddress(GlobalValue::ipaddr), GlobalValue::port);
    connect(socket, SIGNAL(readyRead()), this, SLOT(readPendingDatagrams()));
}
ChatPage::~ChatPage()
{
    delete ui;
}
void ChatPage::readPendingDatagrams()
{
    // 如果udp缓冲区有报文数据的话
    while (socket->hasPendingDatagrams())
    {
        QByteArray datagram;    // 初始化一个字节流缓冲区
        datagram.resize(socket->pendingDatagramSize());		// 重设缓冲区的大小
        socket->readDatagram(datagram.data(), datagram.size(), &sender, &senderPort);
        // 对方发送的字节流必须是GBK编码
        ui->recvEdit->setText(QString::fromLocal8Bit(datagram));
    }
}
void ChatPage::on_sendBtn_clicked()
{
    // 如果已经接收过消息,那么sender和senderPort已经有对方的地址了
    socket->writeDatagram(ui->sendEdit->toPlainText().toLocal8Bit(), sender, senderPort);
}

globalvalue.h
#ifndef GLOBALVALUE_H
#define GLOBALVALUE_H
#include <QString>
class GlobalValue           // 此类仅用于存放静态变量
{
public:
    GlobalValue();
    static QString ipaddr;
    static quint16 port;
};
#endif // GLOBALVALUE_H
globalvalue.cpp
#include "globalvalue.h"
QString GlobalValue::ipaddr;
quint16 GlobalValue::port;
GlobalValue::GlobalValue()
{
}
userver.h
#ifndef USERVER_H
#define USERVER_H
#include <QtWidgets>
#include "chatpage.h"
#include "globalvalue.h"
namespace Ui {
class UServer;
}
class UServer : public QWidget
{
    Q_OBJECT
public:
    explicit UServer(QWidget *parent = 0);
    ~UServer();
private slots:
    void on_pushButton_clicked();
private:
    Ui::UServer *ui;
    ChatPage *chatting;
};
#endif // USERVER_H
userver.cpp
#include "userver.h"
#include "ui_userver.h"
UServer::UServer(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::UServer)
{
    ui->setupUi(this);
    this->setWindowTitle("登录");
}
UServer::~UServer()
{
    delete ui;
}
void UServer::on_pushButton_clicked()
{
    GlobalValue::ipaddr = ui->ipEdit->text();
    GlobalValue::port = ui->portEdit->text().toUShort();
    chatting = new ChatPage;
    chatting->show();   // 初始化一个新的界面,然后进行跳转
    this->close();
}
运行效果如下:
 
 
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!