UDT中epoll對CLOSE狀態的處理

来源:http://www.cnblogs.com/shenlinken/archive/2016/06/27/5621388.html
-Advertisement-
Play Games

epoll_wait()返回可用uid時,對uid取狀態,本該是BROKEN的,卻取到CLOSED,然而,不能像處理BROKEN事件那樣處理CLOSED事件,這樣移除不了CLOSED事件,於是epoll_wait不斷返回該uid,就造成了死迴圈。跟蹤代碼至底層,尋找原因。 int CUDTUnite ...


epoll_wait()返回可用uid時,對uid取狀態,本該是BROKEN的,卻取到CLOSED,然而,不能像處理BROKEN事件那樣處理CLOSED事件,這樣移除不了CLOSED事件,於是epoll_wait不斷返回該uid,就造成了死迴圈。跟蹤代碼至底層,尋找原因。   int CUDTUnited::epoll_remove_usock(const int eid, const UDTSOCKET u) {    int ret = m_EPoll.remove_usock(eid, u);      CUDTSocket* s = locate(u);    if (NULL != s)    {       s->m_pUDT->removeEPoll(eid);    }    //else    //{    //   throw CUDTException(5, 4);    //}      return ret; }   CUDTSocket* CUDTUnited::locate(const UDTSOCKET u) {    CGuard cg(m_ControlLock);      map<UDTSOCKET, CUDTSocket*>::iterator i = m_Sockets.find(u);      if ((i == m_Sockets.end()) || (i->second->m_Status == CLOSED))       return NULL;      return i->second; }   void CUDT::removeEPoll(const int eid) {    // clear IO events notifications;    // since this happens after the epoll ID has been removed, they cannot be set again    set<int> remove;    remove.insert(eid);    s_UDTUnited.m_EPoll.update_events(m_SocketID, remove, UDT_EPOLL_IN | UDT_EPOLL_OUT, false);      CGuard::enterCS(s_UDTUnited.m_EPoll.m_EPollLock);    m_sPollID.erase(eid);    CGuard::leaveCS(s_UDTUnited.m_EPoll.m_EPollLock); }   CUDTUnited::epoll_remove_usock里,先locate目前uid的位置,但如果此時uid的狀態是CLOSED,則返回NULL, 於是,epoll_remove_usock無法再繼續調用removeEPoll,所以無法移除epoll事件。 但為什麼會發生CLOSED事件呢?按照作者的原意,應該是只會發生BROKEN事件,不會發生CLOSED事件的,繼續查找原因。   首先看看BROKEN事件怎麼發生的。   客戶端疑似斷開十秒以上之後, CUDT::checkTimers()做以下操作  ……  ……          m_bClosing = true;          m_bBroken = true;          m_iBrokenCounter = 30;            // update snd U list to remove this socket          m_pSndQueue->m_pSndUList->update(this);            releaseSynch();            // app can call any UDT API to learn the connection_broken error          s_UDTUnited.m_EPoll.update_events(m_SocketID, m_sPollID, UDT_EPOLL_IN | UDT_EPOLL_OUT | UDT_EPOLL_ERR, true);            CTimer::triggerEvent();  ……  …… 在這裡把m_bBroken置為true,並觸發epoll事件。 然而,在epoll_wait返回事件之前,還可能發生這個:   #ifndef WIN32    void* CUDTUnited::garbageCollect(void* p) #else    DWORD WINAPI CUDTUnited::garbageCollect(LPVOID p) #endif {      CUDTUnited* self = (CUDTUnited*)p;      CGuard gcguard(self->m_GCStopLock);      while (!self->m_bClosing)    {         self->checkBrokenSockets();  ……  ……   void CUDTUnited::checkBrokenSockets() {      CGuard cg(m_ControlLock);      // set of sockets To Be Closed and To Be Removed    vector<UDTSOCKET> tbc;    vector<UDTSOCKET> tbr;      for (map<UDTSOCKET, CUDTSocket*>::iterator i = m_Sockets.begin(); i != m_Sockets.end(); ++ i)    {       // check broken connection       if (i->second->m_pUDT->m_bBroken)       {          if (i->second->m_Status == LISTENING)          {             // for a listening socket, it should wait an extra 3 seconds in case a client is connecting             if (CTimer::getTime() - i->second->m_TimeStamp < 3000000)                continue;          }          else if ((i->second->m_pUDT->m_pRcvBuffer != NULL) && (i->second->m_pUDT->m_pRcvBuffer->getRcvDataSize() > 0) && (i->second->m_pUDT->m_iBrokenCounter -- > 0))          {             // if there is still data in the receiver buffer, wait longer             continue;          }            //close broken connections and start removal timer          i->second->m_Status = CLOSED;          i->second->m_TimeStamp = CTimer::getTime();          tbc.push_back(i->first);          m_ClosedSockets[i->first] = i->second; …… …… GC線程是UDT的垃圾回收處理,在UDT調用cleanup(),之前,會一直處於checkBrokenSocket和阻塞的迴圈中。 然後在checkBrokenSocket里,當socket的m_bBroken為true時,m_Status的狀態被置為CLOSED。   所以,這時候再用getsocketstate取socket的狀態,就會取到CLOSED,也就是明明是BROKEN事件,硬生生變成了CLOSED事件!然後接下去epoll事件的移除就失敗了。   於是,修改如下, 把 int CEPoll::remove_usock(const int eid, const UDTSOCKET& u) {    CGuard pg(m_EPollLock);      map<int, CEPollDesc>::iterator p = m_mPolls.find(eid);    if (p == m_mPolls.end())       throw CUDTException(5, 13);      p->second.m_sUDTSocksIn.erase(u);    p->second.m_sUDTSocksOut.erase(u);    p->second.m_sUDTSocksEx.erase(u);      return 0; } 改為 int CEPoll::remove_usock2(const int eid, const UDTSOCKET& u) {    CGuard pg(m_EPollLock);      map<int, CEPollDesc>::iterator p = m_mPolls.find(eid);    if (p == m_mPolls.end())       throw CUDTException(5, 13);      p->second.m_sUDTSocksIn.erase(u);    p->second.m_sUDTSocksOut.erase(u);    p->second.m_sUDTSocksEx.erase(u);      p->second.m_sUDTWrites.erase(u);    p->second.m_sUDTReads.erase(u);    p->second.m_sUDTExcepts.erase(u);      return 0; } 並去掉CUDTUnited::epoll_remove_usock()中對removeEPoll()的調用。   這是比較簡單也比較粗糙的改法,應該有更方便的思路才對。
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1,安裝oracle 10g資料庫並創建一個要恢復的資料庫相同一的實例(註意:最好是新安裝的資料庫,並且安裝的資料庫儘量和要恢復的資料庫的版本一致,並且實例必須一致); 2,以sysdba身份登錄:對控制文件進行備份; sqlplus /nolog;(此處不能加分號,否則黑屏視窗會一閃而過) con ...
  • K-Means聚類演算法是最為經典的,同時也是使用最為廣泛的一種基於劃分的聚類演算法,它屬於基於距離的無監督聚類演算法。KMeans演算法簡單實用,在機器學習演算法中占有重要的地位。對於KMeans演算法而言,如何確定K值,確實讓人頭疼的事情。 最近這幾天一直忙於構建公司的推薦引擎。對用戶群體的分類,要使用KM ...
  • 事務是什麼?事務關鍵在與其原子性。原子性概念是指可以把一些事情當作一個執行單元來看待。從資料庫角度看待。他是指應該全部執行或者全部不執行一條或多條語句的最小組合。當處理數據時候經常確保一件事發生另一件事也隨之發生。或者二件事都不發生。實際上可能達到程度是有幾十件事情或者更多的事情都必須一起發生或者都 ...
  • 電子書為網友wglzaj精心整理,這批資料下載量好評率都非常高,廣受oracle學習者歡迎。文檔共整理了12個精品專題和120個熱門資料的下載地址,推薦給大家希望大家喜歡。目錄0豆下載地址:http://down.51cto.com/data/428209目錄部分預覽: Oracle資料庫性能優化指 ...
  • 有時需要在網上租用空間或資料庫,Mysql成本低一些,所以想將sql server轉成mysql…… 註意:在安裝Mysql時要選擇文字集為utf8,否則將不能使用中文(當前也可以在創建資料庫時使用utf8,不過我不知道在ef生成資料庫時如何設置,希望高手指點) 一、在項目中引用mysql的EF包 ...
  • 對於設計和創建資料庫完全是個新手?沒關係,Joe Celko, 世界上讀者數量最多的SQL作者之一,會告訴你這些基礎。和往常一樣,即使是最專業的資料庫老手,也會給他們帶來驚喜。Joe是DMBS雜誌是多年來最受 讀者喜愛的作者。他在美國、英國,北歐,南美及非洲傳授SQL知識。他在ANSI / ISO ...
  • 一、Hadoop HA的Web頁面訪問 Hadoop開啟HA後,會同時存在兩個Master組件提供服務,其中正在使用的組件稱為Active,另一個作為備份稱為Standby,例如HDFS的NameNode、YARN 的ResourceManager。HDFS的web頁面只有通過Active的Name ...
  • 使用完藍燈後,每次使用IE瀏覽器都不能正常使用,於是有了下麵的這個方案 1、通過Win+R 打開註冊表編輯器(regedit) 進入目錄 HKEY_CURRENT_USER \ Software \ Microsoft \ Windowns \ CurrentVersion \ Internet S ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...