

























之前做的onvif设备模拟器,吹牛逼说支持千路并发,最近就遇到了真实的客户,真的要500路并发,当然网卡是前提必须满足的,带宽管够,亲自测试,超过150路打开就直接崩溃了,那为什么当时笃定可以上千路呢,因为本地测试的时候,用的64路,一看CPU占用才3%不到,按照这个估计大约的数量,推算得出来的,谁知道上了100路,性能开始指数级下降。还有个现象就是150路的时候,只在程序打开的时候崩溃,而如果是添加过程中,是不会出现的,于是先从这个着手,这个现象其实从推流大全程序的时候就有,当时推流大全就按照定时器排队处理推流,比如间隔0.1s处理一个,这样不会瞬间卡主,所以按照这个思路,模拟器这边也按照定时器排队处理,这样试下来,效果非常好,上了300路一点问题没有,起码程序这边不会崩溃,只是CPU占用非常高,突然想起来之前ABL的作者就亲自测试过各种流媒体服务程序的性能PK,发现mediamtx在windows上垫底,想到这里果断换zlm测试,明显优化了很多,300路占用也极大的降低了资源占用。很是奇怪,mediamtx用的go,而go号称天生高并发,为什么并发这么垃圾,搞不懂,据说在linux上性能还可以。经过这几个折腾后,用户电脑上测试500路也可以了,我这电脑配置带不动500路,几乎占满了。


