Peercast核心代碼執行流程

來源:互聯網
上載者:User

執行的流程大致如下:
Peercast啟動時建立servMgr對象
servMgr啟動兩個伺服器線程,分別為servProc和idleProc
servProc啟動兩個監聽servent,分別用於監聽7144和7145連接埠
監聽servent啟動伺服器監聽線程Servent::servProc
當伺服器監聽線程監測到有新串連進入時,給這個串連分配新的servent
新的servent初始化串連資訊,並啟動incomingProc線程
incomingProc線程調用handshakeIncoming進行處理
handshakeIncoming讀取發送進來的請求,若為HTTP請求,則調用handshakeHTTP進行處理
handshakeHTTP處理HTTP請求,並做出相應的回複.其中若是頻道請求則調用handshakePLS進行處理,若是控制請求(ADMIN請求)則調用handshakeCmd進行處理,如果是播放請求則調用triggerChannel進行相應處理(此部分詳見播放模組分析)

WINDOWS程式都是從WinMain開始執行
int APIENTRY WinMain()
{
 peercastInst = new MyPeercastInst();
 peercastApp = new MyPeercastApp();

 peercastInst->init();
}

// 整個程式的初始化,建立sys、servMgr和chanMgr對象以及從設定檔中讀取資訊
// sys、servMgr和chanMgr作為系統中三個最重要的全域變數,支撐起了Peercast核心代碼的大部分操作
// 其中sys用來提供底層操作,如建立SOCKET和擷取系統時間等,可理解為一個實現系統庫的類的對象
// servMgr用來管理網路傳輸,實現監聽、發送、接收資訊等功能,chanMgr用來實現對頻道的管理
void APICALL PeercastInstance::init()
{
 sys = createSys();
 servMgr = new ServMgr();
 chanMgr = new ChanMgr();

 //讀取設定檔中配置資訊
 if (peercastApp->getIniFilename())
  servMgr->loadSettings(peercastApp->getIniFilename());

 servMgr->start();
}

// servMgr啟動兩個線程,其中serverProc(伺服器線程)監聽7144連接埠,處理進來的串連和發送資料
// idleProc在程式的空閑時間進行操作,如向YP發送資訊等
bool ServMgr::start()
{
 serverThread.func = ServMgr::serverProc;
 if (!sys->startThread(&serverThread))
  return false;

 idleThread.func = ServMgr::idleProc;
 if (!sys->startThread(&idleThread))
  return false;

 return true;
}

//下面我們看看伺服器線程的執行情況
// --------------------------------------------------
// 啟動伺服器處理序,分配兩個servent,並初始化sock,預設serv監聽7144連接埠,serv2監聽7145連接埠
int ServMgr::serverProc(ThreadInfo *thread)
{
 Servent *serv = servMgr->allocServent();
 Servent *serv2 = servMgr->allocServent();

 while (thread->active)
 {
  if (servMgr->autoServe)
  {
   if ((!serv->sock) || (!serv2->sock))
   {
    LOG_DEBUG("Starting servers");
    {
     Host h = servMgr->serverHost;

     if (!serv->sock)
      serv->initServer(h);

     h.port++;
     if (!serv2->sock)
      serv2->initServer(h);
    }
   }
  }else{
   // stop server
   serv->abort();  // force close
   serv2->abort();  // force close

   // cancel incoming connectuions
   Servent *s = servMgr->servents;
   while (s)
   {
    if (s->type == Servent::T_INCOMING)
     s->thread.active = false;
    s=s->next;
   }

   servMgr->setFirewall(ServMgr::FW_ON);
  }
   
  sys->sleepIdle();

 }

 sys->endThread(thread);

 return 0;
}

//每個監聽的servent啟動一個監聽線程
// 啟動serverProc線程進行伺服器監聽
bool Servent::initServer(Host &h)
{
 createSocket();
 sock->bind(h);
 thread.data = this;
 thread.func = serverProc;
 type = T_SERVER;
 if (!sys->startThread(&thread))
  throw StreamException("Can`t start thread");

 return true;
}

//下面我們看看伺服器監聽線程是如何啟動並執行
int Servent::serverProc(ThreadInfo *thread)
{
 Servent *sv = (Servent*)thread->data;

 try
 {
  if (!sv->sock)
   throw StreamException("Server has no socket");

  sv->setStatus(S_LISTENING);   //設定為監聽狀態

  char servIP[64];
  sv->sock->host.toStr(servIP);  //servIP為"127.0.0.1:7144"

  while ((thread->active) && (sv->sock->active()))
  {
   if (servMgr->numActiveOnPort(sv->sock->host.port) < servMgr->maxServIn)
   {
    ClientSocket *cs = sv->sock->accept(); //建立一個新的socket以接受串連
    //迴圈判斷cs的值,若cs不為空白,則表示有新的串連進入
    //這是非阻塞方式判斷是否有新串連的一種方法
    if (cs)
    { 
     LOG_DEBUG("accepted incoming");
     Servent *ns = servMgr->allocServent(); //建立servent ns來處理串連請求
     if (ns)
     {
      servMgr->lastIncoming = sys->getTime();
      ns->servPort = sv->sock->host.port;
      ns->networkID = servMgr->networkID;
      ns->initIncoming(cs,sv->allow);     //使用initIncoming處理髮送過來的資訊
     }else
      LOG_ERROR("Out of servents");
    }
   }
   sys->sleep(100);
  }
 }catch(StreamException &e)
 {
  LOG_ERROR("Server Error: %s:%d",e.msg,e.err);
 }

 
 LOG_DEBUG("Server stopped");

 sv->kill();
 sys->endThread(thread);
 return 0;
}

// 當監聽伺服器線程檢測到有新串連進入時,分配新的servent,並初始化Incoming,啟動線程調用incomingProc進行incoming的處理
void Servent::initIncoming(ClientSocket *s, unsigned int a)
{

 try{

  checkFree();

  type = T_INCOMING;
  sock = s;
  allow = a;
  thread.data = this;
  thread.func = incomingProc;

  setStatus(S_PROTOCOL);

  char ipStr[64];
  sock->host.toStr(ipStr);
  LOG_DEBUG("Incoming from %s",ipStr);

  if (!sys->startThread(&thread))
   throw StreamException("Can`t start thread");
 }catch(StreamException &e)
 {
  //LOG_ERROR("!!FATAL!! Incoming error: %s",e.msg);
  //servMgr->shutdownTimer = 1;   
  kill();

  LOG_ERROR("INCOMING FAILED: %s",e.msg);

 }
}

// 調用handshakeIncoming進行Incoming的處理
int Servent::incomingProc(ThreadInfo *thread)
{
// thread->lock();

 Servent *sv = (Servent*)thread->data;
 
 char ipStr[64];
 sv->sock->host.toStr(ipStr);

 try
 {
  sv->handshakeIncoming();
 }catch(HTTPException &e)
 {
  try
  {
   sv->sock->writeLine(e.msg);
   if (e.code == 401)
    sv->sock->writeLine("WWW-Authenticate: Basic realm=/"PeerCast/"");
   sv->sock->writeLine("");
  }catch(StreamException &){}
  LOG_ERROR("Incoming from %s: %s",ipStr,e.msg);
 }catch(StreamException &e)
 {
  LOG_ERROR("Incoming from %s: %s",ipStr,e.msg);
 }

 sv->kill();
 sys->endThread(thread);
 return 0;
}

 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.