1.知识重点
1.这篇文章,和上一篇文章没有什么很大的不同, 大部分代码都相似, 只有传输数据的时候,使用的数据类型不同, 这个方法更加的保密。 (JSON 数据传输)!!
2. 这个程序主要是加上了 JSON 的数据 封包, 和JSON 的 解析,
3.注意: 两台电脑上面的使用, 你的图片存储地址 ,记得自己换一下!!!
2.代码解析
图片封包
整形数据, QString 类型的 封包
判断解析的数据的类型
图片,解析, (解析是和 封包相反的)
整形数据, QString 类型的 解析
3.代码:
1.服务器 (发送图片 ,ip 地址自己改, 端口号自己改)
.pro 文件 加上 QT += network #网络编程
头文件
#ifndef CAMERA_H
#define CAMERA_H
#include <QMainWindow>
/******* 摄像头相关类 *****/
#include <QCamera> /*** 摄像头类 ***/
#include <QCameraInfo> /*** 系统摄像头属性类 ***/
#include <QCameraImageCapture> /*** 用于记录摄像头数据的类 ***/
/********* TCP网络相关类 ********/
#include <QTcpServer>
#include <QTcpSocket>
#include <QFile>
#include <QFileDialog>
#include <QFileInfo>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QTimer>
#include <QTime>
#include <QDebug> /*** debug 调试类 ****/
#include <QHostAddress>
QT_BEGIN_NAMESPACE
namespace Ui { class Camera; }
QT_END_NAMESPACE
class Camera : public QMainWindow
{
Q_OBJECT
public:
Camera(QWidget *parent = nullptr);
~Camera();
private:
Ui::Camera *ui;
QCamera *m_Camera; /*** 摄像机类对象 ***/
QCameraImageCapture *CameraImageCapture; /*** 用于记录摄像头数据的类 ***/
QTcpServer *TcpServer;
/******* TCP 数据 ************/
QList<QTcpSocket *> TcpSockets;
QTimer *timer;
public slots:
void slot_pushButton_camrae_open();
void slot_CameraImageCapture(int id,QImage image);
void slot_pushButton_capture();
void slot_TcpServer();
public:
QByteArray get_Image(QImage Image);//返回一个 图片 封装为 JSON JSON->QJsonDocumen QJsonDocumen-》QByteArray
QByteArray get_Int(int i);//返回一个整数的 JSON
QByteArray get_Qstring(QString a);//返回一个整数的 JSON
private slots:
void on_pushButton_clicked();
};
#endif // CAMERA_H
。cpp 文件
#include "camera.h"
#include "ui_camera.h"
#include <QMessageBox>
Camera::Camera(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::Camera)
{
ui->setupUi(this);
timer = new QTimer(this);
/**** 获取系统可用摄像头列表 ****/
QList<QCameraInfo> cameras = QCameraInfo::availableCameras();//获取可用摄像头设备列表
int index = cameras.size();
for(int i=0;i<index;i++)
{
if(cameras.at(i).isNull() == false)
{
qDebug() << "有效摄像头:" << cameras.at(i).description();//摄像头的设备名称
ui->comboBox->addItem(cameras.at(i).description()); //将摄像头添加到UI界面摄像头列表中
}
}
connect(ui->pushButton_camrae_open,SIGNAL(clicked(bool)),this,SLOT(slot_pushButton_camrae_open()));
connect(ui->pushButton_capture,SIGNAL(clicked(bool)),this,SLOT(slot_pushButton_capture()));
TcpServer = new QTcpServer(this);
TcpServer->listen(QHostAddress::Any,10001);
connect(TcpServer,SIGNAL(newConnection()),this,SLOT(slot_TcpServer()));
slot_pushButton_camrae_open();//打开摄像头
}
#include <QImage>
#include <QBuffer>
QByteArray Camera::get_Image(QImage Image)//返回一个 图片 封装为 JSON JSON->QJsonDocumen QJsonDocumen-》QByteArray
{
qDebug()<<"运用了 返回图片";
//思路 文件打开 图片, 读取数据 成字符串, 字符串,存入JSON 里面, 封装
QByteArray data;//
QBuffer buff(&data);//数据强转 利用 QBuffer 的 数据引用功能
Image.save(&buff,"jpg");//利用 图片的保存功能
QJsonObject Obj;
QString image(data.toBase64());//需要转一下,不然读取不到数据
// QByteArray xxx;
// xxx.append(image);
qDebug() << "data.size = " << data.size() << endl;
qDebug() << "image.size = " << image.size() << endl;
Obj.insert("size",image.size());
Obj.insert("image",image);
//把obj转为字符串
QJsonDocument doc;
doc.setObject(Obj); //把打包好的json数据给到document
QByteArray array = doc.toJson(); //把json格式的对象转为字符串
return array;
}
QByteArray Camera::get_Int(int i)//返回一个整数的 JSON
{
QJsonObject Obj;
int a=sizeof(i);
Obj.insert("size",a);
Obj.insert("int",i);
//把obj转为字符串
QJsonDocument doc;
doc.setObject(Obj); //把打包好的json数据给到document
QByteArray array = doc.toJson(); //把json格式的对象转为字符串
return array;
}
QByteArray Camera::get_Qstring(QString a1)//返回一个整数的 JSON
{
QJsonObject Obj;
int a=sizeof(a1);
Obj.insert("size",a);
Obj.insert("QString",a1);
//把obj转为字符串
QJsonDocument doc;
doc.setObject(Obj); //把打包好的json数据给到document
QByteArray array = doc.toJson(); //把json格式的对象转为字符串
return array;
}
void Camera::slot_TcpServer()
{
qDebug()<<"连接成功";
ui->listWidget->addItem("用户连接成功");
QTcpSocket *aa=new QTcpSocket;
aa=TcpServer->nextPendingConnection();
TcpSockets.append(aa);//添加用户
QHostAddress hostaddr = aa->peerAddress(); /** 获取主机信息 **/
QString ip = hostaddr.toString();
int port = aa->peerPort();
QString PORT = QString::number(port);
ui->listWidget->addItem("用户: "+ ip + " - " + PORT + "连接成功");//同步插入
qDebug()<<"到了这里2";
connect(aa,&QTcpSocket::disconnected,[=](){
ui->listWidget->addItem("用户断开连接");
timer->stop();//停止
});
qDebug()<<"到了这里3";
/************ 发送数据 *******************/
connect(timer,SIGNAL(timeout()),this,SLOT(slot_pushButton_capture()));
timer->start(100);//定时拍照
qDebug()<<"到了这里1";
}
Camera::~Camera()
{
delete ui;
}
void Camera::slot_pushButton_camrae_open()
{
if(ui->pushButton_camrae_open->text() == "打开摄像头")
{
/**** 摄像头初始化 ****/
QCameraInfo camreinfo = QCameraInfo::defaultCamera(); /*** 获取系统默认摄像头 ***/
if(camreinfo.isNull() == true)
{
QMessageBox::warning(this,"警告","系统没有可用摄像头");
return ;
}
/**** 申请摄像头类空间 ****/
m_Camera = new QCamera(camreinfo); // 直接使用系统默认的
m_Camera->setCaptureMode(QCamera::CaptureStillImage); //设置捕捉模式为静态帧(图片形式)
m_Camera->setCaptureMode(QCamera::CaptureMode::CaptureViewfinder); //将采集到取景器中
m_Camera->setViewfinder(ui->VideoWidget); //将摄像头数据输出到 UI 界面显示
m_Camera->start(); //摄像头打开
ui->pushButton_camrae_open->setText("关闭摄像头");
ui->pushButton_capture->setEnabled(true);
/***** 将摄像头放入摄像头记录类中,方便拍照 ******/
CameraImageCapture = new QCameraImageCapture(m_Camera);
CameraImageCapture->setCaptureDestination(QCameraImageCapture::CaptureToFile);
/*********** 捕获信号函数 imageCaptured(int,QImage) 拍了一张照,发出该信号 ********/
connect(CameraImageCapture,SIGNAL(imageCaptured(int,QImage)),this,SLOT(slot_CameraImageCapture(int,QImage)));
}
else
{
delete m_Camera; //释放他的空间
delete CameraImageCapture; //释放他的空间
ui->pushButton_camrae_open->setText("打开摄像头");
ui->pushButton_capture->setEnabled(false);
}
}
#include <QBuffer>
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
void Camera::slot_CameraImageCapture(int , QImage image)
{
ui->label_pixmap->setPixmap(QPixmap::fromImage(image));
QByteArray data =get_Image(image);
u8 type = 0xAA; //接收到0xAA,我的长度来了
size_t size = data.size();
qDebug()<<"size: "<<size;
for(auto TcpSocket : TcpSockets)
{
TcpSocket->write((char *)&type,sizeof(type)); //发送类型
TcpSocket->write((char *)&size,sizeof(size)); //发送长度
TcpSocket->write(data); //发送数据
}
qDebug()<<"发送数据成功";
}
void Camera::slot_pushButton_capture()
{
qDebug()<<"拍照成功";
CameraImageCapture->capture("C:/Users/86150/Desktop/qt_all/TCP/18_Camera_server/王老师.jpg");
}
void Camera::on_pushButton_clicked()
{
QString text= ui->lineEdit->text();
qDebug()<<"text = "<<text;
QByteArray data =get_Qstring(text);
u8 type = 0xAA; //接收到0xAA,我的长度来了
size_t size = data.size();
qDebug()<<"size: "<<size;
for(auto TcpSocket : TcpSockets)
{
TcpSocket->write((char *)&type,sizeof(type)); //发送类型
TcpSocket->write((char *)&size,sizeof(size)); //发送长度
TcpSocket->write(data); //发送数据
}
}
ui 界面
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Camera</class>
<widget class="QMainWindow" name="Camera">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>Camera</string>
</property>
<widget class="QWidget" name="centralwidget">
<widget class="QVideoWidget" name="VideoWidget" native="true">
<property name="geometry">
<rect>
<x>0</x>
<y>30</y>
<width>371</width>
<height>311</height>
</rect>
</property>
</widget>
<widget class="QPushButton" name="pushButton_capture">
<property name="enabled">
<bool>false</bool>
</property>
<property name="geometry">
<rect>
<x>300</x>
<y>360</y>
<width>93</width>
<height>28</height>
</rect>
</property>
<property name="text">
<string>拍照</string>
</property>
</widget>
<widget class="QLabel" name="label_pixmap">
<property name="geometry">
<rect>
<x>420</x>
<y>30</y>
<width>321</width>
<height>191</height>
</rect>
</property>
<property name="text">
<string>照片</string>
</property>
<property name="scaledContents">
<bool>true</bool>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
<widget class="QWidget" name="layoutWidget">
<property name="geometry">
<rect>
<x>20</x>
<y>360</y>
<width>273</width>
<height>30</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>摄像头列表</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBox"/>
</item>
</layout>
</item>
<item>
<widget class="QPushButton" name="pushButton_camrae_open">
<property name="text">
<string>打开摄像头</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QGroupBox" name="groupBox">
<property name="geometry">
<rect>
<x>0</x>
<y>400</y>
<width>295</width>
<height>67</height>
</rect>
</property>
<property name="title">
<string>消息发送窗口</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLineEdit" name="lineEdit">
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton">
<property name="text">
<string>发送</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QGroupBox" name="groupBox_2">
<property name="geometry">
<rect>
<x>440</x>
<y>250</y>
<width>351</width>
<height>231</height>
</rect>
</property>
<property name="title">
<string>消息接收窗口</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QListWidget" name="listWidget"/>
</item>
</layout>
</widget>
<widget class="QLabel" name="label_2">
<property name="geometry">
<rect>
<x>460</x>
<y>10</y>
<width>181</width>
<height>16</height>
</rect>
</property>
<property name="text">
<string>传输的视频</string>
</property>
</widget>
<widget class="QLabel" name="label_3">
<property name="geometry">
<rect>
<x>10</x>
<y>10</y>
<width>72</width>
<height>15</height>
</rect>
</property>
<property name="text">
<string>监控视屏</string>
</property>
</widget>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>26</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<customwidgets>
<customwidget>
<class>QVideoWidget</class>
<extends>QWidget</extends>
<header>qvideowidget.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
客户端
.pro 文件 加 QT += network
头文件
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QTcpSocket>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QFile>
#include <QFileDialog>
#include <QFileInfo>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private:
Ui::Widget *ui;
QTcpSocket *TcpSocket;
bool TCP_state;//TCP 连接的状态
bool display_state;//视屏播放的状态
public slots:
void slot_TcpSocket_readyRead();
public:
void analysis_Json(QByteArray data);//解析JSON
void analysis_int(QJsonObject obj);
void analysis_image(QJsonObject obj);
void analysis_Qstring(QJsonObject obj);
private slots:
void on_pushButton_clicked();
void on_pushButton_3_clicked();
};
#endif // WIDGET_H
.cpp 文件
#include "widget.h"
#include "ui_widget.h"
#include <QHostAddress>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
TCP_state=false;//连接状态为 无连接
display_state=false;//没有播放
}
Widget::~Widget()
{
delete ui;
}
void Widget::analysis_Json(QByteArray data)//解析JSON
{
qDebug()<<"进入解析模块";
QJsonParseError err;
QJsonDocument doc = QJsonDocument::fromJson(data,&err);
if(err.error != QJsonParseError::NoError) //检测是否是json格式
{
qDebug()<<"json error";
}
QJsonObject obj = doc.object();
qDebug()<<"输出obj :"<<obj;
if(obj.find("image") != obj.end())//图片解析
{
analysis_image(obj);
}
if(obj.find("int") != obj.end())//数字解析
{
analysis_int(obj);
}
if(obj.find("QString") != obj.end())//数字解析
{
analysis_Qstring(obj);
}
}
void Widget::analysis_int(QJsonObject obj)//解析数字
{
qDebug()<<"进入数字解析";
int kk=obj["size"].toInt();
int hh=obj["int"].toInt();//解析的数字
QString aa=QString::number(hh);
ui->listWidget->addItem(QString("服务器说: "+ aa));
}
void Widget::analysis_Qstring(QJsonObject obj)//解析语句
{
for(int i=0;i<100;i++)
{
qDebug()<<"进入图片解析";
}
int kk=obj["size"].toInt();
QString hh=obj["QString"].toString();//解析的
qDebug()<<"hh= "<<hh;
ui->listWidget->addItem(QString("服务器说: "+ hh));
}
void Widget::analysis_image(QJsonObject obj)//解析图片
{
qDebug()<<"进入图片解析";
int kk=obj["size"].toInt();
qDebug()<<"size:=="<<kk;
QString pp=obj["image"].toString();
QByteArray ll;
ll.append(pp);
QByteArray data = QByteArray::fromBase64(ll);
QFile file("D:/QT/hqyj_coding/18_TCP_image/王老师.jpg");
if (!file.open(QIODevice::Truncate | QIODevice::ReadWrite)) /*** 打开文件 **/
{
qDebug() << "文件打开失败";
}
file.write(data);
file.close();
QImage image("D:/QT/hqyj_coding/18_TCP_image/王老师.jpg");
if(display_state==true)
{
ui->label_1->setPixmap(QPixmap::fromImage(image));
}
}
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
void Widget::slot_TcpSocket_readyRead()
{
qDebug()<<"接收数据成功";
static u8 type = 0; //接收到0xAA,我的长度来了
static size_t size = 0;
static QByteArray data;
if(size == 0)
{
TcpSocket->read((char *)&type,sizeof(type)); //读取类型
if(type == 0xAA)
{
TcpSocket->read((char *)&size,sizeof(size)); //读取类型
data.clear();
type = 0;
}
}
if(size > 0)
{
QByteArray buf = TcpSocket->read(size); //读取类型
data.append(buf);
size -= buf.size();
if(size <= 0)
{
qDebug()<<"接收成功";
analysis_Json(data);//解析JSON
}
}
}
void Widget::on_pushButton_clicked()//连接
{
if(TCP_state==false)
{
QString ip=ui->lineEdit->text();
QString port=ui->lineEdit_2->text();
if(ip=="" || port=="")
{
ui->listWidget->addItem("参数不完整");
return;
}
int kk=port.toInt();
TcpSocket = new QTcpSocket(this);
TcpSocket->connectToHost(QHostAddress(ip),kk);
connect(TcpSocket,SIGNAL(readyRead()),this,SLOT(slot_TcpSocket_readyRead()));
connect(TcpSocket,&QTcpSocket::connected,[=](){
ui->pushButton->setText("断开连接");
TCP_state=true;
ui->listWidget->addItem("连接成功");
});
}
else
{
disconnect(TcpSocket,SIGNAL(readyRead()),this,SLOT(slot_TcpSocket_readyRead()));
delete TcpSocket;
ui->pushButton->setText("连接");
TCP_state=false;
ui->listWidget->addItem("已经断开连接");
}
}
void Widget::on_pushButton_3_clicked()
{
if(display_state==false)
{
ui->pushButton_3->setText("关闭监控");
display_state=true;
ui->listWidget->addItem("监控已经打开");
}
else
{
ui->pushButton_3->setText("打开监控");
display_state=false;
ui->listWidget->addItem("监控已经关闭");
}
}
ui 设计界面
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Widget</class>
<widget class="QWidget" name="Widget">
<property name="enabled">
<bool>true</bool>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>552</width>
<height>468</height>
</rect>
</property>
<property name="windowTitle">
<string>Widget</string>
</property>
<widget class="QGroupBox" name="groupBox">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>441</width>
<height>261</height>
</rect>
</property>
<property name="title">
<string>监控播放窗口</string>
</property>
<widget class="QLabel" name="label_1">
<property name="geometry">
<rect>
<x>0</x>
<y>20</y>
<width>431</width>
<height>231</height>
</rect>
</property>
<property name="text">
<string/>
</property>
<property name="scaledContents">
<bool>true</bool>
</property>
</widget>
</widget>
<widget class="QPushButton" name="pushButton">
<property name="geometry">
<rect>
<x>240</x>
<y>400</y>
<width>93</width>
<height>28</height>
</rect>
</property>
<property name="text">
<string>连接</string>
</property>
</widget>
<widget class="QPushButton" name="pushButton_3">
<property name="geometry">
<rect>
<x>450</x>
<y>10</y>
<width>93</width>
<height>28</height>
</rect>
</property>
<property name="text">
<string>打开监控</string>
</property>
</widget>
<widget class="QListWidget" name="listWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>270</y>
<width>431</width>
<height>121</height>
</rect>
</property>
</widget>
<widget class="QWidget" name="layoutWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>400</y>
<width>230</width>
<height>55</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>IP地址</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEdit"/>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_2">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>prot </string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEdit_2"/>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections/>
</ui>
这个 资源已经上传 !!!