#include "onvifdeviceserver.h"
#include "onvifdevicesearch.h"
#include "onvifdevicepush.h"
#include "onvifdevicelisten.h"
#include "onvifdevicehelper.h"
OnvifDeviceServer::OnvifDeviceServer(QObject *parent) : QObject(parent)
{
serverHost = "127.0.0.1";
serverIp = "127.0.0.1";
userName = "admin";
userPwd = "123456";
//实例化onvif搜索类并关联信号槽
isStart = false;
onvifSearch = new OnvifDeviceSearch(this);
connect(onvifSearch, SIGNAL(sendData(QByteArray)), this, SIGNAL(sendData(QByteArray)));
connect(onvifSearch, SIGNAL(receiveData(QByteArray)), this, SIGNAL(receiveData(QByteArray)));
connect(onvifSearch, SIGNAL(receiveInfo(QString)), this, SIGNAL(receiveInfo(QString)));
connect(onvifSearch, SIGNAL(receiveError(QString)), this, SIGNAL(receiveError(QString)));
//定时器排队处理
timerPush = new QTimer(this);
connect(timerPush, SIGNAL(timeout()), this, SLOT(pushOne()));
}
OnvifDeviceServer::~OnvifDeviceServer()
{
this->stop();
}
void OnvifDeviceServer::setPara(const QString &serverHost, const QString &serverIp, const QString &userName, const QString &userPwd, int pushInterval)
{
this->serverHost = serverHost;
this->serverIp = serverIp;
this->userName = userName;
this->userPwd = userPwd;
this->pushInterval = pushInterval;
}
bool OnvifDeviceServer::start()
{
foreach (OnvifDeviceListen *listen, listListen) {
if (!listen->isOk()) {
listen->start();
}
}
isStart = true;
this->startPush();
return onvifSearch->start(serverIp);
}
void OnvifDeviceServer::stop()
{
timerPush->stop();
foreach (OnvifDevicePush *push, listPush) {
push->stop();
}
foreach (OnvifDeviceListen *listen, listListen) {
listen->stop();
}
isStart = false;
onvifSearch->stop();
}
bool OnvifDeviceServer::append(const QString &flag, int port, const QString &mediaUrl, const QString &rtspUrl)
{
//构建onvif地址/已经存在说明冲突了
QString hard = OnvifDeviceHelper::getUuid();
QString addr = QString("http://%1:%2/onvif").arg(serverHost).arg(port);
if (listFlag.contains(flag)) {
QMessageBox::critical(NULL, "错误", "推流码重复, 请重新填写!");
return false;
} else if (listAddr.contains(addr)) {
QMessageBox::critical(NULL, "错误", "端口号重复, 请重新填写!");
return false;
}
//启动推流服务
OnvifDevicePush *push = new OnvifDevicePush;
connect(push, SIGNAL(pushStart(QString, int, int, bool)), this, SLOT(slot_pushStart(QString, int, int, bool)));
connect(push, SIGNAL(pushChanged(QString, int)), this, SIGNAL(pushChanged(QString, int)));
connect(push, SIGNAL(pushImage(QString, QImage)), this, SIGNAL(pushImage(QString, QImage)));
push->setPara(flag, mediaUrl, rtspUrl);
//启动监听服务
OnvifDeviceListen *listen = new OnvifDeviceListen;
connect(listen, SIGNAL(sendData(QByteArray)), this, SIGNAL(sendData(QByteArray)));
connect(listen, SIGNAL(receiveData(QByteArray)), this, SIGNAL(receiveData(QByteArray)));
connect(listen, SIGNAL(receiveInfo(QString)), this, SIGNAL(receiveInfo(QString)));
connect(listen, SIGNAL(receiveError(QString)), this, SIGNAL(receiveError(QString)));
connect(listen, SIGNAL(snapshot(QString, QTcpSocket *)), this, SLOT(slot_snapshot(QString, QTcpSocket *)));
listen->setPara(flag, hard, serverIp, port, addr, rtspUrl);
listen->setUserInfo(userName, userPwd);
//处于启动中则立即启动
if (isStart) {
//push->start();
listen->start();
}
listFlag << flag;
listHard << hard;
listAddr << addr;
listPush << push;
listListen << listen;
this->startPush();
onvifSearch->setPara(listHard, listAddr);
return true;
}
void OnvifDeviceServer::remove(const QString &flag)
{
timerPush->stop();
int index = listFlag.indexOf(flag);
if (index >= 0) {
listPush.at(index)->stop();
listPush.at(index)->deleteLater();
listListen.at(index)->stop();
listListen.at(index)->deleteLater();
listFlag.removeAt(index);
listAddr.removeAt(index);
listPush.removeAt(index);
listListen.removeAt(index);
onvifSearch->setPara(listHard, listAddr);
}
}
void OnvifDeviceServer::clear()
{
timerPush->stop();
foreach (OnvifDevicePush *push, listPush) {
push->stop();
push->deleteLater();
}
foreach (OnvifDeviceListen *listen, listListen) {
listen->stop();
listen->deleteLater();
}
listFlag.clear();
listAddr.clear();
listPush.clear();
listListen.clear();
onvifSearch->setPara(listHard, listAddr);
}
void OnvifDeviceServer::appendData(const QString &flag, const QByteArray &data)
{
int index = listFlag.indexOf(flag);
if (index >= 0) {
listPush.at(index)->appendData(data);
}
}
void OnvifDeviceServer::pushOne()
{
if (!isStart || pushIndex >= listPush.count() - 1) {
timerPush->stop();
emit pushFinsh();
return;
}
pushIndex++;
if (!listPush.at(pushIndex)->isOk()) {
listPush.at(pushIndex)->start();
} else {
this->pushOne();
}
}
void OnvifDeviceServer::startPush()
{
pushIndex = -1;
timerPush->stop();
timerPush->start(pushInterval < 50 ? 50 : pushInterval);
}
void OnvifDeviceServer::slot_snapshot(const QString &flag, QTcpSocket *socket)
{
int index = listFlag.indexOf(flag);
if (index >= 0) {
listPush.at(index)->snap(socket);
}
}
void OnvifDeviceServer::slot_pushStart(const QString &flag, int width, int height, bool start)
{
emit pushStart(flag, width, height, start);
int index = listFlag.indexOf(flag);
if (index >= 0) {
listListen.at(index)->setVideoInfo(25, width, height);
}
}
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。