江苏快三开奖结果

隨筆-95  評論-224  文章-24  trackbacks-0
  置頂隨筆
模板
    1. 空基類優化
    2. 元編程技術
        2.1. 選擇API
        2.2. 計算最值
        2.3. 類型選擇
    3. 封裝GCC原子操作
    4. 定制類對象的內存管理

算法
    1. 排序
        1.1. 改進的快速排序
        1.2. 原位統計排序     
    2. 多叉樹
        2.1. 深度優先存儲
        2.2. 迭代器的設計
        2.3. 前序遍歷
        2.4. 后序遍歷
        2.5. 兄弟遍歷
        2.6. 葉子遍歷
        2.7. 深度遍歷 
    3. 優先級隊列
        3.1. 原理
        3.2. 內幕
        3.3. 外觀
    4. RSA加解密的證明
    5. DSA數字簽名的推導

GUI
 
    1. MFC中的WM_COMMAND傳遞
    2. ATL和WTL中的消息反射
    3. 工作線程與消息循環
    4. 多窗口的組合與分離
        4.1. 接口
        4.2. 實現

跨平臺
    1. 用戶態自旋鎖
    2. 互斥鎖
    3. 信號量
    4. socket管道
    5. 鎖框架的設計與實現

網絡
    1. 運用狀態機異步接收變長包
    2. 基于OpenSSL實現的安全連接
    3. TCP/IP FAQ
        3.1. 鏈路層、網絡層和傳輸層
        3.2. 插口層和應用層
    4. Linux套接字與虛擬文件系統
        4.1. 初始化和創建
        4.2. 操作和銷毀
    5. Linux ICMP消息的產生與轉換
    6. nginx iocp
        6.1. tcp異步連接
        6.2. udp異步接收
        6.3. scm服務控制
    7. TCP分組丟失時的狀態變遷

Shell應用
    1. 自動生成并安裝服務腳本
    2. nginx升級與恢復
    3. 使用awk定位反匯編輸出
    4. 自動化批量編譯
posted @ 2014-04-10 16:04 春秋十二月 閱讀(1593) | 評論 (0)編輯 收藏
  2019年11月20日
描述
   nginx是一款著名的高性能開源Web與反向代理服務器,支持windows和linux操作系統,因為在windows系統上還不支持SCM(服務控制管理),所以只能以控制臺方式運行,但這樣并不是在后臺運行,也不能在系統登錄前啟動。針對這些問題,本方法通過改進源碼,使nginx良好地支持了SCM,方便了部署運行

特點
   最大地復用了nginx源碼;支持SCM,并兼容控制臺運行方式;統一處理異常退出而報告服務停止

實現

   變換原主函數
      將原來的main函數更名為ngx_main,并增加第3個參數is_scm來標識運行方式,非0表示服務方式,0表示控制臺方式,流程如下
                                    
      圖上紅色部分為插入的邏輯,其它部分為nginx原來的邏輯。由于服務初始化須將錯誤記錄在log(日志)中,所以應在初始化log模塊后調用

   增加主函數
      這個主函數也就是程序入口main,可被控制臺或SCM調用,當被SCM調用時,注冊服務以及啟動服務控制調度程序,流程如下
                                       
      如果以命令行啟動nginx 也就是master進程(管理進程),或nginx產生worker進程(工作進程)時,那么以控制臺方式調用main,進而以is_scm為0調用ngx_main,當ngx_main返回時,就表示master或worker進程退出了   

   服務主函數
      由SCM生成的一個邏輯線程調用,流程如下
                                         
      這里的邏輯線程代替了nginx的master進程,到這里就表明已經以SCM方式運行了,所以以is_scm為1調用ngx_main,當ngx_main返回時,就表明master進程退出了,應該更新服務狀態為已停止,然后返回表明當前服務結束了

   服務初始化
      由ngx_main調用,見變換原主函數流程圖,流程如下
                                          
      由于在nginx實現中,有多處出現異常錯誤而直接退出,因此首先注冊了進程退出處理器,在其內報告服務狀態為已停止,這樣只要當進程退出了,在SCM上就能看到已停止的狀態了

   服務控制處理器
      由SCM的主線程調用,流程如下
                                         
   
   調用關系
      下圖左邊為master進程調用模塊與函數,右邊為worker進程調用模塊與函數,委托主函數是ngx_main
            
