编程环境
vs2019+QT5.12.10
tcp连接
1.构造创建
ServerListenSocket = new QTcpServer(this); //服务器端监听套接字 ServerListenSocket
ClientConnectedSocket = new QTcpSocket(this);
closTcpFlag = false;
if (!ServerListenSocket->listen(QHostAddress::Any, 8888)) //监听本机8888端口上的任意IP地址的连入
{
//QMessageBox::critical(this, tr("Fortune Server"), tr("Unable to start the server:%l.").arg(ServerListenSocket->errorString()));
ServerListenSocket->close();
return;
}
connect(ServerListenSocket, SIGNAL(newConnection()), this, SLOT(clientConnection())); //将监听套接字有新客户端的接入信号newConnection() 的与处理的槽函数clientConnection() 连接
clientRequestSize = 0; //客户端发送过来的第一段数据块的大小(字节数)
2.二次交互(握手)
//有新客户端连接的处理函数
void Server::clientConnection()
{
//ui.info->addItem("An new client is connected!");
ShowNews("有个新设备已连接", "requestType");
ClientConnectedSocket = ServerListenSocket->nextPendingConnection(); //返回已连接套接字对象
connect(ClientConnectedSocket, SIGNAL(readyRead()), this, SLOT(readClientRequest())); //将已连接套接字对象的准备好可读信号readyRead与 readClientRequest()槽函数连接
connect(ClientConnectedSocket, SIGNAL(disconnected()), ClientConnectedSocket, SLOT(deleterLater())); //已连接套接字的断开信号与自身的稍后删除信号相连接
}
//读取客户端发送过来的 请求 (发送任意字节流,只是将其按收发双方约定的规则解释为 第一次交互的请求)
void Server::readClientRequest()
{
QDataStream in(ClientConnectedSocket);
in.setVersion(QDataStream::Qt_5_10);
//如果客户端发送过来的第一段数据块的大小为0,说明确实是第一次交互
if (clientRequestSize == 0)
{
//客户端发送过来的第一段数据块的大小如果小于 64bit ,则说明:还未收到客户端发送过来的前64bit的数据,这64bit的数据存储了客户端第一次请求包的大小(字节数)
if (ClientConnectedSocket->bytesAvailable() < sizeof(quint16))
{
return ; //返回,继续等待 接收数据,数据还在套接字缓存当中
}
else//如果 客户端发送过来的第一段数据块的大小>= 64bit 了
{
in >> clientRequestSize;//将数据的前64bit提取出来,存储到quint64 类型的clientRequestSize
}
}
if (ClientConnectedSocket->bytesAvailable() < clientRequestSize)//当前套接字缓冲区中存储的数据如果小于clientRequestSize个字节
{
return ;//返回,继续等待 接收数据,数据还在套接字缓存当中
}
quint8 requestType;
in >> requestType;//从套接字缓冲区中读取 8bit的数据解释为quint8类型,存储到requestType中
if (requestType == 'R') //如果requestType是 'R' 字符R的ASCII值
{
ShowNews("连接成功", "");
emit resivFirst();
connect_flag = true;
}
}
3.数据发送
ClientConnectedSocket->write(ba);//把图像数据写入传输给主机
int i_temp = ClientConnectedSocket->waitForReadyRead(); //等待主机响应第二个“ok”
ba.clear();
- 在头文件里
#pragma once
#include <QObject>
#include<QtNetwork>
#include<QTcpServer>
#include<QTcpSocket>
#include<QImage>
#include<QImageReader>
#include<QTime>
#include<QDebug>
#include<QMessageBox>
#include<QFileDialog>
#include <QPixmap>
#include <QMutexLocker>
#include <QMutex>
class Server : public QObject
{
Q_OBJECT
public:
Server();
~Server();
private:
QTcpServer* ServerListenSocket;
QTcpSocket* ClientConnectedSocket;
QTimer* timer1;
QPixmap pixmap;
QMatrix matrix;
quint16 clientRequestSize;
QTimer* timer;
bool connect_flag;
bool closTcpFlag;
private:
void ShowNews(QString ch_z, QString mess);
signals:
void resivFirst();
//把处理后的记过返回给主线程
void resultReady(QByteArray tempimg);
void msgTrans(QString msg);
private slots:
void clientConnection();
void readClientRequest();
public slots:
void SendData(QImage image);
void cutconnnect();
};
##如果在VS下使用Qt记得设置
接收端(客户端)
.h
#pragma once
#include <QtWidgets/QWidget>
#include "ui_UdpRev.h"
#include <QWidget>
#include<QTcpSocket>
#include<QTcpServer>
#include <QPixmap>
#include <QMatrix>
#include <QTimer>
#include <QPushButton>
#include <QApplication>
#include <QtGui>
#include <QLabel>
#include <QPushButton>
#include <QComboBox>
//包头
class TcpRev : public QWidget
{
Q_OBJECT
public:
TcpRev(QWidget* parent = Q_NULLPTR);
QTcpSocket tcpSocket;
QImage img;
qint64 imageBlockSize;
double m_currentIndex;
QImage pixmapScale(const QImage& image, const double& index);
void wheelEvent(QWheelEvent* event);
int m_npfpsCont; ///< 帧率计数
double fFps;
QTimer* m_pTimer; ///<定时器
private:
void ShowImage(QByteArray ba);
private:
private slots:
void connectToServer();
void sendRequest();
void ReceiveData();
void connectionCloseByServer();
void error();
void tcpConnected();
void on_connectToServer_clicked();
void on_requestVideo_clicked();
void ShowNewsR(QString ch_z, QString mess);
void TimerEvent();
private:
Ui::TCPRevClass ui;
};
.cpp
#include "TcpRev.h"
#include <QBuffer>
#include <QImage>
#include <QDebug>
#include <QHostInfo>
#include <QNetworkInterface>
#include <QCoreApplication>
#include <QTime>
#include <windows.h>
#include "qevent.h"
#pragma execution_character_set("utf-8")
TcpRev::TcpRev(QWidget *parent)
: QWidget(parent)
{
ui.setupUi(this);
setAttribute(Qt::WA_StyledBackground);
ui.newEdit_2->setStyleSheet("QTextEdit{background-color:transparent}");
ui.lineEditPort_2->setStyleSheet("QLineEdit{background-color:transparent}"
"QLineEdit{border-width:0;border-style:outset}");
ui.lineEditIP_2->setStyleSheet("QLineEdit{background-color:transparent}"
"QLineEdit{border-width:0;border-style:outset}");
ui.lineEditRevSize->setStyleSheet("QLineEdit{background-color:transparent}"
"QLineEdit{border-width:0;border-style:outset}");
ui.lineEditRevFrame->setStyleSheet("QLineEdit{background-color:transparent}"
"QLineEdit{border-width:0;border-style:outset}");
ui.lineEditRevSize_2->setStyleSheet("QLineEdit{background-color:transparent}"
"QLineEdit{border-width:0;border-style:outset}");
QBrush myBrush;
QPalette palette;
myBrush = QBrush(Qt::white, Qt::DiagCrossPattern);
palette.setBrush(QPalette::Text, myBrush);
ui.newEdit_2->setPalette(palette);
ui.lineEditPort_2->setPalette(palette);
ui.lineEditIP_2->setPalette(palette);
ui.lineEditRevSize->setPalette(palette);
ui.lineEditRevFrame->setPalette(palette);
ui.lineEditRevSize_2->setPalette(palette);
imageBlockSize = 0; //一次接收的图像数据的大小(字节数)
m_pTimer = new QTimer(this);
connect(m_pTimer, SIGNAL(timeout()), this, SLOT(TimerEvent()));
connect(&tcpSocket, SIGNAL(disconnect()), this, SLOT(connectionCloseByServer()));//套接字的断开信号
connect(&tcpSocket, SIGNAL(readyRead()), this, SLOT(ReceiveData()));//套接字一次可读的触发信号
connect(&tcpSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(error()));//套接字的错误消息信号
m_currentIndex = 0.4;
m_npfpsCont = 0; ///< 帧率计数
fFps = 0;
}
void TcpRev::on_connectToServer_clicked()//点击该按钮,连接到服务器主机
{
connectToServer();
bool k = connect(&tcpSocket, SIGNAL(connected()), this, SLOT(tcpConnected())); //将连接以完成信号与 tcpConnected()槽函数绑定
}
void TcpRev::on_requestVideo_clicked()//点击该按钮,发送请求,请求视频图像序列
{
sendRequest();
m_pTimer->start(50);
}
void TcpRev::connectToServer()
{
//连接到本机的8888端口
tcpSocket.connectToHost(QHostAddress::LocalHost, 8888);//connectToHost是异步连接函数(不阻塞),一经调用结束立刻返回
ui.lineEditIP_2->setText(QHostInfo::localHostName());
ui.lineEditPort_2->setText("8888");
ShowNewsR("连接中", "connecting to LocalHost port 8888...");
ui.connectToServer->setEnabled(false);
ShowNewsR("连接成功", QString::number(QHostAddress::LocalHost));
}
void TcpRev::sendRequest()//发送请求,请求视频图像序列
{
QByteArray requestMessage; //请求消息(字节数组)
QDataStream out(&requestMessage, QIODevice::WriteOnly);//只读输出流
out.setVersion(QDataStream::Qt_5_10);
out << quint16(0) << quint8('R');//将请求消息的大小、长度(字节数)与请求消息 'R'写入 输出数据流out
out.device()->seek(0);
out << quint16(requestMessage.size() - sizeof(quint16));
tcpSocket.write(requestMessage);//将输出数据流中的数据写入套接字
ShowNewsR("发送中", "Sending request...");
ui.requestVideo->setEnabled(false);
}
static int receiveCount = 0;//接收 readyRead()信号的触发计数
static int imageCount = 0; //接收到的图像数据的计数
void TcpRev::ReceiveData()
{
receiveCount++;
QString rCount = QString::number(receiveCount);
ui.lineEditRevFrame->setText(rCount);
QByteArray message;//存放从服务器接收到的字节流数据
QDataStream in(&tcpSocket); //将客户端套接字与输入数据流对象in绑定
in.setVersion(QDataStream::Qt_5_12);//设置数据流的版本
//ShowNewsR("接收信号的个数", QString::number(receiveCount));
if (imageBlockSize == 0)
{
//如果imageBlockSize == 0 则说明,一幅图像的大小信息还未传输过来
//uint64是8字节的8 Bytes 64bit
//判断接收的数据是否有8字节(文件大小信息)
//如果有则保存到basize变量中,没有则返回,继续接收数据
if (tcpSocket.bytesAvailable() < (int)sizeof(quint64))
{//一幅图像的大小信息还未传输过来
return;
}
in >> imageBlockSize;//一幅图像的大小信息
if (imageBlockSize == (quint64)0xFFFFFFFFFFFFFFFF)//视频结束的标注符
{
tcpSocket.close();
ShowNewsR("警告", "the video is end!");
ui.requestVideo->setEnabled(true);
ui.connectToServer->setEnabled(true);
return;
}
ui.lineEditRevSize->setText(QString::number(imageBlockSize));
tcpSocket.write("ok");
message.resize(imageBlockSize);
}
//如果没有得到一幅图像的全部数据,则返回继续接收数据
if (tcpSocket.bytesAvailable() < imageBlockSize)
{
return;
}
in >> message;//一幅图像所有像素的完整字节流
imageBlockSize = 0;//已经收到一幅完整的图像,将imageBlockSize置0,等待接收下一幅图像
imageCount++; //已接收的图像计数
QString iCount = QString::number(imageCount);
ui.lineEditRevFrame->setText(iCount);
ShowImage(message); //显示当前接收到的这一幅图像
}
void TcpRev::connectionCloseByServer()//服务端主动断开了已连接套接字
{
ShowNewsR("错误", ":Connection closed by server!");
tcpSocket.close();//关闭客户端套接字
ui.connectToServer->setEnabled(true);
}
void TcpRev::error()
{
ShowNewsR("错误", tcpSocket.errorString());
tcpSocket.close();
ui.connectToServer->setEnabled(true);
}
void TcpRev::tcpConnected()//套接字已经建立连接信号的处理槽函数
{
ui.requestVideo->setEnabled(true);
}
void TcpRev::ShowImage(QByteArray ba) //从接收到了字节流中,执行与服务器断相反的操作:解压缩、解释为图像数据
{
m_npfpsCont++;
QString ss = QString::fromLatin1(ba.data(), ba.size());
QByteArray rc;
rc = QByteArray::fromBase64(ss.toLatin1());
QByteArray rdc = qUncompress(rc);
//img.loadFromData(rdc,"JPEG");//解释为jpg格式的图像
img.loadFromData(rdc);//解释为jpg格式的图像
QImage image;
image = pixmapScale(img, m_currentIndex);
rc.clear();
tcpSocket.write("ok");
update();
}
void TcpRev::wheelEvent(QWheelEvent* event)
{
m_currentIndex += event->delta() / 3000.0;
ui.lineEditRevSize_2->setText(QString::number(m_currentIndex));
if (event->delta()<0 && m_currentIndex<0.13)
{
m_currentIndex = m_currentIndex - 0.05;
}
else
{
m_currentIndex += event->delta() / 1000.0;
}
if (event->delta() < 0 && m_currentIndex <0.02)
{
m_currentIndex = 0.01;
}
QImage image;
image = pixmapScale(img, m_currentIndex);
ui.widget->show();
tcpSocket.write("ok");
update();
}
QImage TcpRev::pixmapScale(const QImage& image, const double& index)
{
QImage r_image;
r_image = image.scaled(image.width() * index, image.height() * index, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
ui.labelImage_2->setPixmap(QPixmap::fromImage(r_image));
ui.labelImage_2->resize(r_image.size());
tcpSocket.write("ok");
return r_image;
}
void TcpRev::ShowNewsR(QString ch_z, QString mess)
{
QString tempText;
QByteArray tem1 = ch_z.toUtf8();
QByteArray tem2 = mess.toLatin1();
tempText.sprintf("%s:%s", tem1.data(), tem2.data());
ui.newEdit_2->append(tempText);
}
void TcpRev::TimerEvent()
{
uint32_t nDevNum = 1;
// TODO: Add your message handler code here and/or call default
uint32_t i = 0; //循环变量
static int s_nCont = 0; //累加值
static time_t s_lTimeFirst = clock();
static time_t s_lTimeSecond = clock();
if ((nDevNum <= 0))
{
return;
}
//统计帧率
s_nCont++;
if (s_nCont >= 10)
{
s_lTimeFirst = clock();
for (i = 0; i < nDevNum; i++)
{
fFps = m_npfpsCont * 1000 / (float)(s_lTimeFirst - s_lTimeSecond);
m_npfpsCont = 0;
}
s_lTimeSecond = clock();
s_nCont = 0;
}
ui.label_fps->setText(QString::number(fFps));
}
此致