我的大学毕设,直播系统的设计

前言:大学时光匆匆而过转瞬即逝,再回首已经分不清是大一还是大四了。

1:项目环境:debian10,gcc 10.2.1版本,php7.4.3,mysql 5.7.26,nginx1.15.11

win10下:

  前后端环境:nginx1.15.11,php7.4.3,mysql 5.7.26使用小皮面板。下载移步于:小皮面板

debian10下:

  IM环境:gcc 10.2.1版本,

  安装方法:

  

su root
apt update
apt install build-essential
//查看gcc与g++版本
gcc --version
g++ --version

还需要nginx与http-flv用于直播推拉流的环境

创建一个nginx文件夹用于存储

mkdir /nginx 
cd nginx

下载nginx

wget http://nginx.org/download/nginx-1.18.0.tar.gz

下载Nginx-http-flv-module模块

wget https://github.com/winshining/nginx-http-flv-module/archive/master.zip

解压Nginx与http-flv模块

tar -zxvf nginx-1.18.0.tar.gz

unzip nginx-http-flv-master.zip

安装相关依赖

apt install gcc //前面安装了gcc可以不用再次安装

apt install libpcre3 libpcre3-dev

apt install openssl libssl-dev

apt install zlib1g-dev

进入解压后的nginx文件我这里是1.18版本

cd nginx-1.18.0/

./configure --add-module=/nginx/nginx-http-flv-master/

这里--add-module=后面的路径一定要是绝对路径 一定要是

make && make install
至此环境搭建成功了

运行目录:/usr/local/nginx/sbin/nginx

配置目录:/usr/local/nginx/conf/nginx.conf

