服务端
思路
- 显示桌面的主机是服务端。
- 当服务端接收完客户端数据时会主动断开和客户端的连接。
客户端
思路
- 被投放桌面的主机是服务端。
- 客户端截图桌面,发送给服务端截图的大小和数据。
- 客户端发送截图后,等待客户端断开连接(通过这个等待判断服务端是不是已经读取完图片了),然后再重新连接服务端。
- 客户端启动后就隐藏程序窗口,后台执行
代码
服务端-mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QTcpServer>
#include <QTcpSocket>
#include <QResizeEvent>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void initClient();
void receivePixmap();
protected:
void resizeEvent(QResizeEvent *event);
private:
Ui::MainWindow *ui;
QTcpServer* tcp_server;
QTcpSocket* tcp_client;
int pixmapSize = 0;
bool isNewPixmap = true;
QByteArray pixmapData;
};
#endif // MAINWINDOW_H
服务端-mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#define PORT 43124
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
// 设置显示桌面标签的布局大小
ui->pixmapLabel->setGeometry(0,0,this->width(),this->height());
this->tcp_server = new QTcpServer;
// 鉴听端口
this->tcp_server->listen(QHostAddress::Any,PORT);
// 当有客户端连接时,发射newConnection()信号
QObject::connect(this->tcp_server,SIGNAL(newConnection()),this,SLOT(initClient()));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::initClient(){
// 获取客户端
this->tcp_client = this->tcp_server->nextPendingConnection();
// 当客户端向服务端发送数据时发射readyRead()信号
QObject::connect(this->tcp_client,SIGNAL(readyRead()),this,SLOT(receivePixmap()));
}
#include <QByteArray>
#include <QPixmap>
#include <QBuffer>
#include <QIODevice>
#include <QImageReader>
void MainWindow::receivePixmap(){
char readBuffer;
// 如果是新的一张照片,则进入if,否则不进入
if(this->isNewPixmap){
char bufferSize[10];
int len = this->tcp_client->read(bufferSize,sizeof(bufferSize));
QString str;
int i;
for(i=0; i<len; i++){
if(bufferSize[i] >= '0' && bufferSize[i] <= '9'){
str.append(bufferSize[i]);
}else{
break;
}
}
// 前面读取数据只是为了获得想要传过来的照片大小
this->pixmapSize = str.toInt();
// 但照片大小不一定装满10字节,故后面的属于照片的数据内容
for(;i < len; i++){
pixmapData.append(bufferSize[i]);
}
isNewPixmap = false;
}
// 如果照片数据没读完
if(pixmapSize > pixmapData.size()){
// readALL 不一定能读完全部数据,所以这里表示读一部分数据
QByteArray tempArray = this->tcp_client->readAll();
QBuffer tempBuffer(&tempArray);
tempBuffer.open(QIODevice::ReadOnly);
int tempSize = tempBuffer.size();
// 从头开始读取
tempBuffer.seek(0);
while(tempSize > 0){
tempBuffer.getChar(&readBuffer);
// 把部分数据加入到照片数据
pixmapData.append(readBuffer);
tempSize--;
}
}
// 如果照片数据读完了
if(pixmapSize == pixmapData.size()){
QBuffer buffer(&pixmapData);
buffer.open( QIODevice::ReadOnly);
QImageReader reader(&buffer, "png");
QImage image = reader.read();
// 显示照片
ui->pixmapLabel->setPixmap(QPixmap::fromImage(image,Qt::AutoColor).scaled(
ui->pixmapLabel->size()));
// 开始接收下一张照片
isNewPixmap = true;
this->pixmapData.clear();
// 断开客户端与服务端的连接
this->tcp_client->disconnectFromHost();
}
}
void MainWindow::resizeEvent(QResizeEvent *event){
// 窗口大小发生任何改变时,改变pixmapLabel大小,实现自适应窗口
ui->pixmapLabel->setGeometry(0,0,this->width(),this->height());
}
客户端-mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QTcpSocket>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void sendPixmap();
private:
Ui::MainWindow *ui;
QTcpSocket* tcp_server;
};
#endif // MAINWINDOW_H
客户端-mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#define HOST "192.168.3.236"
#define PORT 43124
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
this->tcp_server = new QTcpSocket;
// 连接到服务端
this->tcp_server->connectToHost(HOST,PORT);
// 连接成功发送connected()信号
QObject::connect(this->tcp_server,SIGNAL(connected()),this,SLOT(sendPixmap()));
}
MainWindow::~MainWindow()
{
delete ui;
}
#include <QScreen>
#include <QPixmap>
#include <QApplication>
#include <QDesktopWidget>
#include <QGuiApplication>
#include <QImage>
#include <QImageReader>
#include <QByteArray>
#include <QBuffer>
#include <QThread>
void MainWindow::sendPixmap(){
QScreen* screen = QGuiApplication::primaryScreen();
// 获取桌面截图图片
QPixmap pixmap = screen->grabWindow(QApplication::desktop()->winId());
QImage image = pixmap.toImage();
QByteArray ba;
QBuffer buffer(&ba);
buffer.open(QIODevice::WriteOnly);
// 把截图的数据写入buffer
image.save(&buffer, "PNG");
// 把 截图的数据的大小 发送给服务器
this->tcp_server->write(QString::number(ba.size()).toLatin1().data());
// 把 截图的数据 发送给服务器
this->tcp_server->write(ba);
this->tcp_server->flush();
// 服务端接收完数据会和客户端断开连接
// 等待服务端接收完成
this->tcp_server->waitForDisconnected();
// 重新连接,连接成功发送connected()信号,重新执行sendPixmap方法
this->tcp_server->connectToHost(HOST,PORT);
}
需要注意的是客户端在启动的时候把自己窗口隐藏住
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
// 该程序窗口一开始便隐藏,不显示,后台执行
w.hide();
return a.exec();
}