qt之网络协议

tcp:

// -------------- widget.h:

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QTcpServer> //服务器
#include <QTcpSocket> // 套接字 发送的消息

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

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

    QTcpServer* _tcpServer = NULL;
    QTcpSocket* _tcpSocket = NULL;

private slots:
    void on_pushButton_clicked();

    void on_pushButton_2_clicked();

private:
    Ui::Widget *ui;
};

#endif // WIDGET_H

// -------------- widget.cpp:

#include "widget.h"
#include "ui_widget.h"
#include <QHostAddress>

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

    setWindowTitle("服务端:8888");

    //_tcpSocket = new QTcpSocket(this);
    _tcpServer = new QTcpServer(this);
    _tcpServer->listen(QHostAddress::Any,8888);             // 服务第的ip和端口

    connect(_tcpServer, &QTcpServer::newConnection, [=](){  // 有人连接时触发
        _tcpSocket = _tcpServer->nextPendingConnection();   // 获取对方套接字,包含对方的基础信息
        QString ip = _tcpSocket->peerAddress().toString();  // 通过套接字获取对方的iP
        qint16 port = _tcpSocket->peerPort();               // 通过套接字获取对方的端口

        QString temp = QString("[%1:%2]:成功连接").arg(ip).arg(port);
        ui->textEdit->setText(temp);

        connect(_tcpSocket,&QTcpSocket::readyRead,[=](){    // 接收消息,对方连接我成功后方可接收
            QByteArray array = _tcpSocket->readAll();
            ui->textEdit->append(array);
        });

    });


}

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

void Widget::on_pushButton_clicked()                //给客户端发数据
{
    if(_tcpSocket == NULL) return;

    QString str = ui->textEdit_2->toPlainText();

    _tcpSocket->write(str.toUtf8().data());
}

void Widget::on_pushButton_2_clicked()              // 和客户端断开连接
{
    if(_tcpSocket == NULL) return;

    _tcpSocket->disconnectFromHost();
    _tcpSocket->close();

    _tcpSocket = NULL;
}


// -------------- socket.h:

#ifndef SOCKET_H
#define SOCKET_H

#include <QWidget>
#include <QTcpSocket>

namespace Ui {
class socket;
}

class socket : public QWidget
{
    Q_OBJECT

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

    QTcpSocket* _tcpSocket = NULL;

private slots:
    void on_pushButton_2_clicked();

    void on_pushButton_3_clicked();

    void on_pushButton_clicked();

private:
    Ui::socket *ui;
};

#endif // SOCKET_H

// -------------- socket.cpp:

#include "socket.h"
#include "ui_socket.h"
#include <QHostAddress>

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

    _tcpSocket = new QTcpSocket(this);                      // 分配空间,指定父对象

    connect(_tcpSocket,&QTcpSocket::connected,[=](){        // 和服务器连接时触发
        ui->textEdit->setText("成功和服务器连接");

        connect(_tcpSocket,&QTcpSocket::readyRead,[=](){    // 接收消息,这里写在外面也没关系,反正_tcpSocket接收到消息了就触发
            QByteArray array = _tcpSocket->readAll();
            ui->textEdit->append(array);
        });
    });
}

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

void socket::on_pushButton_clicked()                         // 连接服务器
{
    QString ip = ui->lineEdit->text();
    qint16 port = ui->lineEdit_2->text().toInt();

    _tcpSocket->connectToHost(QHostAddress(ip),port);
}

void socket::on_pushButton_2_clicked()                       // 发送数据
{
    if(_tcpSocket == NULL) return;

    QString str = ui->textEdit_2->toPlainText();

    _tcpSocket->write(str.toUtf8().data());
}

void socket::on_pushButton_3_clicked()                         // 断开连接
{
    if(_tcpSocket == NULL) return;

    _tcpSocket->disconnectFromHost();
    _tcpSocket->close();

    _tcpSocket = NULL;
}
基础示例

 

// ----------------------- widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QTcpServer> //服务器
#include <QTcpSocket> // 套接字 发送的消息
#include <QFile>
#include <QTimer>

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

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

    QTcpServer* _tcpServer = NULL;
    QTcpSocket* _tcpSocket = NULL;

    QFile file;
    QString fileName;
    qint64 fileSize;
    qint64 sendSize;

    QTimer timer;

    void sendData();

private slots:
    void on_pushButton_clicked();

    void on_pushButton_2_clicked();

private:
    Ui::Widget *ui;
};

#endif // WIDGET_H


