QT组播实现多人屏幕共享的程序


屏幕共享程序的实现:

发送端(共享屏幕服务端) :

    1. 获取桌面图像
	QScreen *screen = QApplication::primaryScreen(); //获取当前程序的主窗口对象
	QPixmap map = screen->grabWindow(QApplication::desktop()->winId()); //调用主窗口对象的捕捉窗口图像,并传递桌面窗口的id号

    2. 编码成jpg
	QByteArray ba;
 	QBuffer    bf(&ba);
 	map.save(&bf, "jpg", 30) // 30表示压宿率,值从0 – 100, 值越小表示编码出来的图像文件就越小,当然也就越不清晰


    3. 用udp组播发出.
	组播的编程参考http://blog.csdn.net/jklinux/article/details/72123951

	一张jpg大概100K, 每次传输4K字节, 需分成多次传输.
	每次桌面图像编码成jpg, 图像大小是不固定的. 每张图像传输第一次时,发出"newImage:长度", 
	QUdpSocket成功发出个部分数据后, waitForBytesWritten等待发出,完成后再发出下一部分.


接收端:
     1. 创建udp对象,加入组播


     2. 接收数据到内存数据里,并且判断。 如接收到"newImage:长度"则表示上一张图像已传输完毕,可以把上一张图像刷出来了。并且也知道下一张图像的长度。
		
     3. 接收完成一张图像后。使用QPixmap从内存数组里加载图像.
	     QPixmap map;
     	     map.loadFromData((uchar *)data_pic, len_recv);
     	     label->setPixmap(map);

	

完整工程源码:

发送端:
mywin.h

#ifndef MYWIN_H
#define MYWIN_H

#include <QWidget>
#include <QPushButton>
#include "mythread.h"

class MyWin : public QWidget
{
    Q_OBJECT
private:
    QPushButton *btn;
    MyThread    *thread;
public:
    explicit MyWin(QWidget *parent = 0);
    ~MyWin();
signals:

public slots:
    void slot_btn();
};

#endif // MYWIN_H

mywin.cpp