posted @ 2019-11-20 19:45 春秋十二月 閱讀(188) | 評論 (0)編輯 收藏
  2019年11月6日
部署圖
   
   傳統的vss備份架構由于備份應用部署在應用服務器內,因此比較耗應用服務器的CPU和IO,特別是拷貝大量的文件,為了降低對應用服務器的干擾,可采用server-free架構,將耗時的拷貝移到另一機器即備份服務器實現,而應用服務器只負責占用資源及耗時很少的打快照。這種架構運用了vss可傳輸卷影拷貝的特性,要求快照處于共享存儲中,適用于Windows Server 2003 sp1以上版本

協作流程圖
   
   VSS快照代理端的SetContext要求設置成VSS_CTX_APP_BACKUP | VSS_VOLSNAP_ATTR_TRANSPORTABLE
posted @ 2019-11-06 18:01 春秋十二月 閱讀(230) | 評論 (0)編輯 收藏
1. 綁定變量作為一種優化查詢處理的方法,在性能上有利有弊,是一把雙刃劍。它的優勢在于可以共享庫緩存中的父游標,從而避免了硬解析及相關的開銷;劣勢在于因綁定變量掃視增加了查詢優化器選擇(非常)低效執行計劃的風險,即使支持自適應游標共享,也引入了游標感知判斷和謂詞選擇率估算的代價,而且在生成高效的執行計劃前至少有一次是無效率的。因此,是否使用綁定變量,需要衡量實際字面值與處理數據量帶來的解析執行的收益與損害,當損害大于收益時就不應該使用,反之當處理較少數據硬解析耗時比執行多時,就可以使用了

2. 存儲快照一般有三種層次:物理卷、文件系統和應用程序
   ◆ 物理卷快照基于卷扇區映射表實現,宜采用CoFW法,因為它不必每次寫io都去遍歷映射表,比RoFW快
   ◆ 文件系統快照基于inode樹即元數據復制實現,每當寫io時更新快照或源inode的指向,必要時向上回溯至根inode。有的文件系統比如NetApp公司的WAFL則更優,只須復制根inode,因為每次寫io時它會變但其下所有的inode不會變
   ◆ 應用程序快照最典型的就是數據庫,原理本質與上述兩種一樣,基于頁改變位圖,當page首次(相對于快照創建時刻)改變時拷貝到快照文件(一種稀疏文件),另外當撤消未提交事務或回滾事務時也會發生拷貝(此時快照慢慢不再稀疏),這是為了保證快照的可用一致性

3. 數據塊的加鎖有單機和分布式兩種情景,前者是為了同步單實例事務的并發,后者是為了協調分布式事務的同步,并與緩存一致性協議緊密聯系。undo,redo,undo/redo三種日志對數據臟塊與提交日志記錄落盤的順序要求各不同,因此恢復方式不同。脫服務器備份架構比較好,具有不占用應用服務器資源的優勢,而微軟的vss可傳輸卷影拷貝提供了這一支持,足見其技術的先進前瞻性

4. Oracle的實例恢復完全靠在線重做日志,介質恢復必須靠歸檔重做日志,以及在線重做日志。然而在線重做日志是有限數量的,那么Oracle是怎樣保證宕機經實例恢復后不丟數據?答案是檢查點。檢查點是數據庫中一個很重要的機制,被重做日志切換觸發,由DBWn執行刷新臟塊,并清除老的無用的在線重做日志,以允許被覆蓋

5. Linux內核的swap高速緩存和其它的緩存(比如page緩存)不太一樣,因為它存在的主要原因不是為了減少磁盤IO提高性能,而是解決換入換出共享匿名頁同步即并發swap的問題。那么它是唯一的方法嗎?不一定,可以遍歷所有的anon_vma鏈表,查找匿名頁對應的頁框是否已建立,但該方法沒有swap緩存快。當然,在換入操作很多的情景,swap緩存確實能提高系統性能

