草庐IT

QT/C++——网络编程

宇努力学习 2024-02-03 原文

目录

一、基础知识复习

二、UDP

客户端:

服务器:

三、TCP

服务器:

客户端:

四、小项目

客户端:

服务器:


一、基础知识复习

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

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

 

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

二、UDP

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

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

客户端:

#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

服务器:

#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怎么实现。不过服务器我虽然买不起但是我打算自己买点件搭建一个服务器。应该会很有意思。

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

有关QT/C++——网络编程的更多相关文章

  1. ruby - 寻找通过阅读代码确定编程语言的ruby gem? - 2

    几个月前,我读了一篇关于ruby​​gem的博客文章,它可以通过阅读代码本身来确定编程语言。对于我的生活,我不记得博客或gem的名称。谷歌搜索“ruby编程语言猜测”及其变体也无济于事。有人碰巧知道相关gem的名称吗? 最佳答案 是这个吗:http://github.com/chrislo/sourceclassifier/tree/master 关于ruby-寻找通过阅读代码确定编程语言的rubygem?,我们在StackOverflow上找到一个类似的问题:

  2. ruby - 用 Ruby 编写一个简单的网络服务器 - 2

    我想在Ruby中创建一个用于开发目的的极其简单的Web服务器(不,不想使用现成的解决方案)。代码如下:#!/usr/bin/rubyrequire'socket'server=TCPServer.new('127.0.0.1',8080)whileconnection=server.acceptheaders=[]length=0whileline=connection.getsheaders想法是从命令行运行这个脚本,提供另一个脚本,它将在其标准输入上获取请求,并在其标准输出上返回完整的响应。到目前为止一切顺利,但事实证明这真的很脆弱,因为它在第二个请求上中断并出现错误:/usr/b

  3. 网络编程套接字 - 2

    网络编程套接字网络编程基础知识理解源`IP`地址和目的`IP`地址理解源MAC地址和目的MAC地址认识端口号理解端口号和进程ID理解源端口号和目的端口号认识`TCP`协议认识`UDP`协议网络字节序socket编程接口`sockaddr``UDP`网络程序服务器端代码逻辑:需要用到的接口服务器端代码`udp`客户端代码逻辑`udp`客户端代码`TCP`网络程序服务器代码逻辑多个版本服务器单进程版本多进程版本多线程版本线程池版本服务器端代码客户端代码逻辑客户端代码TCP协议通讯流程TCP协议的客户端/服务器程序流程三次握手(建立连接)数据传输四次挥手(断开连接)TCP和UDP对比网络编程基础知识

  4. Qt Designer的简单使用 - 2

    在前面两节的例子中,主界面窗口的尺寸和标签控件显示的矩形区域等,都是用C++代码编写的。窗口和控件的尺寸都是预估的,控件如果多起来,那就不好估计每个控件合适的位置和大小了。用C++代码编写图形界面的问题就是不直观,因此Qt项目开发了专门的可视化图形界面编辑器——QtDesigner(Qt设计师)。通过QtDesigner就可以很方便地创建图形界面文件*.ui,然后将ui文件应用到源代码里面,做到“所见即所得”,大大方便了图形界面的设计。本节就演示一下QtDesigner的简单使用,学习拖拽控件和设置控件属性,并将ui文件应用到Qt程序代码里。使用QtDesigner设计界面在开始菜单中找到「Q

  5. ruby - 我正在学习编程并选择了 Ruby。我应该升级到 Ruby 1.9 吗? - 2

    我完全不是程序员,正在学习使用Ruby和Rails框架进行编程。我目前正在使用Ruby1.8.7和Rails3.0.3,但我想知道我是否应该升级到Ruby1.9,因为我真的没有任何升级的“遗留”成本。缺点是什么?我是否会遇到与普通gem的兼容性问题,或者甚至其他我不太了解甚至无法预料的问题? 最佳答案 你应该升级。不要坚持从1.8.7开始。如果您发现不支持1.9.2的gem,请避免使用它们(因为它们很可能不被维护)。如果您对gem是否兼容1.9.2有任何疑问,您可以在以下位置查看:http://www.railsplugins.or

  6. ruby - 如何以编程方式删除实例上的 "singleton information"以使其编码(marshal)? - 2

    我创建了一个由于“在运行时执行的单例元类定义”而无法编码的对象(这段代码的描述是否正确?)。这是通过以下代码执行的:#defineclassXthatmyusesingletonclassmetaprogrammingfeatures#throughcallofmethod:break_marshalling!classXdefbreak_marshalling!meta_class=class我该怎么做才能使对象编码正确?是否可以从对象instance_of_x的classX中“移除”单例组件?我真的需要一个建议,因为我们的一些对象需要通过Marshal.dump序列化机制进行缓存。

  7. Ruby 元编程问题 - 2

    我正在查看Ruby日志记录库Logging.logger方法并从sourceatgithub提出问题与这段代码有关:logger=::Logging::Logger.new(name)logger.add_appendersappenderlogger.additive=falseclass我知道类 最佳答案 这实际上删除了方法(当它实际被执行时)。这是确保close不会被调用两次的保障措施。看起来好像有嵌套的“class 关于Ruby元编程问题,我们在StackOverflow上找到一

  8. ruby - Paperclip:以编程方式分配图像并设置其名称 - 2

    使用Paperclip,我想从这样的URL抓取图像:require'open-uri'user.photo=open(url)问题是我最后得到一个像“open-uri20110915-4852-1o7k5uw”这样的文件名。有什么方法可以更改user.photo上的文件名?作为一个额外的变化,Paperclip将我的文件存储在S3上,所以如果我可以在初始分配中设置我想要的文件名就更好了,这样图像就会上传到正确的S3key。像这样:user.photo=open(url),:filename=>URI.parse(url).path 最佳答案

  9. ruby - 如何以编程方式检查证书是否已被吊销? - 2

    我正在开发一个xcode自动构建系统。在执行一些预构建验证时,我想检查指定的证书文件是否已被撤销。我了解securityverify-cert验证其他证书属性但不验证吊销。我如何检查撤销?我正在用Ruby编写构建系统,但我对任何语言的想法都持开放态度。我阅读了这个答案(Openssl-Howtocheckifacertificateisrevokedornot),但指向底部的链接(DoesOpenSSLautomaticallyhandleCRLs(CertificateRevocationLists)now?)进入的Material对我的目的来说有点过于复杂(用户上传已撤销的证书是一

  10. ruby - 检查网络文件是否存在,而不下载它? - 2

    是否可以在不实际下载文件的情况下检查文件是否存在?我有这么大的(~40mb)文件,例如:http://mirrors.sohu.com/mysql/MySQL-6.0/MySQL-6.0.11-0.glibc23.src.rpm这与ruby​​不严格相关,但如果发件人可以设置内容长度就好了。RestClient.get"http://mirrors.sohu.com/mysql/MySQL-6.0/MySQL-6.0.11-0.glibc23.src.rpm",headers:{"Content-Length"=>100} 最佳答案

随机推荐