2980|1

111

帖子

0

TA的资源

一粒金砂(中级)

楼主
 

Hi3518重生记(三)minihttp中的http+mjpeg排bug [复制链接]

(一)BUG

经过群里的技术大佬们不懈努力,终于查出minihttp的bug出自tcp socket的意外断链,导致mjpeg的通信管道出问题。那么就需要对这种异常情况处理。

(二)超时处理

1-send超时返回

通过控制台printf排查,查出出bug时,是在【server_thread】线程里面调用send_mjpeg()函数时,卡在了send_to_client中的send这一socket发送函数内。

解决方法:

server_thread主循环开头加入超时处理协议:

SocketTimeoutChange(client_fd, 0,900);

 

函数定义:

 

void SocketTimeoutChange(int client_fd, int sec, int msec)
{
    struct timeval timeout = {sec, msec};
    int ret = setsockopt(client_fd, SOL_SOCKET, SO_SNDTIMEO, (const char *)&timeout, sizeof(timeout));
}

2-超时之后关闭socket,修改send_to_client函数

int send_to_client(int i, char* buf, ssize_t size) {;
    if (send_to_fd(client_fds[i].socket_fd, buf, size) < 0)
    {
        free_client(i);
        return -1;
    }
    return 0;
}

 

3-重启通道

光是关闭连接不够的,通道被破坏了,重新连接也接收不到mjpeg,需要重启 :

int restart_channal()
{

    printf("\tmjpegdead restart!-\t");

    //stop
    if (HI_MPI_VENC_StopRecvPic(g_mjpg_venc_chn) == HI_SUCCESS)
        printf("--\t");
    else
    {
        printf("->stop error\n");
        return -1;
    }

    //reset
    if (HI_MPI_VENC_ResetChn(g_mjpg_venc_chn) == HI_SUCCESS)
        printf("--\t");
    else
    {
        printf("->reset error\n");
    }


    //start
    if (HI_MPI_VENC_StartRecvPic(g_mjpg_venc_chn) == HI_SUCCESS)
        printf("--\t");
    else
    {
        printf("->restart error\n");
    }

    printf("-mjpeg finish!\n");
    return 0;
}

重启要重启在VENC的线程里面,不能在server_thread线程里面关完就在那个线程重启通道,会报错:

首先在send_to_fd里面设置一个标志位:

if (len < 0)
        {
            printf("~>len<0 error\t");
            g_resetChannalFlag = true;
            return -1;
        }

 

在VENC_GetVencStreamProc函数(这也是个子线程)里面while主循环的一开始:

        if (g_resetChannalFlag == true)
        {
            restart_channal();
            g_resetChannalFlag = false;
        }

(三)超时处理

到这里可以满足单连接,出现问题时直接关闭socket

但多连接时,其他连接继续运行有机会出现其他BUG,这是由于上一个socket的严重卡顿(上面设置了900ms)导致另一个本来好好的socket连接也因为本次卡顿,而导致远方客户端异常断连,但这时候诡异的时,他不会因为socket发不出去而关闭,甚至发了几帧之后会因为mjpeg通道被破坏而彻底停止发送,更加不会触发上面的socket断连后重启通道的机制。

这时候可以从两个角度解决:

1-想方设法触发上面的机制

2-另外设置机制

第一种方法比较简单,而且方便使用,或许可以通过调用send_to_socket函数发送一些无关数据来实现触发。

但遗憾的是一开始因为代码耦合性过强,暂时没想到该怎么实现,因此我用第二种方式处理:

 

1-VENC_SaveStream()判断H264帧和MJPEG帧不对等:

int t_mjpegErrorCounter=0;
HI_S32 VENC_SaveStream(int chn_index, PAYLOAD_TYPE_E enType, VENC_STREAM_S *pstStream) {
    // printf("Chn: %d   VENC_SaveStream %d  packs: %d\n", chn_index, enType, pstStream->u32PackCount, pstStream);
    HI_S32 s32Ret;
    if (PT_H264 == enType) { s32Ret = VENC_SaveH264(chn_index,  pstStream); t_mjpegErrorCounter++;}
    else if (PT_MJPEG == enType) { s32Ret = VENC_SaveMJpeg(chn_index, pstStream); t_mjpegErrorCounter=0;}
    else if (PT_JPEG == enType) { s32Ret = VENC_SaveJpeg(chn_index, pstStream); }
    // else if (PT_H265 == enType) { s32Ret = SAMPLE_COMM_VENC_SaveH265(pFd, pstStream); }
    else { return HI_FAILURE; }
    if(t_mjpegErrorCounter>=100){
        printf("mjpeg error\n");
        sleep(1);
        FreeAllMjpegClient();
        g_resetChannalFlag = true;
        g_DestoryErrorFlag = true;
        t_mjpegErrorCounter = 0;
        // restart_channal();
    }
    return s32Ret;
}

 

1-这片代码运行在【VENC_GetVencStreamProc】子线程里

2-睡眠1s是必须的,得让【server_thread】子线程里面向所有socket发送完本次的图像缓冲

3-FreeAllMjpegClient关掉所有客户端socket

4-g_resetChannalFlag置位标志这个循环重新到【VENC_GetVencStreamProc】子线程循环开始时会重新

5-其中g_DestoryErrorFlag是新设计的标志位,代表严重错误出现,全部mjpeg的客户端断连。

void FreeAllMjpegClient()
{

    printf("~>free all client :\n");
    for (uint32_t i = 0; i < MAX_CLIENTS; ++i)
    {
        if (client_fds[i].socket_fd < 0)
            continue;
        if (client_fds[i].type != STREAM_MJPEG)
            continue;
        free_client(i);
    }
    printf("\n");
}

 

在【server_thread】子线程的循坏一开始:

    while (keepRunning) {
        // waiting for a new connection
        int client_fd = accept(server_fd, NULL, NULL);
        printf("=>new socket\n\taccept:%d\t",client_fd);
        if (client_fd == -1) break;
        if(g_DestoryErrorFlag == true)
        {
            // sleep(3);
            g_DestoryErrorFlag = false;
            while(g_resetChannalFlag==true);
            // g_DestoryErrorFlag == false;
            // goto _FOUROFOUR;
        }
……

 

其中下面那个while的作用是等待mjpeg通道重启完成,避免再次出现通道错误而进行阻塞。

执行文件及源码: minihttp_http+mjpeg优化版本V200510.zip (174.88 KB, 下载次数: 1)

此帖出自Linux开发论坛

最新回复

感谢楼主。代码写的很漂亮   详情 回复 发表于 2020-5-11 10:50
点赞 关注

回复
举报

18

帖子

10

TA的资源

一粒金砂(初级)

沙发
 

感谢楼主。代码写的很漂亮

此帖出自Linux开发论坛
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/7 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表