6. Linux內存回收的核心是LRU鏈表,Oracle的buffer cache也有個LRU,這兩種LRU的共同點是引用計數(標志)和非活躍鏈表,引用計數會影響一個對象是否移到非活躍鏈表,非活躍鏈表用于回收或覆蓋這個對象。對于Linux這個對象是頁框,移到非活躍鏈表取決于swap tendency;而Oracle則是數據塊buffer及其TCH

7. Linux內核中的反向映射讓我想起了Oracle中的反向鍵索引,它們的共同點都是為了高性能,前者是為了快速定位引用同一頁框的所有頁表項,從而方便共享內存的回收;后者是為了減少右側索引葉塊的競爭,從而降低緩沖區忙等待、提高并發量

8. mvcc與read uncommitted(簡稱RU)隔離級別的關系究竟如何?這取決于現代數據庫的實現。對于Oracle,RU和RC的讀實現都基于mvcc實現,換句話說Oracle其實沒有臟讀;對于MySQL innodb引擎,mvcc不適用于RU而只適用于RC/RR級別,因為RC/RR必須讀取修改已提交的數據,但基準點不同,前者查詢開始時、后者事務開始時,而RU則可讀取未提交的數據,當然用mvcc模擬實現RU應該也可以,只需要讀取當前新版本而非舊版本

9. 借助內核page cache的數據庫或者存儲引擎,一定程度上講,是粗暴懶惰的表現,這會導致系統負載比較重的情況下,io性能很差。所以為高性能,必須得處理好direct io,設計self cache,這樣一來,就避免了浪費在原先內核頁緩存的頁框,避免處理內核頁緩存和預讀的多余指令而提高了系統調用read和write的效率,同時減少了一次數據拷貝

10. SQL半連接的本質是在內連接的基礎上對內表去重,即使內表有符合多個連接條件的元組,也只匹配一條,從而減少了連接返回的結果集。一般地,簡單的in、exists和any子句,都采用半連接實現,但若內表本身保證了唯一性,則半連接可消除轉為內連接實現,或者內表數據量很小且外表存在索引,那么也會消除半連接,生成由內表驅動外表,外表走索引的執行計劃。由此一例看出,SQL優化器偏愛內連接,因為內連接帶來了驅動表選擇和謂詞下推的靈活,便于產生更優的執行計劃

11. 從Oracle數據庫內核角度講,游標代表SQL語句的句柄,包含了依賴對象及執行計劃等信息,它相當于linux的文件描述符和windows的句柄。打開或緩存的游標是指對應SQL語句所占的內存(父游標句柄、父堆0和子游標句柄的chunk)被加上kgl lock和pin鎖,意味著第三次后解析同樣的SQL不必再從library cache hash chain中加鎖查找而直接從PGA的子堆6地址中獲取并調用執行計劃,如此優化提高了并發度加快了查詢,這正是軟軟解析;軟軟解析前必須軟解析2次,目的是將library cache的執行計劃在PGA中做一份鏈接,軟解析前必須硬解析,目的是將執行計劃放在library cache中。然而,如果共享池空閑內存不足,或者依賴對象發生DDL操作導致執行計劃失效,那么執行計劃所占chunk可以被覆蓋釋放,這樣一來,軟(軟)解析時就需要重新生成執行計劃了

12. Oracle的內存管理粗略地類似于Linux內核,所不同的是內存分配單元,前者叫granule通常大小4M~16M,后者叫page通常4K;數據塊緩沖的分配類似伙伴算法,共享池(主要用于sql緩存)的chunk分配類似slab算法,共享池中的保留池類似基于slab的內存池

13. Oracle數據庫究竟是怎樣構建表數據塊的讀一致性版本?這是個比較復雜、細致和有趣的問題,核心流程如下
   ◆ 克隆數據塊,若不存在則先從磁盤讀,下面幾步以克隆塊為目標
   ◆ 根據ITL中的flag及lck,對所有已提交的事務做清除操作,即延遲塊清除。延遲塊清除為了獲取足夠精確的提交SCN填充到ITL,分2種情況,若事務表槽沒被覆蓋,則直接用其提交SCN;否則先從事務控制區獲取SCN,并判斷對于上界提交是否足夠精確,若不夠則需要回滾事務表一直找到合適的SCN或報錯ORA-01555
   ◆ 根據ITL中的uba,反向更改所有未提交的事務,也就是應用事務的undo記錄
   ◆ 根據ITL中的SCN,不斷反向更改大于目標SCN的已提交事務,直至遇見合適的已提交事務。這里也是應用undo記錄,但不同的是,除了應用行數據,還會從事務的第一個undo記錄找到先前即前一個已提交事務的ITL項拷貝回當前塊的對應ITL項