```cpp

#include "mywin.h"

MyWin::MyWin(QWidget *parent) : QWidget(parent)
{
    btn = new QPushButton("start", this);
    btn->setGeometry(10, 10, 150, 80);
    connect(btn, SIGNAL(clicked(bool)), this, SLOT(slot_btn()));

    thread = new MyThread;
    thread->start();
}

MyWin::~MyWin()
{
    delete btn;

    thread->down();
    thread->terminate();
    thread->wait();
    delete thread;


}

void MyWin::slot_btn()
{
    if (btn->text() == "start")
    {
        thread->goOn();
        btn->setText("pause");
    }
    else
    {
        thread->pause();
        btn->setText("start");
    }


}

mythread.h


#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QUdpSocket>
#include <QThread>
#include <QMutex>

class MyThread : public QThread
{
private:
    QUdpSocket *udp;
    char *data;
    QMutex *mutex;

    int    flag;
public:
    MyThread();
    ~MyThread();

    void run();

    void pause();
    void goOn();
    void down();
};

#endif // MYTHREAD_H

mythread.cpp


#include "mythread.h"
#include <QScreen>
#include <QApplication>
#include <QPixmap>
#include <QDesktopWidget>
#include <QBuffer>
#include <QNetworkInterface>
#include <QMessageBox>
#include <unistd.h>

#define MAX_LEN   (3*1024*1024)
#define P_LEN     4000

#define PORT        7788
#define MULTI_ADDR  "224.55.55.55"

MyThread::MyThread()
{
    mutex = new QMutex;
    mutex->lock();
    flag = 0;
}

MyThread::~MyThread()
{

}

void MyThread::run()
{
    QList<QNetworkInterface> list;
    QNetworkInterface intf;
    list = QNetworkInterface::allInterfaces(); //获取系统里所有的网卡对象
    for (int i = 0; i < list.size(); i++)
    {
        intf = list.at(i);

        QNetworkInterface::InterfaceFlags flags = intf.flags();
        //找出处在执行状态,能支持组播的网卡对象
        if ((flags & QNetworkInterface::IsRunning) && (flags & QNetworkInterface::CanMulticast))
            break;
    }

    udp = new QUdpSocket;
    if (!udp->bind(QHostAddress::AnyIPv4))
        exit(0);
    qDebug() << intf.name();
    udp->setMulticastInterface(intf);

    udp->setSocketOption(QUdpSocket::SendBufferSizeSocketOption, MAX_LEN*3);
    data = new char[P_LEN];

    QByteArray ba_pic;
    int len_pic, len_sent;
   while (1)
   {
       if (0 == flag)
           mutex->lock();
       if (2 == flag)
           break;

      QScreen *src = QApplication::primaryScreen();
      QPixmap map = src->grabWindow(QApplication::desktop()->winId());

      ba_pic.resize(0); //清除空间
      QBuffer bf(&ba_pic);
      map.save(&bf, "jpg", 30);
      len_pic =  ba_pic.size();

      char *pdata = ba_pic.data();

      len_sent = 0 ; //已发送长度

      sprintf(data, "newImage:%d", len_pic);
      int l, ret;

       udp->writeDatagram(data, strlen(data), QHostAddress(MULTI_ADDR), PORT);
       udp->waitForBytesWritten();

       for (len_sent = 0; len_sent < len_pic; len_sent += P_LEN)
       {
           if (len_sent + P_LEN > len_pic)
               l = len_pic - len_sent;
           else
               l = P_LEN;
           ret = udp->writeDatagram(pdata+len_sent, l, QHostAddress(MULTI_ADDR), PORT);
           udp->waitForBytesWritten();
       }
   }


}

void MyThread::pause()
{
    flag = 0;
}

void MyThread::goOn()
{
    flag = 1;
    mutex->unlock();
}

void MyThread::down()
{
    flag = 2;
    mutex->unlock();
}

main.cpp

#include <QApplication>
#include "mywin.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MyWin win;

    win.show();
    return a.exec();
}


接收端:
mywin.h


#ifndef MYWIN_H
#define MYWIN_H

#include <QWidget>
#include <QUdpSocket>
#include <QFile>
#include <QLabel>

class MyWin : public QWidget
{
    Q_OBJECT
private:
    QUdpSocket *udp;
    int        len_pic;
    int        len_recv;
    char       *data_pic;
    char       *data;
    QLabel     *label;

    void resizeEvent(QResizeEvent *event);
public:
    explicit MyWin(QWidget *parent = 0);
    ~MyWin();
signals:

public slots:
    void slot_udp_read();
};

#endif // MYWIN_H

mywin.cpp


#include "mywin.h"
#include <QMessageBox>
#include <QPixmap>

#define MAX_LEN   5*1024*1024
#define  P_LEN     4000
#define PORT  7788
#define MULTI_ADDR   "224.55.55.55"

MyWin::MyWin(QWidget *parent) : QWidget(parent)
{
    udp = new QUdpSocket(this);

    if (!udp->bind(QHostAddress::AnyIPv4, PORT))
    {
        QMessageBox::critical(this, "error", "bind failed");
        exit(0);
    }

    if (!udp->joinMulticastGroup(QHostAddress(MULTI_ADDR)))
    {
        QMessageBox::critical(this, "error", "join multicast group failed");
        exit(0);
    }

    data_pic = new char[MAX_LEN];
    data = new char[P_LEN];
    label = new QLabel(this);
    label->setScaledContents(true);
    label->resize(this->size());

    connect(udp, SIGNAL(readyRead()), this, SLOT(slot_udp_read()));
}

MyWin::~MyWin()
{
    delete udp;
    delete [] data_pic;
    delete [] data;
}

void MyWin::resizeEvent(QResizeEvent *event)
{
    label->resize(this->size());
}

void MyWin::slot_udp_read()
{
    int ret;
    ret = udp->readDatagram(data, P_LEN);
    data[ret] = 0;
    QByteArray ba(data, ret);

    if (ba.contains("newImage:"))
    {
         len_pic = atoi(data+ba.indexOf("newImage:")+9);
         qDebug() << len_pic;
         len_recv = 0;
         return;
    }
    memcpy(data_pic+len_recv, data, ret);
    len_recv += ret;
    if (len_recv >= len_pic)
    {
     QPixmap map;
     map.loadFromData((uchar *)data_pic, len_recv);
     label->setPixmap(map);
    }

}

main.cpp

#include <QApplication>
#include "mywin.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MyWin win;

    win.show();
    return a.exec();
}


  • 7
    点赞
  • 54
    收藏
    觉得还不错? 一键收藏
  • 25
    评论
评论 25
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值