#我的nginx配置
#user  nobody;
worker_processes  1;
events {
    worker_connections  1024;
}
rtmp_auto_push on;
rtmp_auto_push_reconnect 1s;
rtmp_socket_dir /tmp;
rtmp {
    server {
        listen 8082;  # 接受推流的端口号
        chunk_size 8192; # 单一推流数据包的最大容量?
        application myapp { # myapp 模块,可以自行更换名字
            live on; # 打开直播
            # 非常重要, 设定让ngnix断开阻塞中的连接, 才能触发exec_record_done
            # 以及客户端的LFLiveKit reconnectCount自动重新连接才会好用
            drop_idle_publisher 5s;
            meta off; # 为了兼容网页前端的 flv.js,设置为 off 可以避免报错
            gop_cache off; # 支持GOP缓存,以减少首屏时间
            allow play all; # 允许来自任何 ip 的人拉流
        }
    }
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;

    server {
        listen       8083;
        server_name  localhost;
        location / {
            root   html;
            index  index.html index.htm;
        }

        location /live { # 拉流时的 uri ,可以自行修改
            flv_live on; # 打开 http-flv 服务
            chunked_transfer_encoding on;
            add_header 'Access-Control-Allow-Origin' '*'; # 允许跨域
            add_header 'Access-Control-Allow-Credentials' 'true';
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
} 

检查一下是否安装成功:nginx -V

 检查配置文件:nginx -t

 至此我们所有环境都安装完成;

2:代码实现等:

系统最核心的点就是websokcet的编码解码,具体细节可以看我之前的websokcet聊天室那一节:

 

//获取Sec-WebSocket-Key的值
char * fetchSecKey(const char * buf){
    char *key;
    const char *flag="Sec-WebSocket-Key: ";
    int i=0, bufLen=0;
    key=(char *)malloc(256);
    memset(key,0, 256);
    if(!buf){
      return NULL;
    }
    const char* keyBegin=strstr(buf,flag);
    if(!keyBegin){
      return NULL;
    }
    //读取Sec-WebSocket-Key后面的
    keyBegin+=strlen(flag);
    bufLen=strlen(buf);
    for(i=0;i<bufLen;i++){
        if(keyBegin[i]==0x0A||keyBegin[i]==0x0D){
            break;
        }
        key[i]=keyBegin[i];
    }
  return key;
}

//获取加密后的值
char* get_comm_key(char *key){
    const char *mofa="258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
    char *temp_data=(char *)malloc(strlen(key)+strlen(mofa)+1);
    sprintf(temp_data,"%s%s",key,mofa);
    const char *base64_table="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    size_t len = strlen(temp_data);
    unsigned char sha1[SHA_DIGEST_LENGTH];
    SHA1((const unsigned char *)temp_data,len,sha1);
    int sha1_len=strlen((const char *)sha1);
    //定义base64编码后的长度
    int de_len=0;
    if(sha1_len%3==0){
        de_len=(sha1_len/3)*4;
    }else{
        de_len=(sha1_len/3+1)*4;
    }
    // 定义字符数组长度
    char *code_value=(char *)malloc(de_len+1);
    code_value[de_len]='\0';
    //三个一组依次写入
    for(int i=0,j=0;i<sha1_len;i+=3,j+=4){
        //这里是3个齐全的
        if(i+3<sha1_len){
            code_value[j]=base64_table[sha1[i]>>2];
            code_value[j+1]=base64_table[(sha1[i] & 0x3)<<4 | sha1[i+1]>>4];
            code_value[j+2]=base64_table[(sha1[i+1] & 0xf)<<2 | sha1[i+2]>>6];
            code_value[j+3]=base64_table[sha1[i+2] & 0x3f];
        }else{
            //当没有3个时
            int c=sha1_len-i;
            if(c==1){
                code_value[j]=base64_table[sha1[i]>>2];
                code_value[j+1]=base64_table[(sha1[i] & 0x3)<<4];
            }else if(c==2){
                code_value[j]=base64_table[sha1[i]>>2];
                code_value[j+1]=base64_table[(sha1[i] & 0x3)<<4 | sha1[i+1]>>4];
                code_value[j+2]=base64_table[(sha1[i+1] & 0xf)<<2];
            }
        }
    }
    //末尾填写=
    switch(sha1_len % 3)  {  
        case 1:  
            code_value[de_len-2] = '=';  
            code_value[de_len-1] = '=';  
            break;  
        case 2:  
            code_value[de_len-1] = '=';  
            break;  
    } 
    free(temp_data);
    return code_value;
}

//加密获得电脑段key
char * computeAcceptKey(const char * buf){
    char * clientKey=fetchSecKey(buf);
    // char * serverKey=(char *)malloc(100); 
    char * serverKey=get_comm_key(clientKey);
    free(clientKey);
    printf("sever_key=%s\n",serverKey);
    return serverKey;
}
//握手
void shakeHand(int connfd,const char *serverKey){
    char *responseHeader=(char *)malloc(sizeof("a")*200);
    if(!connfd){
        return;
    }
    if(!serverKey){
        return;
    }
    memset(responseHeader,'\0',200);
    sprintf(responseHeader, "HTTP/1.1 101 Switching Protocols\r\n");
    sprintf(responseHeader, "%sUpgrade: websocket\r\n", responseHeader);
    sprintf(responseHeader, "%sConnection: Upgrade\r\n", responseHeader);
    sprintf(responseHeader, "%sSec-WebSocket-Accept: %s\r\n\r\n", responseHeader, serverKey);
    send(connfd,responseHeader,strlen(responseHeader),0);
    free(responseHeader);
}
//数据解码
char* dcode(char *buf,int buf_len){
    int ret =0;
    char* mask = NULL;
    int mask_num=0;
    u_int len = (buf[1]&0x7f);
    if(len==126){
        //数据真实长度
        len=((buf[2]) | (buf[3] << 8));
        if(buf[2]==0){
            len=(buf[3] & 0x000000ff);
        }else{
            len=((buf[2]&0x00ff)<<8 | (buf[3] & 0x00ff));
        }
        mask_num=2;
        // 获取真实长度

    }if(len==127){
        return NULL;
    }
    //开始解码
    mask=buf+2+mask_num;
    char* tmp_msg;

    tmp_msg=(char*)malloc(sizeof(char)*len+1);
    tmp_msg[len]=0;
    char *raw_data =buf+4+2+mask_num;
    for(int i=0;i<len;i++){
        tmp_msg[i] = raw_data[i] ^ mask[i % 4];
    }
    return (char*)tmp_msg;
}
//数据编码
char* ecode(char *buf){
    int buf_len=strlen(buf);
    char* send_buffer=NULL;
    if(buf_len<126){
        send_buffer=(char *)malloc(buf_len+3);
        memset(send_buffer,0,buf_len+3);
        send_buffer[0] = 0x81;
        send_buffer[1] = buf_len;
        memcpy(send_buffer+2,buf,buf_len);
    }else if(buf_len<65535){
        send_buffer=(char *)malloc(buf_len+5);
        memset(send_buffer,0,buf_len+5);
        send_buffer[0] = 0x81;
        send_buffer[1] = 126;
        send_buffer[2]=(buf_len>>8) & 255;
        send_buffer[3]=buf_len & 255;
        memcpy(send_buffer+4,buf,buf_len);
    }
    return send_buffer;
}

 

前端就没啥好说的;

 

3:系统运行:

第一步:启动debian中的nginx环境;

cd /usr/local/nginx/sbin/nginx &&./nginx

 

 

 

 

 

 

 

 

 

 

 

 

如图就是开启成功。

进入IM文件夹运行命令:gcc main.cpp -lstdc++ -lm -lpthread -lcrypto -o main && ./main

 如果提示错误就执行./main直到成功为止

如果需要修改端口则在main.cpp中修改:

 接下来就是前后端运行了:

 启动小皮中的这两个环境

创建一个网站,设置根目录,然后在浏览器中输入对应的域名就可以了

对了记得修改文件中的数据库账号密码等等以及导入数据库

 

 导入数据库文件

 

 

 

开直播只需要下载一个obs中设置对应的obs和推流码就可以了

 

 

 

最后附上项目下载地址地址:

链接:https://pan.baidu.com/s/1fDhOwlbpZtyC1CaZ2bNv8A?pwd=53fq
提取码:53fq

posted @ 2024-05-17 22:57  鬼灰也  阅读(69)  评论(0)    收藏  举报