14. Oracle的多版本控制機制,為dml不僅提供了一致且正確的結果,還提高了并發性,可謂魚和熊掌兼得。那么它的缺點是什么?可能會導致熱表的IO增高,因為讀一致性需要不斷回滾多個事務對數據塊的修改,直到查詢開始時的數據。事務隔離級別read committed與read uncommitted的相同是不會臟讀,區別是前者會不可重復讀或幻讀

15. Sql*plus的ARRAYSIZE對查詢數據性能有重要的影響,這個值過大過小都不好,而是要接近一個數據塊所擁有的行數,如此僅一次邏輯IO就拿到了一批行。那么設置合適的ARRAYSIZE就一定能提高性能嗎?不一定,還要看所查詢的表使用了什么索引列及表數據在磁盤上的物理布局,若數據分散即聚簇因子低,則優化器會選用全表而非索引區間掃描,去執行這個查詢

16. IOT表如果為非主鍵列再建索引,那么就成二級索引。這時候查詢數據,需要兩次掃描,一是掃描二級索引得到IOT中的位置,二是掃描IOT本身匹配那個位置,之所以這樣是因為行記錄在IOT中的位置會變。而堆組織表,僅需一次掃描索引結構,得到rowid,再直接讀磁盤獲取行記錄。因此IOT上再建二級索引,并非明智的選擇

17. 相容性矩陣是封鎖調度的核心結構; 任意一個無環優先圖的封鎖調度都是沖突可串行化的; 基于樹協議的無環優先圖的封鎖調度,其整個事務集合的任意一個拓撲順序都是等價可串行化的

18. 總結解決數據庫丟失更新問題的方案
     ◆ 對于表不會被悲觀鎖鎖定的情景:使用基于select+update的樂觀鎖方法,查詢保存前映像,以便定位更新。前映像列可為全列,或新增一個時間戳列作為版本列
     ◆ 對于表可能會被悲觀鎖鎖定的情景:使用select…for update nowait+update的悲觀鎖方法,可以以全列的hash(虛擬列)來定位更新

19. 如果能夠在備庫上打開閃回,那么就可以做到既讓生產系統沒有承擔閃回的開銷,又能快速地為錯誤或故障恢復到以前某個時刻。一舉兩得比較完美,重做日志的創新使用真是太棒了

20. Oracle的索引聚簇表是個創新,它能將多個不同表的行按照索引列存儲在同一塊中,屬于物理上的join,這樣一來既可減少data buffer緩存的塊數而提高效率,又可提高多個相關表連接查詢的性能,比如通過外鍵約束的父子表。最典型的應用就是數據字典,數據字典對于查詢優化的成本估算很重要,由此可見oracle的設計之明智,mysql的innodb只有索引組織表,sql server有堆表和索引組織表,但它們都沒有索引聚簇表

21. 分布式事務處理是工程難題。Oracle的serializable串行隔離級別以樂觀鎖實現,所以并發度與非串行相當,需要注意的是:串行并不是說一個事務提交了才能處理下一個,而是多個事務間沒有沖突表現地像只有一個事務在運行,否則Oracle的serializable級別就不存在拋出ORA-08177錯誤了

22. 理清read uncommitted事務隔離級別的鎖策略:讀不加共享鎖,寫加排它鎖直至提交,這里的鎖是指lock;塊的緩沖區并發操作必須加鎖,這里的鎖是指latch,若不加,那臟讀讀到的數據可能是錯的。臟讀隔離級別允許讀修改但未提交的行記錄,這意味著讀不能被寫阻塞,也不能阻塞寫,所以不會申請共享鎖(顯式鎖定讀除外)

23. 與MySQL不同,Oracle的行鎖無需索引列的限制,是真正的行鎖,其實現為數據塊的屬性而非傳統的鎖管理器,但是它需要在事務commit或rollback時才釋放,如果存在慢sql,那么導致的阻塞會比較嚴重

