QT/C++——网络编程

时间:2023-02-02 22:56:28

目录

一、基础知识复习

二、UDP

客户端:

服务器:

三、TCP

服务器:

客户端:

四、小项目

客户端:

服务器:


一、基础知识复习

这部分内容前面讲的比较详细,现在就是简单复习一下。

QT/C++——网络编程

两台主机之间通信要经过封包他有一堆包头

QT/C++——网络编程 

QT/C++——网络编程

TCP、UDP都是基于套接字,C写我感觉已经挺简单了,老师说C++更简单,我们往下学学看。

二、UDP

QT/C++——网络编程

网络编程这块要在工程文件中加上network

服务器是被动套接字,客户端是主动套接字

QT/C++——网络编程

客户端:

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QTextEdit>
#include <QLineEdit>
#include <QPushButton>
#include <QUdpSocket>
#include <QHostAddress>

class Widget : public QWidget
{
    Q_OBJECT
public slots:
    void senddata()
    {
        udpsock->writeDatagram(le->text().toStdString().c_str(), QHostAddress("192.168.3.27"), 8888);
    }

    void recvdata()
    {
        QByteArray datagram;
        datagram.resize(udpsock->pendingDatagramSize());
        QHostAddress sender;
        quint16 senderPort;

        udpsock->readDatagram(datagram.data(), datagram.size(),
                                          &sender, &senderPort);
        te->append(datagram);
    }
public:
    Widget(QWidget *parent = 0);
    ~Widget();
private:
    QTextEdit *te;
    QLineEdit *le;
    QPushButton *pb;

    QUdpSocket *udpsock;
};

#endif // WIDGET_H
#include "widget.h"
#include <QVBoxLayout>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    te = new QTextEdit;
    le = new QLineEdit;
    pb = new QPushButton("send");
    QVBoxLayout *vbox = new QVBoxLayout;
    vbox->addWidget(te);
    vbox->addWidget(le);
    vbox->addWidget(pb);
    setLayout(vbox);

    udpsock = new QUdpSocket;

    connect(pb, SIGNAL(clicked(bool)), this, SLOT(senddata()));
    connect(udpsock, SIGNAL(readyRead()), this, SLOT(recvdata()));
}

Widget::~Widget()
{

}

服务器:

#ifndef UDPSERVER_H
#define UDPSERVER_H

#include <QObject>
#include <QUdpSocket>
#include <QDebug>

class udpServer : public QObject
{
    Q_OBJECT
public:
    explicit udpServer(QObject *parent = 0);
    void init()
    {
        udpSocket = new QUdpSocket(this);
        udpSocket->bind(QHostAddress::AnyIPv4, 8888);

        connect(udpSocket, SIGNAL(readyRead()),
                      this, SLOT(readPendingDatagrams()));
        qDebug()<<"init....";
    }
signals:

public slots:
    void readPendingDatagrams()
    {
        while (udpSocket->hasPendingDatagrams()) {
                  QByteArray datagram;
                  datagram.resize(udpSocket->pendingDatagramSize());
                  QHostAddress sender;
                  quint16 senderPort;

                  udpSocket->readDatagram(datagram.data(), datagram.size(),
                                          &sender, &senderPort);

                  //processTheDatagram(datagram);
                  qDebug()<<"recv: "<<datagram;

                  udpSocket->writeDatagram(datagram.data(), datagram.size(),
                                           sender, senderPort);
              }
    }

private:
    QUdpSocket *udpSocket;
};

#endif // UDPSERVER_H

两个程序的工程文件中一定要加入network

三、TCP

QT/C++——网络编程

服务器:

#ifndef TCPSERVER_H
#define TCPSERVER_H

#include <QObject>
#include <QTcpServer>
#include <QTcpSocket>
#include <QDebug>

class tcpServer : public QObject
{
    Q_OBJECT
public:
    explicit tcpServer(QObject *parent = 0);

signals:

public slots:
    void newconnected()
    {
        qDebug()<<"connected";
        clientsock = ser->nextPendingConnection();

        connect(clientsock, SIGNAL(readyRead()), this, SLOT(readdata()));
    }

    void readdata()
    {
        QByteArray buf =  clientsock->readAll();
        qDebug()<<"recv: "<<buf;
        clientsock->write(buf);
    }

private:
    QTcpServer *ser;
    QTcpSocket *clientsock;

};

#endif // TCPSERVER_H
#include "tcpserver.h"
#include <QHostAddress>