// ----------------------- widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include <QFileDialog>
#include <QDebug>
#include <QFileInfo> // 获取文件信息


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

    setWindowTitle("服务端:8888");

    // 没连接时按钮不能按
    ui->pushButton->setEnabled(false);
    ui->pushButton_2->setEnabled(false);

    //_tcpSocket = new QTcpSocket(this);
    _tcpServer = new QTcpServer(this);
    _tcpServer->listen(QHostAddress::Any,8888);                 // 服务第的ip和端口

     connect(_tcpServer, &QTcpServer::newConnection, [=](){     // 有人连接时触发
            _tcpSocket = _tcpServer->nextPendingConnection();   // 获取对方套接字,包含对方的基础信息
            QString ip = _tcpSocket->peerAddress().toString();  // 通过套接字获取对方的iP
            qint16 port = _tcpSocket->peerPort();               // 通过套接字获取对方的端口

            QString temp = QString("[%1:%2]:成功连接").arg(ip).arg(port);
            ui->textEdit->setText(temp);

            // 成功连接时选择文件按钮恢复
            ui->pushButton->setEnabled(true);

            connect(_tcpSocket,&QTcpSocket::readyRead,[=](){           // 服务端收到消息
                QByteArray array = _tcpSocket->readAll();
                if(QString(array) == "file done"){
                    ui->textEdit->append("文件发送完毕");
                    file.close();

                    _tcpSocket->disconnectFromHost();
                    _tcpSocket->close();
                }
            });

     });





     connect(&timer,&QTimer::timeout,[=](){ timer.stop();sendData(); });
}

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

void Widget::on_pushButton_clicked()                //选择文件
{
    QString filePath = QFileDialog::getOpenFileName(this,"open","../");
    if(filePath.isEmpty()) return;

    // 获取文件信息
    fileName.clear();
    fileSize = 0;

    QFileInfo info(filePath);
    fileName = info.fileName();
    fileSize = info.size();
    sendSize = 0;

    // 打开文件
    file.setFileName(filePath);
    bool isOk = file.open(QIODevice::ReadOnly);
    if(!isOk) qDebug() << "只读方式打开文件失败";

    ui->textEdit->append(filePath);
    ui->pushButton->setEnabled(false);
    ui->pushButton_2->setEnabled(true);             // 选好了文件后,发送按钮打开
}


void Widget::on_pushButton_2_clicked()                  // 发送文件
{
    // 先发送头部信息 文件名##文件大小
    QString head = QString("%1##%2").arg(fileName).arg(fileSize);

    qint64 len = _tcpSocket->write(head.toUtf8());
    if(len > 0){                                        // 头部信息发送成功

        // 发送真正的文件数据。但为了防止TCP黏包,所以这里通过定时器延时20ms后再发送文件数据,保证头部信息发完了先
        timer.start(20);

    }else{
        qDebug() << "头部信息发送失败";
        file.close();
        ui->pushButton->setEnabled(true);
        ui->pushButton_2->setEnabled(false);
    }

}

void Widget::sendData(){

    ui->textEdit->append("文件开始发送...");

    qint64 len2 = 0;
    do{
        len2 = 0;                                   // 和len一样判断当前实际读了或者发送了多少数据
        char buf[4*1024] = {0};                     // 每次发送4k

        len2 = file.read(buf,sizeof(buf));          // 把文件数据读到buf里,读4k的内容

        _tcpSocket->write(buf,len2);                // 发送数据,读多少(看len2),发多少

        sendSize += len2;

    }while(len2 > 0);                                // len2小于等于0了,表示没有读到数据了

//    if(sendSize == fileSize){
//        ui->textEdit->append("文件发送完毕");
//        file.close();

//        _tcpSocket->disconnectFromHost();
//        _tcpSocket->close();
//    }
}


// ----------------------- socket.h

#ifndef SOCKET_H
#define SOCKET_H

#include <QWidget>
#include <QTcpSocket>
#include <QFile>

namespace Ui {
class socket;
}

class socket : public QWidget
{
    Q_OBJECT

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

    QTcpSocket* _tcpSocket = NULL;

    QFile file;
    QString fileName;
    qint64 fileSize;
    qint64 recvSize;

    bool isHead = true;

private slots:
    void on_pushButton_clicked();

private:
    Ui::socket *ui;
};

#endif // SOCKET_H


// ----------------------- socket.cpp