24. 隔離是實現安全的一種辦法,其結果常被稱作“沙箱”。從這個意義上講Oracle很明智,因為它的事務沒有也不需要read uncommitted隔離級別,Oracle最低且默認的隔離級別是read committed,因為它有基于undo的多版本控制,天生非阻塞讀,根本不會臟讀。我想不出read uncommitted有什么好處,除了非阻塞讀及可能的高并發,要謹慎臟讀是危險不安全的

25. windows內存映射和linux內存映射的實現機制不太一樣,前者使用了內存區section的專用數據結構而不像后者重用了頁緩存,內存區的映射完全由內存管理器負責包括物理頁分配及臟頁面寫入器,與緩存管理器無關;緩存管理器基于內存管理器維護了文件塊數據的視圖,并提供了自己的延遲寫入器。這兩種寫入器即回刷,獨立并行地工作
posted @ 2019-11-06 11:29 春秋十二月 閱讀(1122) | 評論 (0)編輯 收藏
  2019年11月5日
腳本概述
   由于某些sdk或軟件依賴眾多的第三方庫,而從官網下載到windows主機或從linux傳到windows時,所依賴的so庫往往丟失符號鏈接,給編譯運行帶來不便,因此編寫了ctlsolink腳本,用于自動為單個so或某目錄下的眾多so或創建/刪除一級/二級符號鏈接。該腳本的用法如下:
   ● 第1參數為mk或rm子命令,mk表示創建,rm表示刪除
   ● 第2參數為文件或目錄
   
● 第3參數是可選的-r,且只能是-r,如果指定了,則表示不斷遞歸子目錄

腳本實現
   考慮到so庫帶版本一般多為libx.so.1,libx.so.1.2,libx.so.1.2.3這三種形式(x為庫名),對于前一種創建/刪除一級符號鏈接即可,后兩種則創建/刪除二級符號鏈接。為了精確地抽出一級和二級鏈接名稱,這里使用awk來匹配,用shell變量的最短匹配模式從尾部逐步刪除點號及數字,核心代碼如下   
 1    if [ "$dir" != "$self_dir" ] || [ "$name" != "$self_name" ]; then
 2        if echo $name | aw'{if($0~/\.so\.[0-9]{1,}\.[0-9]{1,}\.[0-9]{1,}$/) exit 0; else exit 1}'; then
 3            link_name=${name%.[0-9]*}
 4            link_name=${link_name%.[0-9]*}
 5            link_name=${link_name%.[0-9]*}
 6            link_name2=${name%.[0-9]*}
 7            link_name2=${link_name2%.[0-9]*}
 8        elif echo $name | awk '{if($0~/\.so\.[0-9]{1,}\.[0-9]{1,}$/) exit 0; else exit 1}'; then
 9            link_name=${name%.[0-9]*}
10            link_name=${link_name%.[0-9]*}
11            link_name2=${name%.[0-9]*}
12        elif echo $name | awk '{if($0~/\.so\.[0-9]{1,}$/) exit 0; else exit 1}'; then 
13            link_name=${name%.[0-9]*}
14        else
15            return
16        fi
17
18        if [ $do_mk = "yes" ]; then
19            #echo "name=$name, link_name=$link_name, link_name2=$link_name2"
20            if [ -"$link_name2" ]; then
21                ln -sf $name $link_name2
22                ln -sf $link_name2 $link_name
23            else
24                ln -sf $name $link_name
25            fi
26        else
27            if [ -n $link_name2 ]; then
28                rm -f $link_name2
29            fi
30            rm -f $link_name
31        fi
32    fi
   要注意的是,這兒不能使用%%刪除最長匹配的尾部來得到link_name,因為它的模式是.[0-9]*,這可能會錯誤地匹配了so前的部分,比如libx.1.so.2得到libx,而期望的是libx.1.so
   完整腳本下載:ctlsolink

運行效果
   初始狀態
   
   運行ctlsolink創建軟鏈接后
   
   運行ctlsolink刪除軟鏈接后
          
