搭建一個流媒體伺服器–引子

來源:互聯網
上載者:User

在家休息一段時間了,中間有小公司老闆邀請,也有企鵝的幾個事業部的邀請,說實話要是放在以前應該都挺有興趣,不過現在看的淡了。

和企鵝幾個HR聊過,人家總是自我感覺良好,以為薪水高一點就可以搞定原則了,其實在南山住的人有哪個不知道那個半夜12點還開著燈的公司,那個號稱不夜城的公司。簽企鵝說不定就是在出賣健康,出賣生命,只是過程看起來比較華麗。

現在互連網公司都有一個跡象,加班都朝著無底線的方向走。

曾經一直覺得這都很正常,估計這樣想的人不在少數。直到前段時間遇到一位外籍同事,人家每天都是朝9晚6,儘管其他人都搞到晚上9點多。有次我不解,就直接問他為什麼這麼早走,結果他說這一點都不奇怪,他回家還要做飯,還有家務要做。我靠,這答案多麼簡潔啊,震暈了我那肽合金的狗腦,居然還有天天回家做飯的同事。

記得兩年前把爸媽接深圳來的時候,前一兩個星期,老媽總在幫我洗衣服,洗被子,老爸則是在屋裡抹抹掃掃,二老還不停的說我懶,不知道大家有沒有這樣的經曆。

現在想想,也許真不能怪我,每天下班都9點了,到家都10點多了,睡覺起碼也要到11點多以後了,要是再有心思在家務上,那我真成聖男了。

其實,有時候做家務也是一種奢侈,人家老外的生活咱還只是停留在想想上面,而且也只能想想。

不過衣服還是要常洗的哈,保持新鮮乾淨總是對的,後來我想到了一個好方法,就是一直帶爸媽在身邊,至少我可以每天換一次衣服,連洗衣機都省了。

朋友因為業務需要,要做一個流媒體伺服器,問我要不要幫忙,我想反正閑著也是閑著,還不如給他支點招,不過這哥們還真懶,一看我幫他,就乾脆整個讓我寫了。

記得以前在迅雷的時候,迅雷的流媒體伺服器有基於RTMP/HLS的,能夠適應各個網路環境。但是現在這個應用情境是P-S模式,用RTSP也就夠了。

市面上現在的流媒體伺服器有live555,darwin等。

拿live555來看,它是一個用C++開發的基於select 模型的RTSP流媒體伺服器。

說實話,代碼的可讀性和代碼風格不能推崇,隨處可見的注釋,拿其中的解析函數為例:

unsigned j = i+1;  while (j < reqStrSize && (reqStr[j] == ' ' || reqStr[j] == '\t')) ++j; // skip over any additional white space  for (; (int)j < (int)(reqStrSize-8); ++j) {    if ((reqStr[j] == 'r' || reqStr[j] == 'R')&& (reqStr[j+1] == 't' || reqStr[j+1] == 'T')&& (reqStr[j+2] == 's' || reqStr[j+2] == 'S')&& (reqStr[j+3] == 'p' || reqStr[j+3] == 'P')&& reqStr[j+4] == ':' && reqStr[j+5] == '/') {      j += 6;      if (reqStr[j] == '/') {// This is a "rtsp://" URL; skip over the host:port part that follows:++j;while (j < reqStrSize && reqStr[j] != '/' && reqStr[j] != ' ') ++j;      } else {// This is a "rtsp:/" URL; back up to the "/":--j;      }      i = j;      break;    }  }  // Look for the URL suffix (before the following "RTSP/"):  parseSucceeded = False;  for (unsigned k = i+1; (int)k < (int)(reqStrSize-5); ++k) {    if (reqStr[k] == 'R' && reqStr[k+1] == 'T' &&reqStr[k+2] == 'S' && reqStr[k+3] == 'P' && reqStr[k+4] == '/') {      while (--k >= i && reqStr[k] == ' ') {} // go back over all spaces before "RTSP/"      unsigned k1 = k;      while (k1 > i && reqStr[k1] != '/') --k1;      // ASSERT: At this point      //   i: first space or slash after "host" or "host:port"      //   k: last non-space before "RTSP/"      //   k1: last slash in the range [i,k]      // The URL suffix comes from [k1+1,k]      // Copy "resultURLSuffix":      unsigned n = 0, k2 = k1+1;      if (i <= k) { // There's a slash after "host" or "host:port"        if (k - k1 + 1 > resultURLSuffixMaxSize) return False; // there's no room        while (k2 <= k) resultURLSuffix[n++] = reqStr[k2++];      }      resultURLSuffix[n] = '\0';      // The URL 'pre-suffix' comes from [i+1,k1-1]      // Copy "resultURLPreSuffix":      n = 0; k2 = i + 1;      if (i <= k) { // There's a slash after "host" or "host:port"        if (k1 - i > resultURLPreSuffixMaxSize) return False; // there's no room        while (k2 <= k1 - 1) resultURLPreSuffix[n++] = reqStr[k2++];      }      resultURLPreSuffix[n] = '\0';      decodeURL(resultURLPreSuffix);      i = k + 7; // to go past " RTSP/"      parseSucceeded = True;      break;    }  }