#include "socket.h"
#include "ui_socket.h"
#include <QDebug>
#include <QMessageBox>
#include <QHostAddress>

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

    setWindowTitle("客户端");

    ui->progressBar->setValue(0);

    _tcpSocket = new QTcpSocket(this);

    connect(_tcpSocket,&QTcpSocket::readyRead,[=](){        // 接收消息,我连接对方成功后方可接收

        QByteArray array = _tcpSocket->readAll();           // 取出数据

        if(isHead){                                         // 一开肯定是头,故isHead默认为true
            isHead = false;

            // 解析头部信息
            fileName = QString(array).section("##",0,0);    // section("##",0,0),以##分割成一段一段的,这里0段开始0段结束
            fileSize = QString(array).section("##",1,1).toInt();
            recvSize = 0;

            // 打开文件,根据解析得到的文件名写文件,这里执行一次即可,具体在下面写
            file.setFileName(fileName);
            bool isOk = file.open(QIODevice::WriteOnly);
            if(!isOk) {
                qDebug() << "写文件失败";
                _tcpSocket->disconnectFromHost();
                _tcpSocket->close();
                return;
            }

            // 弹出对话框,显示接收到了文件xinx
            //QString str = QString("接收的文件:[%1: %2kb]").arg(fileName).arg(fileSize/1024);
            //QMessageBox::information(this,"文件信息",str);

            // 设置进度条
            ui->progressBar->setMinimum(0);                  //最小值
            ui->progressBar->setMaximum(fileSize/1024);      //最大值
            ui->progressBar->setValue(0);                    // 当前值

        }else{                                               // 具体信息
            qint64 len = file.write(array);                  // 把具体信息写成文件

            if(len > 0) recvSize += len;

            ui->progressBar->setValue(recvSize/1024);        // 更新进度条

            if(recvSize == fileSize){

                //qDebug() << "998";
                _tcpSocket->write("file done");              // 告诉服务器我接收完了

                file.close();
                QMessageBox::information(this,"完成","文件接收完成");   // 把接收的都写完了

                _tcpSocket->disconnectFromHost();
                _tcpSocket->close();
            }
        }

    });

    //connect(_tcpSocket,&QTcpSocket::connected,[=](){   });
}

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

void socket::on_pushButton_clicked()            //连接服务器
{
    QString ip = ui->lineEdit->text();
    quint16 port = ui->lineEdit_2->text().toInt();

    _tcpSocket->connectToHost(QHostAddress(ip), port);
}
传输文件

 

udp:

// ------------ 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();

    QUdpSocket* udp;

private:
    Ui::Widget *ui;
};

#endif // WIDGET_H



// ------------ widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include <QHostAddress>

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

    // 报文和套接字都是消息,只是协议在套接字里多放了一些东西

    ui->lineEdit->setText("8888");
    ui->lineEdit_2->setText("9999");
    ui->lineEdit_3->setText("127.0.0.1");

    udp = new QUdpSocket(this);                     // 创建套接字
    udp->bind(ui->lineEdit->text().toInt());        // 绑定自己的端口

    connect(ui->pushButton,&QPushButton::clicked,[=](){ // 发送报文(消息)

        udp->writeDatagram(ui->textEdit_2->toPlainText().toUtf8(),QHostAddress(ui->lineEdit_3->text()),ui->lineEdit_2->text().toInt());

        ui->textEdit->append("my say: "+ui->textEdit_2->toPlainText());

        ui->textEdit_2->clear();
    });

    connect(udp,&QUdpSocket::readyRead,[=](){       // 接收报文(消息)

        qint64 size = udp->pendingDatagramSize(); // 报文长度
        QByteArray array = QByteArray(size,0);  // 构造时初始化长度和数据 size个0

        udp->readDatagram(array.data(), size); // 读到数据放到array

        ui->textEdit->append("to say: "+array);
    });
}

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


// ------------ upd2.h

#ifndef UDP2_H
#define UDP2_H

#include <QWidget>
#include <QUdpSocket>


namespace Ui {
class udp2;
}

class udp2 : public QWidget
{
    Q_OBJECT

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

     QUdpSocket* udp;

private:
    Ui::udp2 *ui;
};

#endif // UDP2_H


// ------------ upd2.cpp

#include "udp2.h"
#include "ui_udp2.h"

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

    // 报文和套接字都是消息,只是协议在套接字里多放了一些东西

    ui->lineEdit->setText("9999");
    ui->lineEdit_2->setText("8888");
    ui->lineEdit_3->setText("127.0.0.1");

    udp = new QUdpSocket(this);                     // 创建套接字
    udp->bind(ui->lineEdit->text().toInt());        // 绑定自己的端口

    connect(ui->pushButton,&QPushButton::clicked,[=](){ // 发送报文(消息)

        udp->writeDatagram(ui->textEdit_2->toPlainText().toUtf8(),QHostAddress(ui->lineEdit_3->text()),ui->lineEdit_2->text().toInt());

        ui->textEdit->append("my say:"+ui->textEdit_2->toPlainText());

        ui->textEdit_2->clear();
    });

    connect(udp,&QUdpSocket::readyRead,[=](){       // 接收报文(消息)

        qint64 size = udp->pendingDatagramSize(); // 报文长度
        QByteArray array = QByteArray(size,0);  // 构造时初始化长度和数据 size个0

        udp->readDatagram(array.data(), size); // 读到数据放到array

        ui->textEdit->append("to say: "+array);
    });
}

udp2::~udp2()
{
    delete ui;
}
基础示例

 

posted @ 2022-08-28 19:45  封兴旺  阅读(56)  评论(0编辑  收藏  举报

联系方式: 18274305123(微信同号)