posted @ 2019-11-05 18:17 春秋十二月 閱讀(310) | 評論 (0)編輯 收藏
  2019年7月31日
   為了減少程序中的硬編碼,靈活按需管理字符串空間,使用了ATL中的CString類,代碼如下
 1         CString bstrComPathName;
 2         WCHAR componentPathName[1];
 3         DWORD dwNameLen = 1;    
 4 
 5         if (!GetComputerNameEx(ComputerNamePhysicalDnsFullyQualified, componentPathName, &dwNameLen))
 6         { 
 7             DWORD dwErr = GetLastError();
 8             if(ERROR_MORE_DATA==dwErr)
 9             {            
10                 if (!GetComputerNameEx(ComputerNamePhysicalDnsFullyQualified, bstrComPathName.GetBuffer(dwNameLen), &dwNameLen))
11                 { 
12                     zlog_error(g_zc, "GetComputerNameEx with ComputerNamePhysicalDnsFullyQualified fail: %d", GetLastError());
13                     return -1;
14                 }
15             }
16             else
17             {
18                 zlog_error(g_zc, "GetComputerNameEx with ComputerNamePhysicalDnsFullyQualified for fail: %d", dwErr);
19                 return -1;
20             }
21         }                
22         bstrComPathName.ReleaseBuffer(); 
    需要注意的是,GetBuffer方法雖提供方便了直接修改CString對象的內部緩沖區,但違背了面向對象設計的原則(由公開方法修改內部數據),因此不保證對象的完整性,在操作完成后一定要調用ReleaseBuffer
posted @ 2019-07-31 12:51 春秋十二月 閱讀(1201) | 評論 (0)編輯 收藏
  2018年11月16日
  在GNU make中文手冊這本書中,3.14節講到了依賴文件的自動生成,如下圖


  圖中的規則對C源文件和Makefile在同一目錄,是正確的。但是不在同一目錄的又希望依賴文件在對應的目錄下,比如src/log/log_file.c,希望依賴文件log_file.d生成在src/log/下。因為gcc(aix平臺xlc編譯器亦如此)生成的依賴文件內容中目標文件名沒有帶路徑,例如下所示
log_file.o: src/log/log_file.c src/log/log_file.h src/log/log_type.h \
 src/log/../base/io_ext.h

  所以sed就找不到src/log/log_file.o而替換了,改正后的規則如下
%.d: %.c
    $(CC) $(CFLAGS) $(INCS) $< $(MFLAGS) $@.$$$$;\
    sed 's,$(*F).o[ :]*,$*.o $@: ,g' < $@.$$$$ > $@;\
    $(RM) $@.$$$$

  該規則對C源文件和Makefile在同一目錄也適合,生成后的依賴文件內容如下
src/log/log_file.o src/log/log_file.d: src/log/log_file.c src/log/log_file.h src/log/log_type.h \
 src/log/../base/io_ext.h
posted @ 2018-11-16 12:08 春秋十二月 閱讀(494) | 評論 (0)編輯 收藏
  2017年12月29日
由于traceroute只能診斷UDP通信的包路由,不能確定TCP通信的實際路由(可能變換),因此編寫了本文。為方便描述,下面的IP、MAC和端口均為示例,實際診斷中可更換為具體的值

1. 如何判斷客戶端到服務器的TCP包,是否經過了網關
     在客戶端執行 tcpdump -i eno16777728 ether dst b0:b9:8a:69:65:3e and host 192.168.0.26 and tcp port 80  抓取經過網關且往返服務器的TCP端口為80的包
     eno16777728 接口名稱;ether 以太網鏈路,dst 目標(src表示源);b0:b9:8a:69:65:3e 網關MAC地址;192.168.0.26 服務器IP地址,80 監聽端口

     輸出結果分析
       ● 有輸出,則表示經過了網關
       ● 有部分輸出而TCP通信還在進行,則表示先前的包經過了網關,后來路由表項緩存被重定向更新,沒經過網關了
       ● 不斷輸出,則表示一直經過網關

2. 如何判斷路由表項緩存被重定向更新
     在客戶端執行 tcpdump -i eno16777728 src 192.168.1.1 and dst 192.168.1.45 and icmp  抓取來自網關和到達客戶端的所有icmp包
     192.168.1.1 網關IP;192.168.1.45 客戶端(出口)IP

     輸出結果分析
       ● 沒有輸出,則表示沒有收到rerdirect包,路由表項緩存不變
       ● 有輸出類似ICMP redirect 192.168.0.26 to host 192.168.0.26(前面一個IP表示到達服務器的直接路由IP,后一個表示服務器IP)
       ● 則表示收到了ICMP重定向包,內核會更新路由表項及緩存網關為192.168.0.26,下次通信時就直接發往192.168.0.26了