tcpServer::tcpServer(QObject *parent) : QObject(parent)
{
    ser = new QTcpServer;
    ser->listen(QHostAddress::AnyIPv4, 8888);
    connect(ser, SIGNAL(newConnection()), this, SLOT(newconnected()));

    ser->waitForNewConnection();
}

客户端:

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QTextEdit>
#include <QLineEdit>
#include <QPushButton>
#include <QTcpSocket>

class Widget : public QWidget
{
    Q_OBJECT
public slots:
    void senddata()
    {
        tcpsocket->write(le->text().toStdString().c_str());
    }

    void recvdata()
    {
        QByteArray buf = tcpsocket->readAll();
        te->append(buf);
    }
public:
    Widget(QWidget *parent = 0);
    ~Widget();
private:
    QTextEdit *te;
    QLineEdit *le;
    QPushButton *pb;

    QTcpSocket *tcpsocket;
};

#endif // WIDGET_H
#include "widget.h"
#include <QVBoxLayout>
#include <QHostAddress>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    te = new QTextEdit;
    le = new QLineEdit;
    pb = new QPushButton("send");

    QVBoxLayout *vbox = new QVBoxLayout;
    vbox->addWidget(te);
    vbox->addWidget(le);
    vbox->addWidget(pb);
    setLayout(vbox);

    tcpsocket = new QTcpSocket;
    //connect to server
    tcpsocket->connectToHost(QHostAddress("192.168.3.27"), 8888);

    connect(pb, SIGNAL(clicked(bool)), this, SLOT(senddata()));
    connect(tcpsocket, SIGNAL(readyRead()), this, SLOT(recvdata()));
}

Widget::~Widget()
{

}

四、小项目

实现一个类似于监控的东西

就是把传输内容换成了照片

客户端:

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QLabel>
#include <QLineEdit>
#include <QTcpSocket>
#include <QPushButton>
#include <QHostAddress>
#include <QDebug>
#include <QPixmap>

class Widget : public QWidget
{
    Q_OBJECT

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

public slots:
    void startv()
    {
        readsize = true;

        sockv = new QTcpSocket(this);
        connect(sockv, SIGNAL(readyRead()), this, SLOT(recv_show()));
        sockv->connectToHost(QHostAddress(leip->text()), atoi(leport->text().toStdString().c_str()));
        btstart->setText("STOP");
        leip->setDisabled(true);
        leport->setDisabled(true);

        disconnect(btstart, SIGNAL(clicked()), this, SLOT(startv()));
        connect(btstart, SIGNAL(clicked()), this, SLOT(stop()));
    }

    void stop()
    {
        sockv->close();
        sockv->deleteLater();

        disconnect(btstart, SIGNAL(clicked()), this, SLOT(stop()));
        connect(btstart, SIGNAL(clicked()), this, SLOT(startv()));

        leip->setDisabled(false);
        leport->setDisabled(false);
        btstart->setText("START");
    }

    void recv_show()
    {
        if(readsize){ //接收图片大小
            char buf[10] = {0};
            sockv->read(buf, 10);
            picsize = atoi(buf); //转成整形大小值
     //       qDebug()<<picsize;

            readsize = false;
        }
        else
        {
            if(sockv->bytesAvailable() < picsize) //等待图片内容接收完整
                return;

            char buf[640*480*3];
            sockv->read(buf, picsize);
            QPixmap pix;
            pix.loadFromData((uchar*)buf, picsize, "jpeg");
            lbvideo->setPixmap(pix);//切换照片

            readsize = true;
        }

    }

private:
    QLabel *lbvideo, *lbip, *lbport;
    QLineEdit *leip, *leport;
    QPushButton *btstart;

    QTcpSocket *sockv;

    bool readsize;
    int picsize;

};

#endif // WIDGET_H
#include "widget.h"
#include <QHBoxLayout>
#include <QVBoxLayout>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    lbvideo = new QLabel;
    lbvideo->setFixedSize(640,480);
    lbvideo->setScaledContents(true);
    lbip = new QLabel("IP");
    lbport = new QLabel("PORT");

    leip = new QLineEdit("192.168.3.27");
    leport = new QLineEdit("8888");

    btstart = new QPushButton("START");

    QHBoxLayout *hbox = new QHBoxLayout;
    hbox->addWidget(lbip);
    hbox->addWidget(leip);
    hbox->addWidget(lbport);
    hbox->addWidget(leport);
    hbox->addWidget(btstart);

    QVBoxLayout *vbox = new QVBoxLayout;
    vbox->addLayout(hbox);
    vbox->addWidget(lbvideo);

    setLayout(vbox);

    connect(btstart, SIGNAL(clicked()), this, SLOT(startv()));
}

