<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

         摘要: http://autumnrain-zgq.iteye.com/blog/1743279蘋果平臺開發(fā)的應(yīng)用程序,不支持后臺運行程序,所以蘋果有一個推送服務(wù)在軟件的一些信息推送給用戶。 JAVA中,有一個開源軟件,JavaPNS實現(xiàn)了Java平臺中連接蘋果服務(wù)器與推送消息的服務(wù)。但是在使用的過程中,有兩點需要使用者注意一下,希望后續(xù)使用的同志們能避免我走過的覆轍。 1、一是向蘋果...  閱讀全文
    posted @ 2014-07-22 18:44 小馬歌 閱讀(595) | 評論 (0)編輯 收藏
     
    http://blog.csdn.net/totogo2010/article/details/8048652

    iOS的應(yīng)用程序的生命周期,還有程序是運行在前臺還是后臺,應(yīng)用程序各個狀態(tài)的變換,這些對于開發(fā)者來說都是很重要的。 iOS系統(tǒng)的資源是有限的,應(yīng)用程序在前臺和在后臺的狀態(tài)是不一樣的。在后臺時,程序會受到系統(tǒng)的很多限制,這樣可以提高電池的使用和用戶體驗。

    //開發(fā)app,我們要遵循apple公司的一些指導(dǎo)原則,原則如下:

    1、應(yīng)用程序的狀態(tài)

    狀態(tài)如下:

    Not running  未運行  程序沒啟動

    Inactive          未激活        程序在前臺運行,不過沒有接收到事件。在沒有事件處理情況下程序通常停留在這個狀態(tài)

    Active             激活           程序在前臺運行而且接收到了事件。這也是前臺的一個正常的模式

    Backgroud     后臺           程序在后臺而且能執(zhí)行代碼,大多數(shù)程序進入這個狀態(tài)后會在在這個狀態(tài)上停留一會。時間到之后會進入掛起狀態(tài)(Suspended)。有的程序經(jīng)過特殊的請求后可以長期處于Backgroud狀態(tài)

    Suspended    掛起           程序在后臺不能執(zhí)行代碼。系統(tǒng)會自動把程序變成這個狀態(tài)而且不會發(fā)出通知。當掛起時,程序還是停留在內(nèi)存中的,當系統(tǒng)內(nèi)存低時,系統(tǒng)就把掛起的程序清除掉,為前臺程序提供更多的內(nèi)存。

    下圖是程序狀態(tài)變化圖:


    各個程序運行狀態(tài)時代理的回調(diào):

    - (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions
          告訴代理進程啟動但還沒進入狀態(tài)保存
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
         告訴代理啟動基本完成程序準備開始運行
    - (void)applicationWillResignActive:(UIApplication *)application
        當應(yīng)用程序?qū)⒁敕腔顒訝顟B(tài)執(zhí)行,在此期間,應(yīng)用程序不接收消息或事件,比如來電話了
    - (void)applicationDidBecomeActive:(UIApplication *)application 
         當應(yīng)用程序入活動狀態(tài)執(zhí)行,這個剛好跟上面那個方法相反
    - (void)applicationDidEnterBackground:(UIApplication *)application
        當程序被推送到后臺的時候調(diào)用。所以要設(shè)置后臺繼續(xù)運行,則在這個函數(shù)里面設(shè)置即可
    - (void)applicationWillEnterForeground:(UIApplication *)application
    當程序從后臺將要重新回到前臺時候調(diào)用,這個剛好跟上面的那個方法相反。
    - (void)applicationWillTerminate:(UIApplication *)application
    當程序?qū)⒁顺鍪潜徽{(diào)用,通常是用來保存數(shù)據(jù)和一些退出前的清理工作。這個需要要設(shè)置UIApplicationExitsOnSuspend的鍵值。
    - (void)applicationDidFinishLaunching:(UIApplication*)application
    當程序載入后執(zhí)行

    在上面8個方法對應(yīng)的方法中鍵入NSLog打印。

    現(xiàn)在啟動程序看看執(zhí)行的順序:

    啟動程序
    lifeCycle[40428:11303] willFinishLaunchingWithOptions
    lifeCycle[40428:11303] didFinishLaunchingWithOptions
    lifeCycle[40428:11303] applicationDidBecomeActive

    按下home鍵

    lifeCycle[40428:11303] applicationWillResignActive
    lifeCycle[40428:11303] applicationDidEnterBackground

    雙擊home鍵,再打開程序

    lifeCycle[40428:11303] applicationWillEnterForeground
    lifeCycle[40428:11303] applicationDidBecomeActive

    2、應(yīng)用程序的生命周期

    2.1、加載應(yīng)用程序進入前臺


    2.2、加載應(yīng)用程序進入后臺



    2.3、關(guān)于main函數(shù)

    main函數(shù)是程序啟動的入口,在iOS app中,main函數(shù)的功能被最小化,它的主要工作都交給了UIKit framework

    1. #import <UIKit/UIKit.h>  
    2.    
    3. int main(int argc, char *argv[])  
    4. {  
    5.     @autoreleasepool {  
    6.         return UIApplicationMain(argc, argv, nil, NSStringFromClass([MyAppDelegate class]));  
    7.     }  
    8. }  

    UIApplicationMain函數(shù)有四個參數(shù),你不需要改變這些參數(shù)值,不過我們也需要理解這些參數(shù)和程序是如何開始的

    argc 和argv參數(shù)包含了系統(tǒng)帶過來的啟動時間。  第三個參數(shù)確定了主要應(yīng)用程序類的名稱,這個參數(shù)指定為nil,這樣UIKit就會使用默認的程序類UIApplication。第四個參數(shù)是程序自定義的代理類名,這個類負責系統(tǒng)和代碼之間的交互。它一般在Xcode新建項目時會自動生成。

    另外 UIApplicationMain函數(shù)加載了程序主界面的文件。雖然這個函數(shù)加載了界面文件,但是沒有放到應(yīng)用程序的windows上,你需要在Delegate的 application:willFinishLaunchingWithOptions方法中加載它。

    一個應(yīng)用程序可以有一個主的storyboard文件或者有一個主的nib文件,但不能同時有兩個存在。

    如果程序在啟動時沒有自動加載主要的故事版或nib文件,你可以在application:willFinishLaunchingWithOptions方法里準備windows的展示。

    3、響應(yīng)中斷

    3.1 當一個基于警告式的中斷發(fā)生時,比如有電話打進來了,這是程序會臨時進入inactive狀態(tài),這用戶可以選擇如何處理這個中斷,流程如下圖:


    在iOS5,通知不會把程序變成為激活狀態(tài),通知會顯示在狀態(tài)欄上,如果你;拉下狀態(tài)欄,程序會變成inactive,把狀態(tài)欄放回去,程序變回active。

    按鎖屏鍵也是另外一種程序的中斷,當你按下鎖屏鍵,系統(tǒng)屏蔽了所有觸摸事件,把app放到了后臺,這時app狀態(tài)是 inactive,并進入后臺。

    3.2 當有這些中斷時,我們的app該怎么辦呢?我們應(yīng)該在applicationWillResignActive:方法中:

    • 停止timer 和其他周期性的任務(wù)
    • 停止任何正在運行的請求
    • 暫停視頻的播放
    • 如果是游戲那就暫停它
    • 減少OpenGL ES的幀率
    • 掛起任何分發(fā)的隊列和不重要的操作隊列(你可以繼續(xù)處理網(wǎng)絡(luò)請求或其他時間敏感的后臺任務(wù))。
    當程序回到active狀態(tài) ,   applicationDidBecomeActive:   方法應(yīng)該上面提到的任務(wù)重新開始,比如重新開始timer, 繼續(xù)分發(fā)隊列,提高OpenGL ES的幀率。不過游戲要回到暫停狀態(tài),不能自動開始。

    4、轉(zhuǎn)到后臺運行

    4.1 如圖所示:

    PS:只有在IOS4以上系統(tǒng)或者支持多任務(wù)的設(shè)備才能后臺運行。不然會直接結(jié)束狀態(tài)。

    4.2 當應(yīng)用程序進入后臺時,我們應(yīng)該做寫什么呢?

    • 保存用戶數(shù)據(jù)或狀態(tài)信息,所有沒寫到磁盤的文件或信息,在進入后臺時,最后都寫到磁盤去,因為程序可能在后臺被殺死,
    • 釋放盡可能釋放的內(nèi)存
    applicationDidEnterBackgound: 方法有大概5秒的時間讓你完成這些任務(wù)。如果超過時間還有未完成的任務(wù),你的程序就會被終止而且從內(nèi)存中清除。如果還需要長時間的運行任務(wù),可以調(diào)用  beginBackgroundTaskWithExpirationHandler       方法去請求后臺運行時間和啟動線程來運行長時間運行的任務(wù)。
    4.3 應(yīng)用程序在后臺時的內(nèi)存使用
    在后臺時,每個應(yīng)用程序都應(yīng)該釋放最大的內(nèi)存。系統(tǒng)努力的保持更多的應(yīng)用程序在后臺同時 運行。不過當內(nèi)存不足時,會終止一些掛起的程序來回收內(nèi)存,那些內(nèi)存最大的程序首先被終止。
    事實上,應(yīng)用程序應(yīng)該的對象如果不再使用了,那就應(yīng)該盡快的去掉強引用,這樣編譯器可以回收這些內(nèi)存。如果你想緩存一些對象提升程序的性能,你可以在進入后臺時,把這些對象去掉強引用。
    下面這樣的對象應(yīng)該盡快的去掉強引用:
    • 圖片對象
    • 你可以重新加載的 大的視頻或數(shù)據(jù)文件
    • 任何沒用而且可以輕易創(chuàng)建的對象
    在后臺時,為了減少程序占用的內(nèi)存,系統(tǒng)會自動在回收一些系統(tǒng)幫助你開辟的內(nèi)存。比如:
    系統(tǒng)回收Core Animation的后備存儲。
    去掉任何系統(tǒng)引用的緩存圖片
    去掉系統(tǒng)管理數(shù)據(jù)緩存強引用

    5 、返回前臺運行

    流程如圖所示:
    當app處于掛起狀態(tài)時,它是不能執(zhí)行任何代碼的。因此它不能處理在掛起期間發(fā)過來的通知,比如方向改變,時間改變,設(shè)置的改變還有其他影響程序展現(xiàn)的或狀態(tài)的通知。在程序返回后臺或前臺是,程序都要正確的處理這些通知。

    6、程序的終止

    程序只要符合以下情況之一,只要進入后臺或掛起狀態(tài)就會終止:
    iOS4.0以前的系統(tǒng)
    app是基于iOS4.0之前系統(tǒng)開發(fā)的。
    設(shè)備不支持多任務(wù)
    在Info.plist文件中,程序包含了 UIApplicationExitsOnSuspend  鍵。
    app如果終止了  ,系統(tǒng)會調(diào)用app的代理的方法 applicationWillTerminate:   這樣可以讓你可以做一些清理工作。你可以保存一些數(shù)據(jù)或app的狀態(tài)。這個方法也有5秒鐘的限制。超時后方法會返回程序從內(nèi)存中清除。
    注意:用戶可以手工關(guān)閉應(yīng)用程序。

    7、 The Main Run Loop  主運行循環(huán)

    Main Run Loop負責處理用戶相關(guān)的事件。UIApplication對象在程序啟動時啟動main run Loop,它處理事件和更新視圖的界面。看Main Run Loop就知道,它是運行在程序的主線程上的。這樣保證了接收到用戶相關(guān)操作的事件是按順序處理的。
    Main Run Loop  處理事件的架構(gòu)圖:
    用戶操作設(shè)備,相關(guān)的操作事件被系統(tǒng)生成并通過UIKit的指定端口分發(fā)。事件在內(nèi)部排成隊列,一個個的分發(fā)到Main run loop 去做處理。UIApplication對象是第一個接收到時間的對象,它決定事件如何被處理。觸摸事件分發(fā)到主窗口,窗口再分發(fā)到對應(yīng)出發(fā)觸摸事件的View。其他的事件通過其他途徑分發(fā)給其他對象變量做處理。
    大部分的事件可以在你的應(yīng)用里分發(fā),類似于觸摸事件,遠程操控事件(線控耳機等)都是由app的 responder objects 對象處理的。Responder objects 在你的app里到處都是,比如:UIApplication 對象。view對象,view controller 對象,都是resopnder objects。大部分事件的目標都指定了resopnder object,不過事件也可以傳遞給其他對象。比如,如果view對象不處理事件,可以傳給父類view或者view controller。
    參考:https://developer.apple.com/library/ios/#documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/ManagingYourApplicationsFlow/ManagingYourApplicationsFlow.html#//apple_ref/doc/uid/TP40007072-CH4-SW20

    容芳志 (http://blog.csdn.net/totogo2010)

    本文遵循“署名-非商業(yè)用途-保持一致”創(chuàng)作公用協(xié)議


    posted @ 2014-07-22 18:01 小馬歌 閱讀(222) | 評論 (0)編輯 收藏
     
    1、概述

    Aho-Corasick自動機算法(簡稱AC自動機)1975年產(chǎn)生于貝爾實驗室。該算法應(yīng)用有限自動機巧妙地將字符比較轉(zhuǎn)化為了狀態(tài)轉(zhuǎn)移。此算法有兩個特點,一個是掃描文本時完全不需要回溯,另一個是時間復(fù)雜度為O(n),時間復(fù)雜度與關(guān)鍵字的數(shù)目和長度無關(guān)。

    好了,我們先看下最原始的多模式匹配算法:

    主串T,n=strlen(T)。

    模式串Pi mi = strlen(pi)

     

    1. for(i=0;i<n-MIN(m);++i)  
    2.     for(j=0;j<k;++j)  
    3.         if(n-mk<=n-i &&memcmp(T[i],Pk,mk)==0)  
    4.            printf(“match/n”);  
     

     

     

     

    是O(mn)的時間復(fù)雜度。

    上面的算法很笨吧,下面看看聰明的AC算法是個啥意思。

    2、 AC算法思想

    AC算法思想:用多模式串建立一個確定性的樹形有限狀態(tài)機,以主串作為該有限狀態(tài)機的輸入,使狀態(tài)機進行狀態(tài)的轉(zhuǎn)換,當?shù)竭_某些特定的狀態(tài)時,說明發(fā)生模式匹配。

    下圖是多模式he/ she/ his /hers構(gòu)成的一個確定性有限狀態(tài)機,做幾點說明:

    wps_clip_image-531

    1、 該狀態(tài)機優(yōu)先按照實線標注的狀態(tài)轉(zhuǎn)換路徑進行轉(zhuǎn)換,當所有實線標注的狀態(tài)轉(zhuǎn)換路徑條件不能滿足時,按照虛線的狀態(tài)轉(zhuǎn)換路徑進行狀態(tài)轉(zhuǎn)換。如:狀態(tài)0時,當輸入h,則轉(zhuǎn)換到狀態(tài)1;輸入s,則轉(zhuǎn)換到狀態(tài)3;否則轉(zhuǎn)換到狀態(tài)0。

    2、 匹配過程如下:從狀態(tài)0開始進行狀態(tài)轉(zhuǎn)換,主串作為輸入。如主串為:ushers,狀態(tài)轉(zhuǎn)換的過程是這樣的:

    wps_clip_image-720

    3、  當狀態(tài)轉(zhuǎn)移到2,5,7,9等紅色狀態(tài)點時,說明發(fā)生了模式匹配。

    如主串為:ushers,則在狀態(tài)5、2、9等狀態(tài)時發(fā)生模式匹配,匹配的模 式串有she、he、hers。

     

    定義:

    在預(yù)處理階段,AC自動機算法建立了三個函數(shù),轉(zhuǎn)向函數(shù)goto,失效函數(shù)failure和輸出函數(shù)output,由此構(gòu)造了一個樹型有限自動機。

     

    轉(zhuǎn)向函數(shù),指的是一種狀態(tài)之間的轉(zhuǎn)向關(guān)系。g(pre, x)=next:狀態(tài)pre在輸入一個字符x后轉(zhuǎn)換為狀態(tài)next(上圖中的實線部分)。如果在模式串中不存在這樣的轉(zhuǎn)換,則next=failstate。

     

    失效函數(shù),指的也是狀態(tài)和狀態(tài)之間一種轉(zhuǎn)向關(guān)系。f(per)=next:是在比較失配的情況下使用的轉(zhuǎn)換關(guān)系。在構(gòu)造轉(zhuǎn)向函數(shù)時,把不存在的轉(zhuǎn)換用failstate表示,但是failstate不是一個具體的狀態(tài),狀態(tài)機轉(zhuǎn)換轉(zhuǎn)換到failstate狀態(tài)的時候就不知道該往哪轉(zhuǎn)了。所以就要在狀態(tài)機中找到一個有意義的狀態(tài)代替failstate,當出現(xiàn)failstate狀態(tài)時,自動切換到那個狀態(tài)。

    這個狀態(tài)節(jié)點應(yīng)該具有這樣的特征:從這個狀態(tài)節(jié)點向上直到樹根節(jié)點(狀態(tài)0)所經(jīng)歷的輸入字符,和從產(chǎn)生failstate狀態(tài)的那個狀態(tài)節(jié)點向上所經(jīng)歷的輸入字符串完全相同。而且這個狀態(tài)節(jié)點,是所有具備這些條件的節(jié)點中深度最大的那個節(jié)點。如果不存在滿足條件的狀態(tài)節(jié)點,則失效函數(shù)為0。

    累死了。舉例子說吧,對狀態(tài)9輸入任何一個字符都會產(chǎn)生failstate狀態(tài),需要失效函數(shù)。狀態(tài)3向上到狀態(tài)0經(jīng)過的輸入字符串為s;而由狀態(tài)9向上的輸入字符串為sreh。字符串s相同,并且狀態(tài)3是滿足此條件的唯一節(jié)點,則

    f(9)=3。

    說來說去,失效函數(shù)就是要干這么件事兒:

    wps_clip_image-1497

    意思就是說,在比較模式串1發(fā)生失配時,找一個模式串2,使得P2[0...j-1] = P1[i-j+1...i]。然后繼續(xù)比較模式串2。看上面那個圖,想起點兒什么東西沒有?對了,是KMP算法。有人說AC算法就是KMP算法在多模式匹配情況下的擴展。


    輸出函數(shù)
    ,指的是狀態(tài)和模式串之間的一種關(guān)系。output(i)={P},表示當狀
    態(tài)機到達狀態(tài)i時,模式串集合{P}中的所有模式串可能已經(jīng)完成匹配。

    例:

    模式串為:he/ she/ hers/ his 時,如上圖所示:

    轉(zhuǎn)向函數(shù):

    wps_clip_image-1758

    失效函數(shù):

    wps_clip_image-1780

    輸出函數(shù):

    wps_clip_image-1801

    3、 AC代碼分析

    下面的代碼參考snort入侵檢測系統(tǒng)開源軟件的acsmx.c文件。

    3.1數(shù)據(jù)結(jié)構(gòu)分析

    所有狀態(tài)都被存儲在一個ACSM_STATETABLE類型的數(shù)組中。

    typedef struct  {   

        int      NextState[ ALPHABET_SIZE ]; 

        int      FailState;  

        ACSM_PATTERN *MatchList;

    }ACSM_STATETABLE;

    NextState對應(yīng)轉(zhuǎn)向函數(shù);FailState對應(yīng)失效函數(shù);MatchList對應(yīng)輸出函數(shù)。

     

    3.2代碼分析

    代碼流程如下圖:

    wps_clip_image-2124

     

    https://github.com/robert-bor/aho-corasick
    posted @ 2014-07-16 09:24 小馬歌 閱讀(254) | 評論 (0)編輯 收藏
     
         摘要: 一 原理區(qū)別     一般在瀏覽器中輸入網(wǎng)址訪問資源都是通過GET方式;在FORM提交中,可以通過Method指定提交方式為GET或者POST,默認為GET提交 Http定義了與服務(wù)器交互的不同方法,最基本的方法有4種,分別是GET,POST,PUT,DELETE URL全稱是資源描述符,我們可以這樣認為:一個URL地址,它用于描述一個網(wǎng)...  閱讀全文
    posted @ 2014-07-15 17:22 小馬歌 閱讀(398) | 評論 (0)編輯 收藏
     

    先描述一下問題,多個服務(wù)器實現(xiàn)的負載均衡,每個服務(wù)器存儲在自己的硬盤里。但是現(xiàn)在需要對日志做統(tǒng)一的分析,在多個服務(wù)器上統(tǒng)計就麻煩了。思路是把日志統(tǒng)一到一臺日志服務(wù)器上,再統(tǒng)一做統(tǒng)計分析。怎么統(tǒng)一到一臺服務(wù)器上,說實話沒有特別好的思路,最后嘗試了log4j的SocketAppender。查了不少網(wǎng)絡(luò)資源,都說的有些不明了,還是得親自嘗試之后才見分曉。

    1、客戶端的配置

    客戶端的配置比較簡單,只需要告訴log4j需要監(jiān)聽哪個遠程服務(wù)器的哪個端口即可。直接在log4j.properties里直接配置就好。

    1. <span style="font-size:12px;">log4j.appender.logs=org.apache.log4j.DailyRollingFileAppender  
    2. log4j.appender.logs.File = /data/logs/request/logs.log  
    3. log4j.appender.logs.layout = org.apache.log4j.PatternLayout  
    4. log4j.appender.logs.layout.ConversionPattern=%d [%t] - %m%n  
    5. log4j.appender.logs.DatePattern='.'yyyy-MM-dd'.log'  
    6.   
    7. log4j.appender.socket=org.apache.log4j.net.SocketAppender  
    8. log4j.appender.socket.RemoteHost=172.16.2.152  
    9. log4j.appender.socket.Port=4560  
    10. log4j.appender.socket.LocationInfo=true  
    11. #下面這兩句感覺沒用  
    12. log4j.appender.socket.layout=org.apache.log4j.PatternLayout  
    13. log4j.appender.socket.layout.ConversionPattern=[%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%t%m%n  
    14.   
    15. #將日志寫入本地和遠程日志服務(wù)器  
    16. log4j.logger.com.test.core.filter =DEBUG,socket,logs</span>  
     

    2、日志服務(wù)器的配置

    日志服務(wù)器需要單獨啟動一個java進程,接收客戶端給自己發(fā)送的socket請求。Log4j提供了org.apache.log4j.net.SocketServer類,直接運行其main函數(shù)就行了(當然也可以自己寫啦)。

    java -cp /log4jsocket/serverConfig/log4j-1.2.16.jarorg.apache.log4j.net.SocketServer 4560 /log4jsocket/log4jserver.properties /log4jsocket/clientConfig

    /log4jsocket/serverConfig/log4j-1.2.16.jar是log4j jar包存放的位置,org.apache.log4j.net.SocketServer需要三個參數(shù):

    1)4560 是監(jiān)聽的端口號

    2)/log4jsocket/log4jserver.properties 是記錄日志服務(wù)器的日志的配置文件

    3)/log4jsocket/clientConfig 是客戶端配置文件所在的目錄(注意是目錄)。

    著重說一下org.apache.log4j.net.SocketServer的第三個參數(shù),這個文件夾下配置的是各個客戶端的日志的配置。配置文件以.lcf結(jié)尾,文件名可以用客戶端的IP命名,log4j會自己找發(fā)送請求的客戶端IP對應(yīng)的那個配置文件,如172.16.2.46服務(wù)器發(fā)送的socket請求會尋找172.16.2.46.lcf配置文件,并根據(jù)配置將日志寫入對應(yīng)的文件。

    1. <span style="font-size:12px;">#注意logger后面的值要與client的值相同  
    2. log4j.logger.com.test.core.filter=DEBUG,localLogs  
    3.    
    4. log4j.appender.localLogs=org.apache.log4j.DailyRollingFileAppender  
    5. log4j.appender.localLogs.File=/data/logs/request/172.16.2.46/logs.log  
    6. log4j.appender.localLogs.layout=org.apache.log4j.PatternLayout  
    7. log4j.appender.localLogs.layout.ConversionPattern=%d [%t] - %m%n  
    8. log4j.appender.localLogs.DatePattern='.'yyyy-MM-dd'.log'  
    9. </span>  


    這樣做的好處是可以根據(jù)不同客戶端,將日志寫入不同的文件夾下的。

    其實,配置過程就這么簡單,但是當你這么做之后,你會發(fā)現(xiàn)運行org.apache.log4j.net.SocketServer后,客戶端向日志服務(wù)器發(fā)送請求時,會報找不到.lcf文件的錯誤,得不到想要的結(jié)果。原因出在org.apache.log4j.net.SocketServer代碼中的一個小bug。 

    1. <span style="font-size:12px;">LoggerRepository configureHierarchy(InetAddress inetAddress)  
    2.   {  
    3.     cat.info("Locating configuration file for " + inetAddress);  
    4.   
    5.     String s = inetAddress.toString();  
    6.     int i = s.indexOf("/");  
    7.     if (i == -1) {  
    8.       cat.warn("Could not parse the inetAddress [" + inetAddress + "]. Using default hierarchy.");  
    9.   
    10.       return genericHierarchy();  
    11.     }  
    12.     String key = s.substring(0,i);  
    13.   
    14.     File configFile = new File(this.dir, key + CONFIG_FILE_EXT);  
    15.     if (configFile.exists()) {  
    16.       Hierarchy h = new Hierarchy(new RootLogger(Level.DEBUG));  
    17.       this.hierarchyMap.put(inetAddress, h);  
    18.   
    19.       new PropertyConfigurator().doConfigure(configFile.getAbsolutePath(), h);  
    20.   
    21.       return h;  
    22.     }  
    23.     cat.warn("Could not find config file [" + configFile + "].");  
    24.     return genericHierarchy();  
    25.   }</span>  

    String key = s.substring(0, i);換成String key = s.substring(i+1);就好了。這段代碼是解析IP地址,然后尋找對應(yīng)IP命名的.lcf配置文件;如果找不到,則解析默認的generic.lcf。由于截取的錯誤,導(dǎo)致找不到172.16.2.46.lcf,文件夾下又沒有g(shù)eneric.lcf,所以會拋異常。

    org.apache.log4j.net.SocketServer代碼中的另外一個bug是,只能接收來自一臺客戶端的日志請求,一旦客戶端停止運行,SocketServer也將關(guān)閉。查看代碼:

    1. public static void main(String[] argv)  
    2.   {     
    3.       if (argv.length == 3)  
    4.       init(argv[0], argv[1], argv[2]);  
    5.     else  
    6.       usage("Wrong number of arguments.");  
    7.     try  
    8.     {  
    9.         cat.info("Listening on port " + port);  
    10.         ServerSocket serverSocket = new ServerSocket(port);  
    11.         cat.info("Waiting to accept a new client.");  
    12.     Socket socket = serverSocket.accept();  
    13.     InetAddress inetAddress = socket.getInetAddress();  
    14.     cat.info("Connected to client at " + inetAddress);  
    15.       
    16.     LoggerRepository h = (LoggerRepository)server.hierarchyMap.get(inetAddress);  
    17.     if (h == null) {  
    18.             h = server.configureHierarchy(inetAddress);  
    19.     }  
    20.       
    21.     cat.info("Starting new socket node.");  
    22.     new Thread(new SocketNode(socket, h)).start();  
    23.       }  
    24.     catch (Exception e)  
    25.     {  
    26.       e.printStackTrace();  
    27.     }  
    28.   }  

    問題出在只建立了一個socket連接就不在accept了,加上while循環(huán)問題就解決了。

    1. ServerSocket serverSocket = new ServerSocket(port);  
    2. while(true){  
    3.  cat.info("Waiting to accept a new client.");  
    4.  Socket socket = serverSocket.accept();  
    5.  InetAddress inetAddress = socket.getInetAddress();  
    6.  cat.info("Connected to client at " + inetAddress);  
    7.   
    8.  LoggerRepository h = (LoggerRepository)server.hierarchyMap.get(inetAddress);  
    9.  if (h == null) {  
    10.    h = server.configureHierarchy(inetAddress);  
    11.  }  
    12.   
    13.  cat.info("Starting new socket node.");  
    14.  new Thread(new SocketNode(socket, h)).start();  
    15. }  



     

     

    好了。Log4j的配置到此結(jié)束。

    最后一個問題,日志服務(wù)器是linux,需要有一個統(tǒng)一的start、shutdown命令來啟動和關(guān)閉org.apache.log4j.net.SocketServer。那就需要些shell命令了,下面這段代碼參考了http://www.cnblogs.com/baibaluo/archive/2011/08/31/2160934.html

    catalina.sh

    1. <span style="font-size:12px;">#!/bin/bash  
    2. #端口  
    3. LISTEN_PORT=4560  
    4. #服務(wù)端log4j配置文件  
    5. SERVER_CONFIG=/log4jsocket/server.properties  
    6. #客戶端的配置  
    7. CLIENT_CONFIG_DIR=/log4jsocket/clientConfig  
    8.   
    9. #Java程序所在的目錄(classes的上一級目錄)  
    10. APP_HOME=/opt/log4jsocket/serverConfig   
    11. #需要啟動的Java主程序(main方法類)  
    12. APP_MAINCLASS=org.apache.log4j.net.SocketServer  
    13.    
    14. #拼湊完整的classpath參數(shù),包括指定lib目錄下所有的jar  
    15. CLASSPATH=$APP_HOME  
    16. for i in "$APP_HOME"/*.jar; do     
    17.     CLASSPATH="$CLASSPATH":"$i"  
    18. done  
    19.   
    20. #JDK所在路徑  
    21. JAVA_HOME="/opt/jdk1.6.0_30"   
    22. #執(zhí)行程序啟動所使用的系統(tǒng)用戶,考慮到安全,推薦不使用root帳號  
    23. RUNNING_USER=root  
    24.    
    25. #java虛擬機啟動參數(shù)  
    26. JAVA_OPTS="-ms512m -mx512m -Xmn256m -Djava.awt.headless=true -XX:MaxPermSize=128m"   
    27.   
    28. #初始化psid變量(全局)  
    29. psid=0  
    30.    
    31. checkpid() {  
    32.    javaps=`$JAVA_HOME/bin/jps -l | grep $APP_MAINCLASS`  
    33.    
    34.    if [ -n "$javaps" ]; then  
    35.       psid=`echo $javaps | awk '{print $1}'`  
    36.    else  
    37.       psid=0  
    38.    fi  
    39. }  
    40.   
    41. start() {  
    42.    checkpid  
    43.    
    44.    if [ $psid -ne 0 ]; then  
    45.       echo "================================"  
    46.       echo "warn: $APP_MAINCLASS already started! (pid=$psid)"  
    47.       echo "================================"  
    48.    else  
    49.       echo -n "Starting $APP_MAINCLASS ..."  
    50.       JAVA_CMD="nohup $JAVA_HOME/bin/java -classpath $CLASSPATH $APP_MAINCLASS $LISTEN_PORT $SERVER_CONFIG $CLIENT_CONFIG_DIR >/dev/null 2>&1 &"  
    51.       su - $RUNNING_USER -c "$JAVA_CMD"  
    52.       checkpid  
    53.       if [ $psid -ne 0 ]; then  
    54.          echo "(pid=$psid) [OK]"  
    55.       else  
    56.          echo "[Failed]"  
    57.       fi  
    58.    fi  
    59. }  
    60.   
    61. stop() {  
    62.    checkpid  
    63.    
    64.    if [ $psid -ne 0 ]; then  
    65.       echo -n "Stopping $APP_MAINCLASS ...(pid=$psid) "  
    66.       su - $RUNNING_USER -c "kill -9 $psid"  
    67.       if [ $? -eq 0 ]; then  
    68.          echo "[OK]"  
    69.       else  
    70.          echo "[Failed]"  
    71.       fi  
    72.    
    73.       checkpid  
    74.       if [ $psid -ne 0 ]; then  
    75.          stop  
    76.       fi  
    77.    else  
    78.       echo "================================"  
    79.       echo "warn: $APP_MAINCLASS is not running"  
    80.       echo "================================"  
    81.    fi  
    82. }  
    83.   
    84. status() {  
    85.    checkpid  
    86.    
    87.    if [ $psid -ne 0 ];  then  
    88.       echo "$APP_MAINCLASS is running! (pid=$psid)"  
    89.    else  
    90.       echo "$APP_MAINCLASS is not running"  
    91.    fi  
    92. }  
    93. info() {  
    94.    echo "System Information:"  
    95.    echo "****************************"  
    96.    echo `head -n 1 /etc/issue`  
    97.    echo `uname -a`  
    98.    echo  
    99.    echo "JAVA_HOME=$JAVA_HOME"  
    100.    echo `$JAVA_HOME/bin/java -version`  
    101.    echo  
    102.    echo "APP_HOME=$APP_HOME"  
    103.    echo "APP_MAINCLASS=$APP_MAINCLASS"  
    104.    echo "****************************"  
    105. }  
    106. case "$1" in  
    107.   
    108.    'start')  
    109.       start  
    110.       ;;  
    111.    'stop')  
    112.      stop  
    113.      ;;  
    114.    'restart')  
    115.      stop  
    116.      start  
    117.      ;;  
    118.    'status')  
    119.      status  
    120.      ;;  
    121.    'info')  
    122.      info  
    123.      ;;  
    124.   *)  
    125.      echo "Usage: $0 {start|stop|restart|status|info}"   
    126.      exit 0   
    127. esac  
    128. </span>  
    startup.sh

    1. <span style="font-size:12px;">#!/bin/sh  
    2. EXECUTABLE=/log4jsocket/catalina.sh  
    3. exec "$EXECUTABLE" start "$@"</span>  
    shutdown.sh

    1. <span style="font-size:12px;">EXECUTABLE=/log4jsocket/catalina.sh  
    2. exec "$EXECUTABLE" stop "$@"</span>  
    posted @ 2014-07-09 15:31 小馬歌 閱讀(2820) | 評論 (0)編輯 收藏
     

    遇到如題的這么一個場景:需要在MySQL的一張innodb引擎的表(tableA)上添加一個唯一索引(idx_col1_u)。但是表中已經(jīng)有大量重復(fù)數(shù)據(jù),對于每個key(col1),有的重復(fù)2行,有的重復(fù)N行。

    此時,做數(shù)據(jù)的手工清理,或者SQL處理無疑是非常耗時的。

     

    1. Alter ignore table come to help

    印象中MySQL有一個獨有的 alter ignore add unique index的語法。

    語法如下:

    ALTER [ONLINE | OFFLINE] [IGNORE] TABLE tbl_name

     

    行為類似于insert ignore,即遇到?jīng)_突的unique數(shù)據(jù)則直接拋棄而不報錯。對于加唯一索引的情況來說就是建一張空表,然后加上唯一索引,將老數(shù)據(jù)用insert ignore語法插入到新表中,遇到?jīng)_突則拋棄數(shù)據(jù)。

    文檔中對于alter ignore的注釋:詳見:http://dev.mysql.com/doc/refman/5.1/en/alter-table.html

    IGNORE is a MySQL extension to standard SQL. It controls how ALTER TABLE works if there are duplicates on unique keys in the new table or if warnings occur when strict mode is enabled. If IGNORE is not specified, the copy is aborted and rolled back if duplicate-key errors occur. If IGNORE is specified, only the first row is used of rows with duplicates on a unique key. The other conflicting rows are deleted. Incorrect values are truncated to the closest matching acceptable value.

     

    2.  #1062 - Duplicate entry 

     然而在執(zhí)行了 alter ignore table tableA add unique index idx_col1_u (col1) 后,還是報了以下錯誤:

     #1062 - Duplicate entry '111' for key 'col1'.

    不是會自動丟棄重復(fù)數(shù)據(jù)么?世界觀被顛覆了。查了下資料原來是alter ignore的語法不支持innodb。

    得知alter ignore的實現(xiàn)完全取決于存儲引擎的內(nèi)部實現(xiàn),而不是server端強制的,具體描述如下:

    For ALTER TABLE with the IGNORE keyword, IGNORE is now part of the information provided to the storage engine. It is up to the storage engine whether to use this when choosing between the in-place or copy algorithm for altering the table. For InnoDB index operations, IGNORE  is not used if the index is unique, so the copy algorithm is used

     詳見:http://bugs.mysql.com/bug.php?id=40344

     

    3. 解決方案

    當然解決這個問題的tricky的方法還是有的,也比較直白粗暴。具體如下:

    ALTER TABLE tableA ENGINE MyISAM;
    ALTER IGNORE TABLE tableA ADD UNIQUE INDEX idx_col1_u (col1)
    ALTER TABLE table ENGINE InnoDB;

     

    updated in 2013-09-26:

    @jyzhou 分享提到,可以不用改成MyISAM,而直接使用set old_alter_table = 1; 的方法。具體做法如下:

    set old_alter_table = 1;

    ALTER IGNORE TABLE tableA ADD UNIQUE INDEX idx_col1_u (col1) 

    具體原理:http://dev.mysql.com/doc/refman/5.1/en/server-system-variables.html#sysvar_old_alter_table

    posted @ 2014-07-07 13:52 小馬歌 閱讀(269) | 評論 (0)編輯 收藏
     
    url:http://www.myexception.cn/operating-system/1525825.html
    使用IOS企業(yè)版證書發(fā)布應(yīng)用

            蘋果的企業(yè)開發(fā)證書,可以不經(jīng)app store,直接發(fā)布到自己的網(wǎng)站上。其他人可以直接下載安裝。但前提要用蘋果自帶的瀏覽器(safari)才能下載,其他瀏覽器不能識別該協(xié)議。

            一、制作證書

           打開Keychain Access工具,把Keychain的配置改為如下圖:


    并從菜單中選擇Keycahin Access->Certificate Assistant->Request a Certificate From a Certificate Authority...如下圖所示:


     填寫必要的信息,生成證書保存在桌面或其他地方,等會要用到:




     
     二、生成并安裝證書

            用企業(yè)版的apple id登陸蘋果開發(fā)者中心: https://developer.apple.com, 登陸后選擇對應(yīng)的選項,上傳之前生成的證書文件,如下圖:


     

     生成證書文件后,下載下來,雙擊打開即安裝。

    三、增加APP ID

    四、生成Profiles文件

    在開發(fā)中心點擊Provisioning Profiles中的Distribution, 點擊“+”,增加Profiles。APP ID選擇剛才增加的。如圖
     

    添加好之后,就可以下載下來,把它拖到Xcode中。或是拖到Organizer中。如圖:



     

    五、發(fā)布應(yīng)用

    在XCode的Targets中選擇簽名:



     在XCode的菜單Product->Archive中選擇打包。打包時要把iPad或是iphone接到電腦上,并選擇目標是iPad或是iphone才能成功。



     

     



    Required的信息填寫即可,save,則會同時生成ipa和plist 文件,如下

     

    apple文檔地址:http://developer.apple.com/library/ios/#featuredarticles/FA_Wireless_Enterprise_App_Distribution/Introduction/Introduction.html


    以無線方式安裝應(yīng)用程序

    iOS 支持以無線方式安裝企業(yè)級應(yīng)用程序,這可讓您在不使用 iTunes 的情況下將內(nèi)部軟件分發(fā)給用戶。

    要求

    • 已鑒定的用戶可訪問的安全 Web 服務(wù)器

    • .ipa 格式的 iOS 應(yīng)用程序,經(jīng)構(gòu)建用于發(fā)布/生產(chǎn)(使用了企業(yè)級預(yù)置描述文件)

    • 本文稿中稍后描述的 XML 清單文件

    • 可讓設(shè)備訪問 Apple iTunes 服務(wù)器的網(wǎng)絡(luò)配置

    安裝應(yīng)用程序很簡單。用戶可以將清單文件從您的網(wǎng)站上下載到他們的 iOS 設(shè)備上。該清單文件會指示設(shè)備下載和安裝該清單文件中所引用的應(yīng)用程序。

    您可以分發(fā) URL 以便通過短信或電子郵件來下載清單文件,也可以將它嵌入您所創(chuàng)建的其他企業(yè)級應(yīng)用程序中。

    由您設(shè)計和主管用于分發(fā)應(yīng)用程序的網(wǎng)站。確定用戶已被鑒定(可能是使用基本鑒定或基于目錄的鑒定),并確定網(wǎng)站可通過內(nèi)聯(lián)網(wǎng)或互聯(lián)網(wǎng)進行訪問。您可以將應(yīng)用程序和清單文件放入隱藏的目錄中,或任何可使用 HTTP 或 HTTPS 來讀取的其他位置中。

    準備企業(yè)級應(yīng)用程序進行無線分發(fā)

    若要準備企業(yè)級應(yīng)用程序進行無線分發(fā),您應(yīng)該構(gòu)建歸檔的版本(.ipa 文件),以及構(gòu)建清單文件以啟用應(yīng)用程序的無線分發(fā)和安裝。

    使用 Xcode 來創(chuàng)建應(yīng)用程序歸檔。使用您的分發(fā)證書給應(yīng)用程序簽名并在歸檔中包括您的企業(yè)級開發(fā)預(yù)置描述文件。有關(guān)清單文件的信息,請參閱以下內(nèi)容。有關(guān)構(gòu)建和歸檔應(yīng)用程序的更多信息,請訪問 iOS Dev Center(iOS 開發(fā)中心)或參閱《Xcode User Guide》(Xcode 使用手冊),可通過 Xcode 中的“Help”(幫助)菜單來訪問該使用手冊。

    關(guān)于無線清單文件

    清單文件是 XML plist 格式的。iOS 設(shè)備使用它在 Web 服務(wù)器上查找應(yīng)用程序,以及從 Web 服務(wù)器上下載和安裝應(yīng)用程序。清單文件是由 Xcode 創(chuàng)建的,使用您在共享歸檔的應(yīng)用程序以進行企業(yè)級分發(fā)時所提供的信息。請參閱上一節(jié)準備應(yīng)用程序進行分發(fā)

    以下欄是必填的:

    項目

    描述

    URL

    應(yīng)用程序 (.ipa) 文件的完整合格的 HTTP 或 HTTPS URL。

    display-image

    下載和安裝過程中顯示的 57 x 57 像素 PNG 圖像。指定圖像的完整合格的 URL。

    full-size-image

    用來在 iTunes 中表示應(yīng)用程序的 512 x 512 像素 PNG 圖像。

    bundle-identifier

    您應(yīng)用程序的包標識符,與 Xcode 項目中指定的完全一樣。

    bundle-version

    您應(yīng)用程序的包版本,在 Xcode 項目中指定。

    title

    下載和安裝過程中顯示的應(yīng)用程序的名稱。

    僅對于“報刊雜志”應(yīng)用程序,需要填寫以下欄位:

    項目

    描述

    newsstand-image

    完整大小的 PNG 圖像,用于顯示在“報刊雜志”書架上。

    UINewsstandBindingEdge

    UINewsstandBindingType

    這些鍵必須與“報刊雜志”應(yīng)用程序中的 info.plist 中的鍵相符。

    UINewsstandApp

    指示該應(yīng)用程序是“報刊雜志”應(yīng)用程序。

    您可以使用的一些可選鍵如示例清單文件所述。例如,如果應(yīng)用程序文件太大并且您想要在執(zhí)行錯誤檢驗(TCP 通信通常會執(zhí)行該操作)的基礎(chǔ)上確保下載的完整性,則可以使用 MD5 鍵。

    您可以使用單個清單文件安裝多個應(yīng)用程序,方法是指定 items 數(shù)組的附加成員。

    本文稿末尾列出了示例清單文件。

    構(gòu)建網(wǎng)站

    將這些項目上傳到您網(wǎng)站上已鑒定的用戶可以訪問的區(qū)域:

    • 應(yīng)用程序 (.ipa) 文件

    • 清單 (.plist) 文件

    您的網(wǎng)站設(shè)計可以像用來鏈接到清單文件的單個頁面那么簡單。當用戶輕按 Web 鏈接時,清單文件會被下載,并觸發(fā)它所描述的應(yīng)用程序的下載和安裝。

    以下是一個示例鏈接:

    <a href="itms-services://?action=download-manifest&url=http://example.com/
manifest.plist">Install App</a>

    請勿添加歸檔的應(yīng)用程序 (.ipa) 的 Web 鏈接。載入清單文件時,設(shè)備會下載該 .ipa。雖然 URL 的協(xié)議部分是 itms-services,但 iTunes Store 并不參與此過程。

    設(shè)定服務(wù)器 MIME 類型

    您可能需要配置您的 Web 服務(wù)器以便正確地傳輸清單文件和應(yīng)用程序文件。

    對于 OS X Server,將以下 MIME 類型添加到 Web 服務(wù)的“MIME Types”(MIME 類型)設(shè)置中:

    application/octet-stream ipa

    text/xml plist

    對于 IIS,使用 IIS Manager 在服務(wù)器的“屬性”頁面中添加 MIME 類型:

    .ipa application/octet-stream

    .plist text/xml

    openssl使用的是macos系統(tǒng)自帶的版本,關(guān)鍵點是不同直接使用ios設(shè)備打開https的鏈接,需要將證書發(fā)到系統(tǒng)的mail里,安裝到設(shè)備,
    如果命令執(zhí)行不成功,用sudo執(zhí)行。

    1.生成服務(wù)器的私鑰
    openssl genrsa -out server.key 1024

    2.生成簽署申請(注意除Common Name以外可以為空,Common Name必須為服務(wù)器的ip或域名)
    openssl req -new -key server.key -out server.csr

    3.生成CA私鑰
    openssl genrsa  -out ca.key 1024 

    4.利用CA的私鑰產(chǎn)生CA的自簽署證書
    openssl req  -new -x509 -days 365 -key ca.key -out ca.crt

    5.在當前目錄創(chuàng)建demoCA,里面創(chuàng)建文件index.txt和serial,serial內(nèi)容為01,index.txt為空,以及文件夾newcerts
    openssl ca -in server.csr -out server.crt -cert ca.crt -keyfile ca.key
    將ca.crt文件通過郵件發(fā)送到ios設(shè)備的Mail上,進行證書的安裝
    nginx https配置:

     

     

        server {

            listen       443;
            server_name  ios.xxx.com;
            error_log  /dev/null;
            ssl                  on;
            ssl_certificate      server.crt;
            ssl_certificate_key  server.key;
            ssl_session_timeout  5m;
            #ssl_protocols  SSLv2 SSLv3 TLSv1;
            ssl_protocols  SSLv3 TLSv1;
            ssl_ciphers  ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;
            ssl_prefer_server_ciphers   on;
            root   /workspace/ios;
            #add_header Content-Disposition: 'attachment;';
        }
    posted @ 2014-06-26 21:42 小馬歌 閱讀(22915) | 評論 (2)編輯 收藏
     
    ylbtech-DatabaseDesgin:ylbtech-QQ(騰訊)-群空間-數(shù)據(jù)庫設(shè)計

    DatabaseName:QQ-群空間

    Model:群相冊、群共享、群論壇、群成員、留言板、公告。6個模塊。

    Type:空間-群空間、論壇

    Url:http://qun.qzone.qq.com/

    1.A,數(shù)據(jù)庫關(guān)系圖(Database Diagram)

    1.B,數(shù)據(jù)庫設(shè)計腳本(Database Design Script)-第一版
    use master
    go
    -- =============================================
    -- DatabaseName:QQ-群空間
    -- pubdate:16:50 2013-09-26
    -- author:Yuanbo
    -- http://qun.qzone.qq.com/
    -- =============================================
    IF EXISTS (SELECT * 
           FROM   master..sysdatabases 
           WHERE  name = N'qq_qun')
        DROP DATABASE qq_qun
    GO
    CREATE DATABASE qq_qun
    GO
    use qq_qun
    go
    -- =============================================
    -- ylb:1,賬戶表
    -- 
    -- =============================================
    create table account
    (
    account_id int identity(100000,1) primary key,    --編號【PK】
    nickname varchar(20) not null,    --昵稱
    pwd varchar(20) not null,        --密碼
    [type] int,        --類型 0:QQ號;1:QQ群號
    [enable] bit --狀態(tài) 0:正常;1:禁用
    )
    -- =============================================
    -- ylb: 3.1.1 相冊表
    -- =============================================
    create table album
    (
    album_id int primary key identity(1,1),    --編號【PK】
    album_name varchar(30) not null,        --相冊名稱
    album_desc varchar(80),        --相冊描述
    pubdate datetime default(getdate()),        --創(chuàng)建時間
    album_url varchar(100),                        --封面圖片
    account_qq int references account(account_id),    --相冊創(chuàng)建者的QQ號
    account_qun_id int references account(account_id),    --QQ群號
    )
    GO
    -- =============================================
    -- ylb: 3.2.1 相片表
    -- =============================================
    create table photo
    (
    photo_id int primary key identity(100,1),    --編號【PK】
    photo_name varchar(30) not null,        --相片名稱
    --photo_desc varchar(100),                --描述
    photo_url varchar(100),                --保存地址
    pubdate datetime default(getdate()),        --上傳時間
    album_id int references Album(album_id),    --相冊編號[FK]
    account_qq int references account(account_id),    --相冊創(chuàng)建者的QQ號
    account_qun_id int references account(account_id),    --QQ群號
    )
    GO
    -- =============================================
    -- ylb: 3.2.2 相片評論表
    -- =============================================
    create table replyphoto
    (
    replyphoto_id int primary key identity(100,1),--編號
    content varchar(200) not null,            --評論內(nèi)容
    pubdate datetime default(getdate()),        --評論時間
    baseId int default(0),                --評論級次 0:發(fā)表;其他:回復(fù)|跟貼
    photo_id int references photo(photo_id),    --照片編號[FK]
    account_qq int references account(account_id),    --相冊創(chuàng)建者的QQ號
    account_qun_id int references account(account_id),    --QQ群號
    )
    -- =============================================
    -- ylb:1,群共享
    -- 
    -- =============================================
    create table share
    (
    [filename] varchar(20),    --文件名
    ttl datetime,    --有效期【14天】
    filesize int,        --文件大小【8.65KB】
    uploaded_author varchar(20),    --上傳者
    pubdate datetime default(getdate()),    --上傳時間
    download_cnt int,    --下載次數(shù)
    account_id int references account(account_id), --上傳者QQ號
    account_qun_id    int references account(account_id) --群編號
    )
    go
    -- =============================================
    -- ylb:1,群論壇
    -- 
    -- =============================================
    create table bbs
    (
    bbs_id int primary key identity(100,1),    --編號【PK】
    [subject] varchar(20),    --主題
    content varchar(400),    --內(nèi)容
    pubdate datetime default(getdate()),        --創(chuàng)建時間
    lock_enable bit,    --鎖帖|解鎖
    stick_enable bit,    --0:不頂置;1:頂置
    tags_enable bit,    --0:;1:精華
    lightbox_enable bit, --1:高亮
    account_qq int references account(account_id),    --相冊創(chuàng)建者的QQ號
    account_qun_id int references account(account_id)    --QQ群號
    )
    go
    -- =============================================
    -- ylb:1,回復(fù)主題
    -- 
    -- =============================================
    create table replaybbs
    (
    replaybbs_id int primary key identity(100,1),    --編號【PK】
    content varchar(400),    --內(nèi)容
    pubdate datetime default(getdate()),        --創(chuàng)建時間
    bbs_id int references bbs(bbs_id),    --主題編號
    account_qq int references account(account_id),    --相冊創(chuàng)建者的QQ號
    account_qun_id int references account(account_id)    --QQ群號
    )
    go
    -- =============================================
    -- ylb:1,群成員
    -- 
    -- =============================================
    create table member
    (
    member_id int primary key identity(100,1),--編號
    group_nikename varchar(30),    --群昵稱
    sex varchar(2),        --性別
    phone varchar(13),    --電話
    email varchar(60),    --郵箱
    remark varchar(200),--備注
    pubdate datetime default(getdate()),        --創(chuàng)建時間
    alow_admin_edit_enable bit,    --允許管理員協(xié)助修改我的群名片
    [role] int,    --角色:群主|管理員|成員【power】
    account_id int references account(account_id), --上傳者QQ號
    account_qun_id    int references account(account_id)--群編號
    )
    go
    -- =============================================
    -- ylb:1,留言板
    -- 
    -- =============================================
    create table messageboard
    (
    messageboard_id int primary key identity(100,1),--編號
    content varchar(30),    --內(nèi)容
    pubdate datetime default(getdate()),       --創(chuàng)建時間
    account_id int references account(account_id), --上傳者QQ號
    account_qun_id    int references account(account_id)--群編號
    )
    go
    -- =============================================
    -- ylb:1,公告
    -- 
    -- =============================================
    create table notice
    (
    notice_id int primary key identity(100,1),--編號
    content varchar(30),    --內(nèi)容
    pubdate datetime default(getdate()),       --創(chuàng)建時間
    account_id int references account(account_id), --上傳者QQ號
    account_qun_id    int references account(account_id)--群編號
    )
    go
    -- =============================================
    -- ylb:1,標簽【公共】
    -- 
    -- =============================================
    create table tag
    (
    tag_id uniqueidentifier,    --guid
    tag_name varchar(30),    --標簽名稱
    pubdate datetime default(getdate())       --創(chuàng)建時間
    )
    go
    print 'QQ 群空間數(shù)據(jù)創(chuàng)建成功!'
    1.C,數(shù)據(jù)庫設(shè)計腳本(Database Design Script)-第二版
    posted @ 2014-06-19 20:02 小馬歌 閱讀(405) | 評論 (0)編輯 收藏
     

    1.推送過程簡介

         (1)App啟動過程中,使用UIApplication::registerForRemoteNotificationTypes函數(shù)與蘋果的APNS服務(wù)器通信,發(fā)出注冊遠程推送的申請。若注冊成功,回調(diào)函數(shù)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken 會被觸發(fā),App可以得到deviceToken,該token就是一個與設(shè)備相關(guān)的字符串.
         (2)App獲取到DeviceToken后,將DeviceToken發(fā)送給自己的服務(wù)端。
         (3)服務(wù)端拿到DeviceToken以后,使用證書文件,向蘋果的APNS服務(wù)器發(fā)起一個SSL連接。連接成功之后,發(fā)送一段JSON串,該JSON串包含推送消息的類型及內(nèi)容。
        (4)蘋果的APNS服務(wù)器得到JSON串以后,向App發(fā)送通知消息,使得App的回調(diào)函數(shù)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo被調(diào)用,App從userInfo中即可得到推送消息的內(nèi)容。

     

    2. 用到的證書文件及生成過程

       (1)certSigningRequest文件,該文件在MAC系統(tǒng)中生成,用于在Apple網(wǎng)站上申請推送證書文件。
             生成過程:
             打開應(yīng)用程序中的“鑰匙串訪問”軟件,從菜單中選擇 “鑰匙串訪問”-》“證書助理”-》“從證書頒發(fā)機構(gòu)請求證書”,郵箱和名稱隨便填寫,然后選擇保存到磁盤,就可以在本地生成一個CertificateSigningRequest.certSigningRequest文件。

       (2)注冊一個支持push的app id,后面會用到。
            生成過程:
           進入developer.apple.com,選擇member center - Certificates, Identifiers & Profiles  -  Identifiers- App Ids,然后選擇注冊app id,設(shè)置appid名稱,同時,app id suffix一欄必須選擇explicit app id,然后設(shè)置bundle id,最后勾選 App Services中的 Push Notifications,這樣就可以注冊一個支持push的aphid。

        
      (3) 推送證書cer文件,該文件在developer.apple.com中生成,用于生成服務(wù)端需要的文件。
            生成過程:
            進入developer.apple.com,選擇member center - Certificates, Identifiers & Profiles  -  Certificates,然后選擇創(chuàng)建certificate,類型分為Development和Product。這里以Development為例,選擇Apple Push Notification service SSL (Sandbox) ,然后下一步,選擇之前生成的支持push的AppId,然后下一步,提交之前創(chuàng)建的CSR文件,再下一步就可以生成cer文件,然后保存到本地。

      (4)生成服務(wù)端使用的證書文件。如果是使用網(wǎng)上的mac 版PushMeBaby工具,在mac機器上進行推送消息的發(fā)送,那么有上面的cer文件就夠了。如果是使用PHP、java/c#開發(fā)自己的服務(wù)端,那么還需要將上面的cer文件做一個轉(zhuǎn)換,生成pem文件或者p12文件。

           生成php用的pem文件過程為
            首先雙擊前面保存的cer文件,此時會打開“鑰匙串訪問”軟件,里面會出現(xiàn)一個Apple Development  IOS push services證書,一個公用密鑰和一個專用秘鑰,秘鑰的名稱與證書助理中填寫的名稱一致。
          選中證書,導(dǎo)出為 apns-dev-cert.p12 文件
          選中專有秘鑰,導(dǎo)出為apns-dev-key.p12文件
          通過終端命令將這些文件轉(zhuǎn)換為PEM格式:
          openssl pkcs12 -clcerts -nokeys -out apns-dev-cert.pem -in apns-dev-cert.p12
          openssl pkcs12 -nocerts -out apns-dev-key.pem -in apns-dev-key.p12
          最后, 需要將兩個pem文件合并成一個apns-dev.pem文件,此文件在連接到APNS時需要使用:
          cat apns-dev-cert.pem apns-dev-key-noenc.pem > apns-dev.pem

           生成java/c#用的p12文件過程為

           openssl pkcs12 -clcerts -nokeys -out apns-dev-cert.pem -in apns-dev-cert.p12
           openssl pkcs12 -nocerts -out apns-dev-key.pem -in apns-dev-key.p12
           openssl pkcs12 -export -in apns-dev-cert.pem -inkey apns-dev-key.pem -certfile CertificateSigningRequest.certSigningRequest -name "push" -out push.p12      

          
      (5)生成XCODE使用的provisioning文件,該文件用于真機調(diào)試。
             生成過程:
             進入developer.apple.com,選擇member center - Certificates, Identifiers & Profiles  -  Provisioning Profiles,然后選擇創(chuàng)建Provisioning  file,接著選擇iOS App Development ,下一步選擇AppId,選中之前建立的支持push的appid,接著下一步選擇支持push的certificate,下一步勾選需要支持的device id,最后一步設(shè)置provisioning文件的文件名,這樣provisioning文件就生成了。

        3. 服務(wù)端的開發(fā)
         (1)如果只是希望在mac電腦上測試一下消息的推送,可以使用PushMeBaby工具,使用起來比較簡單。該工具是開源的,可以從https://github.com/stefanhafeneger/PushMeBaby 下載,代碼的執(zhí)行過程實際上就是設(shè)置一下SSL證書,然后連接APNS,接著發(fā)送JSON數(shù)據(jù)。由于要處理SSL邏輯,因此代碼稍微多點。在使用工具時,將工程資源中的cer文件替換成自己的cer文件,然后將代碼中的deviceToken替換成自己設(shè)備的deviceToken即可。


         (2)使用php開發(fā)服務(wù)端
           由于php已經(jīng)內(nèi)置了ssl模塊,因此使用php連接APNS服務(wù)器來發(fā)送json的過程實際上是很簡單的,代碼如下:

    該文件可以放到服務(wù)器中通過瀏覽器來訪問,也可以通過命令行的方式來解釋執(zhí)行,代碼為:$ php -f Pusher.php

         

    復(fù)制代碼
    <?php $deviceToken= ‘自己的deviceToken'; //沒有空格
    $body = array("aps" => array("alert" => 'message',"badge" => 2,"sound"=>'default')); //推送方式,包含內(nèi)容和聲音$$ctx = stream_context_create();

    //如果在Windows的服務(wù)器上,尋找pem路徑會有問題,路徑修改成這樣的方法:
    //$pem = dirname(__FILE__) . '/' . 'apns-dev.pem';
    //linux 的服務(wù)器直接寫pem的路徑即可
    stream_context_set_option($ctx,"ssl","local_cert","apns-dev.pem");
    $pass = "xxxxxx";stream_context_set_option($ctx, 'ssl', 'passphrase', $pass);//
    //此處有兩個服務(wù)器需要選擇,如果是開發(fā)測試用,選擇第二名sandbox的服務(wù)器并使用Dev的pem證書,如果是正式發(fā)布,使用Product的pem并選用正式的服務(wù)器
    $fp = stream_socket_client("ssl://gateway.push.apple.com:2195", $err, $errstr, 60, STREAM_CLIENT_CONNECT, $ctx);
    $fp = stream_socket_client("ssl://gateway.sandbox.push.apple.com:2195", $err, $errstr, 60, STREAM_CLIENT_CONNECT, $ctx);
    if (!$fp)
    {echo "Failed to connect $err $errstrn";return;}
    print "Connection OK\n";
    $payload = json_encode($body);$msg = chr(0) . pack("n",32) . pack("H*", str_replace(' ', '', $deviceToken)) . pack("n",strlen($payload)) . $payload;
    echo "sending message :" . $payload ."\n";
    fwrite($fp, $msg); fclose($fp);
    ?>
    復(fù)制代碼

        4. 客戶端的開發(fā)
         (1)下載前面建立的cer文件和provisioning文件,雙擊,導(dǎo)入到xcode中,在build setting中code signing一欄里選擇這兩個文件的名稱,這樣就可以將支持push的app部署到真機中。
         

         (2)處理推送消息
               客戶端對推送消息的處理分兩種情況:
              一. 在App沒有運行的情況下,系統(tǒng)收到推送消息,用戶點擊推送消息,啟動App。此時,不會執(zhí)行前面提到的          didReceiveRemoteNotification函數(shù),而是在App的applicationDidFinishLaunching函數(shù)中處理推送,通過以下代碼可以獲取推送消息中的數(shù)據(jù): NSDictionary *userInfo =[launchOptionsobjectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];


              二 . 當APP處于前臺時,系統(tǒng)收到推送消息,此時系統(tǒng)不會彈出消息提示,會直接觸發(fā)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo函數(shù),推送數(shù)據(jù)在userInfo字典中。

               當App處于后臺時,如果系統(tǒng)收到推送消息,當用戶點擊推送消息時,會執(zhí)行application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo函數(shù),
              此時AppDelegate中函數(shù)執(zhí)行的順序為:
              applicationWillEnterForeground 
              application:didReceiveRemoteNotification

              applicationDidBecomeActiveI
    posted @ 2014-06-18 16:53 小馬歌 閱讀(5623) | 評論 (0)編輯 收藏
     

    下面內(nèi)容來源于Quora上的一個提問,問題是使用Redis需要避免的五個問題。而回答中超出了五個問題的范疇,描述了五個使用Redis的注意事項。如果你在使用或者考慮使用Redis,可能你可以學(xué)習一下下面的一些建議,避免一下提到的問題。

    1.使用key值前綴來作命名空間

    雖然說Redis支持多個數(shù)據(jù)庫(默認32個,可以配置更多),但是除了默認的0號庫以外,其它的都需要通過一個額外請求才能使用。所以用前綴作為命名空間可能會更明智一點。

    另外,在使用前綴作為命名空間區(qū)隔不同key的時候,最好在程序中使用全局配置來實現(xiàn),直接在代碼里寫前綴的做法要嚴格避免,這樣可維護性實在太差了。

    2.創(chuàng)建一個類似 ”registry” 的key用于標記key使用情況

    為了更好的管理你的key值的使用,比如哪一類key值是屬于哪個業(yè)務(wù)的,你通常會在內(nèi)部wiki或者什么地方創(chuàng)建一個文檔,通過查詢這個文檔,我們能夠知道Redis中的key都是什么作用。

    與之結(jié)合,一個推薦的做法是,在Redis里面保存一個registry值,這個值的名字可以類似于 __key_registry__ 這樣的,這個key對應(yīng)的value就是你文檔的位置,這樣我們在使用Redis的時候,就能通過直接查詢這個值獲取到當前Redis的使用情況了。

    3.注意垃圾回收

    Redis是一個提供持久化功能的內(nèi)存數(shù)據(jù)庫,如果你不指定上面值的過期時間,并且也不進行定期的清理工作,那么你的Redis內(nèi)存占用會越來越大,當有一天它超過了系統(tǒng)可用內(nèi)存,那么swap上場,離性能陡降的時間就不遠了。所以在Redis中保存數(shù)據(jù)時,一定要預(yù)先考慮好數(shù)據(jù)的生命周期,這有很多方法可以實現(xiàn)。

    比如你可以采用Redis自帶的過期時間為你的數(shù)據(jù)設(shè)定過期時間。但是自動過期有一個問題,很有可能導(dǎo)致你還有大量內(nèi)存可用時,就讓key過期去釋放內(nèi)存,或者是內(nèi)存已經(jīng)不足了key還沒有過期。

    如果你想更精準的控制你的數(shù)據(jù)過期,你可以用一個ZSET來維護你的數(shù)據(jù)更新程度,你可以用時間戳作為score值,每次更新操作時更新一下score,這樣你就得到了一個按更新時間排序序列串,你可以輕松地找到最老的數(shù)據(jù),并且從最老的數(shù)據(jù)開始進行刪除,一直刪除到你的空間足夠為止。

    4.設(shè)計好你的Sharding機制

    Redis目前并不支持Sharding,但是當你的數(shù)據(jù)量超過單機內(nèi)存時,你不得不考慮Sharding的事(注意:Slave不是用來做Sharding操作的,只是數(shù)據(jù)的一個備份和讀寫分離而已)。

    所以你可能需要考慮好數(shù)據(jù)量大了后的分片問題,比如你可以在只有一臺機器的時候就在程序上設(shè)定一致性hash機制,雖然剛開始所有數(shù)據(jù)都hash到一臺機器,但是當你機器越加越多的時候,你就只需要遷移少量的數(shù)據(jù)就能完成了。

    5.不要有個錘子看哪都是釘子

    當你使用Redis構(gòu)建你的服務(wù)的時候,一定要記住,你只是找了一個合適的工具來實現(xiàn)你需要的功能。而不是說你在用Redis構(gòu)建一個服務(wù),這是很不同的,你把Redis當作你很多工具中的一個,只在合適使用的時候再使用它,在不合適的時候選擇其它的方法。

    來源:www.quora.com

    posted @ 2014-06-18 11:17 小馬歌 閱讀(298) | 評論 (0)編輯 收藏
    僅列出標題
    共95頁: First 上一頁 18 19 20 21 22 23 24 25 26 下一頁 Last 
     
    主站蜘蛛池模板: 国产亚洲一区二区手机在线观看 | 一个人免费视频观看在线www| 亚洲国产成人AV在线播放| 日本免费xxxx| 亚洲宅男永久在线| 69视频在线是免费观看| 日本一道在线日本一道高清不卡免费| 国产午夜影视大全免费观看| 国产成人无码综合亚洲日韩| 亚洲乱色伦图片区小说| 日韩精品无码免费专区午夜不卡| 国产成人毛片亚洲精品| xxxxx做受大片视频免费| 曰批全过程免费视频播放网站| 日本久久久久亚洲中字幕| 99在线观看精品免费99| 国产亚洲美女精品久久久2020| 亚洲欧美国产国产综合一区| 妞干网免费视频观看| 羞羞视频免费观看| 国产精品亚洲精品日韩已方| 亚洲免费观看视频| 亚洲一区精品视频在线| 永久免费AV无码网站在线观看| 亚洲黄色网站视频| 成人免费视频软件网站| 欧洲乱码伦视频免费国产| 亚洲人成亚洲人成在线观看| 8x网站免费入口在线观看| 中文字幕亚洲码在线| 114一级毛片免费| 亚洲va久久久噜噜噜久久男同 | 日韩在线免费视频| 色偷偷亚洲男人天堂| 亚洲精品午夜无码专区| 91嫩草免费国产永久入口| 亚洲AV无码AV吞精久久| 亚洲日韩小电影在线观看| 1000部拍拍拍18勿入免费凤凰福利| 亚洲欧美日韩久久精品| 亚洲中文字幕无码久久2017|