3. 如何控制接收ICMP重定向
      ● echo 0 | tee /proc/sys/net/ipv4/conf/*/accept_redirects    禁止所有網卡接收,可避免路由表項緩存被修改
      ● echo 1 | tee /proc/sys/net/ipv4/conf/*/accept_redirects    啟用所有網卡接收ICMP重定向消息

4. 查看、刷新路由表項緩存
      ● ip route get 192.168.0.26    可以從輸出中看到通住目標IP的實際路由
      ● ip route flush cache             清空路由表項緩存,下次通信時內核會查main表(即命令route輸出的表)以確定路由
posted @ 2017-12-29 17:24 春秋十二月 閱讀(1227) | 評論 (0)編輯 收藏
  2016年12月15日
前言
   近期有機會,深入了SSL/TLS協議原理與細節,并分析了相關密碼學內容,心得頗多,歷經半月,終于寫成了這份文檔。
   本人水平尚有限,錯誤難免,歡迎指正,不勝感激。

目錄
         

部分章節預覽
   第3章


   第5章第4節


   第11章第3節

全文
   下載地址:深入理解SSL/TLS技術內幕
posted @ 2016-12-15 17:16 春秋十二月 閱讀(1199) | 評論 (0)編輯 收藏
  2016年11月24日
算法描述
【公開密鑰】    
   p是512到1024位的素數
   q是160位長,并與p-1互素的因子
   g = h^((p-1)/q) mod p,其中h<p-1且g>1
   y = g^x mod p
【私有密鑰】
   x < q,長160位
【簽名】
   k為小于q的隨機數,k^-1為k模q的逆元,m為消息,H為單向散列函數
   r = (g^k mod p) mod q
   s = (k^-1(H(m)+xr)) mod q
【驗證】
   w = s^-1 mod q
   u1 = (H(m)w) mod q
   u2 = (rw) mod q
   v = ((g^u1 * y^u2) mod p) mod q
   若v = r,則簽名被驗證

驗簽推導
   1. 先證明兩個中間結論
      因(h,p)=1(p為素數且h<p,(a1,a1)是數論中的符號,記為a1與a2的最大公約數),故依費馬小定理有h^(p-1)=1 mod p,則對任意整數n,有
      g^(nq) mod p = (h^((p-1)/q))^(nq) mod p
                          = h^(n(p-1)) mod p
                          = (h^(p-1) mod p)^n  mod p
                          = (1^n) mod p = 1     (1)
      對任意整數t、n,可表示為t=nq+z,其中z>0,則有
      g^t mod p = g^(nq+z) mod p
                      = (g^(nq) mod p * (g^z mod p)) mod p
                      = g^z mod p
                      = g^(t mod q) mod p    (2)

  2. 再假設簽名{r,s}和消息m均沒被修改,令H(m)=h,開始推導v
      v = ((g^u1 * y^u2) mod p) mod q
         = (g^(hw mod q) * ((g^x mod p)^(rw mod q) mod p)) mod q
         = ((g^(hw mod q) mod p * ((g^x mod p)^(rw mod q) mod p)) mod p) mod q
         = ((g^(hw mod q) mod p * (g^(x * (rw mod q)) mod p)) mod p) mod q
         = ((g^(hw) mod p * ((g^(rw mod q) mod p)^x mod p)) mod p) mod q
         = ((g^(hw) mod p * ((g^(rw) mod p)^x mod p)) mod p) mod q
         = ((g^(hw) mod p * (g^(rwx) mod p)) mod p) mod q
         = (g^(hw+rwx) mod p) mod q
         = (g^((h+rx)w) mod p) mod q    (3)

      又因w = s^-1 mod q
         故(sw) mod q = 1
           =>(((k^-1(h+xr)) mod q)w) mod q = 1
           =>((k^-1(h+xr))w) mod q = 1
           =>(h+xr)w = k mod q    (4)

      將(4)式代入(3)式中得
      v = (g^(k mod q) mod p) mod q
         = (g^k mod p) mod q
         = r

  3. 最后由(4)式知,若h、r和s任一個有變化(s變化導致w變化),則v ≠ r