Widget::~Widget()
{

}

服务器:

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QCamera>
#include <QCameraViewfinder>
#include <QCameraImageCapture>
#include <QLabel>
#include <QTimerEvent>
#include <QDebug>
#include <QPixmap>
#include <QTcpServer>
#include <QTcpSocket>
#include <QTemporaryFile>
#include <QFile>
#include <QBuffer>

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = 0);
    ~Widget();
public slots:
    void show_pic(int i, QImage img)
    {

        QPixmap pix(1920, 1080);
#if 1
        pix.fill(Qt::red);
        pix = pix.fromImage(img);
        lb_pic->setPixmap(pix);
#else
        lb_pic->setPixmap(QPixmap::fromImage(img));

#endif
//        qDebug()<<i;


        if(client&&client->isWritable())
        {
//            qDebug()<<"sending "<<pix.size();
#if 0
            pix.save("tem.jpg","jpeg");
//             qDebug()<<"saveed";
            QFile tem("tem.jpg");
            tem.open(QIODevice::ReadOnly);

#else
            QBuffer tem;
            pix.save(&tem, "jpeg");
#endif
            char buf[10] = {0};
 //           qDebug()<<"size: "<<buf;
            sprintf(buf, "%d", tem.size());
  //          qDebug()<<"size: "<<buf;
            client->write(buf, 10);//发大小(大小值先转换成字符串装在固定的10个字节的buff中发送)
  //          qDebug()<<"size ok";
#if 0
            QByteArray data = tem.readAll();           
#else
            QByteArray data(tem.buffer());
#endif
            client->write(data);//发图片内容
   //          qDebug()<<"finish";
             tem.close();
        }
    }

    void accept_client()
    {
        if(NULL != client)
        {
            client->close();
            client->deleteLater();
        }
        client = myserver->nextPendingConnection();
        connect(client, SIGNAL(disconnected()), this, SLOT(client_close()));
    }

    void client_close()
    {
        client->close();
        client->deleteLater();
        client = NULL;
    }
protected:
    virtual void
    timerEvent(QTimerEvent *event)
    {
        imageCapture->capture();
//        qDebug()<<"tttt";
    }

 private:
    QCamera *camera;
    QCameraViewfinder *viewfinder;
    QCameraImageCapture *imageCapture;
    QLabel *lb_pic;

    QTcpServer *myserver;
    QTcpSocket *client;
};

#endif // WIDGET_H
#include "widget.h"
#include <QHBoxLayout>
#include <QHostAddress>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    camera = new QCamera("/dev/video0"); //"/dev/video0" 摄像头设备文件,视情况而定
    viewfinder = new QCameraViewfinder(this);
    viewfinder->setFixedSize(640,480);
    viewfinder->show();

      lb_pic = new QLabel(this);
      myserver = new QTcpServer(this);
      client = NULL;

    camera->setViewfinder(viewfinder);
      QHBoxLayout *hbox = new QHBoxLayout;
        hbox->addWidget(viewfinder);
      hbox->addWidget(lb_pic);

      this->setLayout(hbox);

      imageCapture = new QCameraImageCapture(camera);

      camera->setCaptureMode(QCamera::CaptureStillImage);

      connect(imageCapture, SIGNAL(imageCaptured(int,QImage)), this, SLOT(show_pic(int,QImage)));
      connect(myserver, SIGNAL(newConnection()), this, SLOT(accept_client()));

      this->startTimer(3);
      myserver->listen(QHostAddress::AnyIPv4, 8888);
      camera->start();
}

Widget::~Widget()
{

}

---------------------------------------------------------------------------------------------------------------------------------

发文不通过只能写点”废话“了。学了一个星期的QT感觉其实不难,就是把一些封装好的类组合起来形成一些图形化界面。感觉还是挺好用,起码和C有相通性,唯一的难点应该在C++的语法上。所以会C++的同学应该更加的得心应手。挺好玩的,等学完驱动试试拿QT开发两个项目练练手。比如电视剧里男主给女主写的那个小猪闹钟,非常可爱以前不知道怎么下手做,学完QT我好像知道应该怎么写了。然后我还想做一个类似于QQ微信这种的聊天工具,可惜还不知道怎么用私网和私网通信。难道和女神之间搞点浪漫的东西还要租两台云服务器嘛,那也太扫兴了。现在这ip都是192.168开头的不能直接通信。听朋友说java有个内网透传技术是干这个的。不知道用C怎么实现。不过服务器我虽然买不起但是我打算自己买点件搭建一个服务器。应该会很有意思。

---------------------------------------------------------------------------------------------------------------------------------