這段代碼的主要功能是解析RTSP頭:

比較字串的時候,其實可以將 ‘RTSP'轉換成整型再進行比較。

另外從CPU運算上來看,第25行和51行都可最佳化。

live555 將事件與事務放在一線程中進行處理,事件模型又是基於古老的select 模型,而事務基本都是有IO的,因此當並發量達到一定程度,伺服器就全在跑IO了。

實際上這樣的業務需要和事件分隔開,否則就成了“紅管子”。

不過live555的確可以完成RTSP協議,這一點是無可厚非的。

我的流媒體伺服器要從效能上超越live555是完全可能的,由於是基於新的高效事件模型epoll,又是基於多線程的架構,目前市面上還缺這樣的產品。為了方便大家研究,我準備對伺服器的開發過程進行連載。

如果將整個系列博文看成一桌菜的話,那今天先上一道開胃菜,流媒體請求的資料結構,大家可以先從請求入手,看看一個請求會涉及到哪些參數。

struct yumei_rtsp_s{    long long                client_ip;    int                      udp_port;    yumei_rtsp_media_t      *media;    yumei_rtsp_track_t      *track;    };struct yumei_rtsp_req_s{    int                            version;    int                            req_id;    int                            req_type;    long long                      session_id;    char                           header[ 4 ];    void                          *media_name;    void                          *track_name;    void                          *req_cmd;    void                          *user_agent;    void                          *transport;    void                          *accept;    void                          *range;};

業務定義與處理函數:

typedef int (*yumei_rtsp_busi_handle )( yumei_rtsp_busi_t *busi );struct yumei_rtsp_busi_s{    void                          *conn;    void                          *pool;    void                          *rtsp;        yumei_rtsp_req_t               req;    yumei_rtsp_busi_handle         handle;    };int yumei_rtsp_busi_handle_options( yumei_rtsp_busi_t  *busi );int yumei_rtsp_busi_handle_describe( yumei_rtsp_busi_t *busi );int yumei_rtsp_busi_handle_setup( yumei_rtsp_busi_t    *busi );int yumei_rtsp_busi_handle_play( yumei_rtsp_busi_t     *busi );int yumei_rtsp_busi_handle_pause( yumei_rtsp_busi_t    *busi );int yumei_rtsp_busi_handle_teardown( yumei_rtsp_busi_t    *busi );int yumei_rtsp_busi_handle_get_parameter( yumei_rtsp_busi_t    *busi );int yumei_rtsp_busi_handle_set_parameter( yumei_rtsp_busi_t    *busi );

再上一個簡單的業務函數:

int yumei_rtsp_busi_header( yumei_rtsp_busi_t  *busi ){    yumei_conn_t        *conn;    yumei_mem_buf_t     *sb;    int                  len;    const char*          date;        conn = busi->conn;    sb = conn->send_buf;        date = yumei_time_get_current_buf();        len = sprintf( sb->data, rtsp_rsp_header, busi->req_id, date );        sb->pos = len;        return YUMEI_RTSP_OK;}int yumei_rtsp_busi_handle_options( yumei_rtsp_busi_t  *busi ){     yumei_conn_t        *conn;    yumei_mem_buf_t     *sb;    int                  len, len2;        conn = busi->conn;    sb = conn->send_buf;        yumei_rtsp_busi_header( busi );        len = sb->pos - 1;        len2 = strcpy( sb->data + len, rtsp_rsp_options );        sb->pos = len + len2;        return YUMEI_RTSP_OK;        }

首先至少從代碼已經做到清晰簡潔了。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.