posted @ 2016-11-24 19:39 春秋十二月 閱讀(3276) | 評論 (0)編輯 收藏
  2016年11月18日
算法描述    
   隨機選擇兩個大的素數 p、q ,且p ≠ q,計算n = pq、r = (p-1)(q-1),依歐拉定理,r即為與n互質的素數個數;選擇一個小于r的整數e(即加密指數),求得e關于模r的逆元d(即解密指數),則{n,e}為公鑰、{n,d}為私鑰;根據模的逆元性質有ed ≡ 1 (mod r);設m為明文,則加密運算為m^e ≡ c (mod n), c即為密文;則解密過程 c^d ≡ m (mod n)。
   證明會用到費馬小定理,即 若y為素數且x不為y的倍數, 則 x^(y-1) ≡ 1 (mod y)(費馬小定理的證明需先證明歐拉定理,此處略)。符號≡表示同余,^表示,|表示整除,*表示相乘。

算法證明
 第一種證明途徑   
   因 ed ≡ 1 (mod (p-1)(q-1)),令 ed = k(p-1)(q-1) + 1,其中 k 是整數
   則 c^d = (m^e)^d = m^(ed) = m^(k(p-1)(q-1)+1)
   1.若m不是p的倍數,也不是q的倍數
      則 m^(p-1) ≡ 1 (mod p) (費馬小定理)
         => m^(k(p-1)(q-1)) ≡ 1 (mod p)
      m^(q-1) ≡ 1 (mod q) (費馬小定理)
         => m^(k(p-1)(q-1)) ≡ 1 (mod q)
      故 p、q 均能整除 m^(k(p-1)(q-1)) - 1
         => pq | m^(k(p-1)(q-1)) - 1
      即 m^(k(p-1)(q-1)) ≡ 1 (mod pq)   
         => m^(k(p-1)(q-1)+1) ≡ m (mod n)   

   2.若m是p的倍數,但不是q的倍數
      則 m^(q-1) ≡ 1 (mod q) (費馬小定理)
         => m^(k(p-1)(q-1)) ≡ 1 (mod q)
         => m^(k(p-1)(q-1)+1) ≡ m (mod q)
      因 p | m
         => m^(k(p-1)(q-1)+1) ≡ 0 (mod p)
         => m^(k(p-1)(q-1)+1) ≡ m (mod p)
      故 m^(k(p-1)(q-1)+1) ≡ m (mod pq) 
      即 m^(k(p-1)(q-1)+1) ≡ m (mod n)

   3.若m是q的倍數,但不是p的倍數,證明同上

   4.若m同為p和q的倍數時
      則 pq | m
         => m^(k(p-1)(q-1)+1) ≡ 0 (mod pq)
         => m^(k(p-1)(q-1)+1) ≡ m (mod pq)
      即 m^(k(p-1)(q-1)+1) ≡ m (mod n)

 第二種證明途徑
   先證明m^ed ≡ m (mod p)恒成立
   1.若p為m的因子,則p | m^ed - m顯然成立,即m^ed ≡ m (mod p)
   2.若p不為m的因子,令ed = k(p-1)(q-1) + 1,則 m^(ed-1) - 1 = m^(k(p-1)(q-1)) - 1
       m^(p-1) ≡ 1 (mod p) (費馬小定理)
        => m^(k(p-1)) ≡ 1 (mod p)
        => m^(k(p-1)(q-1)) ≡ 1 (mod p)
        => m^(ed-1) ≡ 1 (mod p)
        => m^ed ≡ m (mod p)
   同理可證m^ed ≡ m (mod q)
   故m^ed ≡ m (mod pq),即m^ed ≡ m (mod n)
   又因 c^d = m^e^d = m^(ed)
   故 c^d ≡ m (mod n),證畢
   
總結
 第二種比第一種簡單直觀,以上證明途徑對RSA私鑰簽名與驗簽同樣適合。
posted @ 2016-11-18 17:05 春秋十二月 閱讀(1847) | 評論 (0)編輯 收藏