posts - 33, comments - 0, trackbacks - 0, articles - 0
            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

          2011年9月6日

                在第一篇時就說過框架要在URL上作文章,是的,本文就框架怎樣充分利用url上作盡可能詳細的說明。

                做web開發的不可能對url陌生,早在web1.0時代,url作為統一資源定位符,在對web中資源的如何獲得上起到巨大作用。不論用戶請求的時靜態頁面或者是各種圖片、腳本文件,通過url總能從web網站獲取要訪問的資源。Web2.0更是常常使用url作為get請求時參數的傳遞,如http://xxx.xxx.xxx/xxx.jsp?user=admin。以及近幾年很火restful web service 摒棄soap而使用url傳遞請求參數 都說明合理利用url的可行和流行。

                當然不止是使用了url就算好的實踐,而是能夠做到優雅的使用,保證層次分明和整體的簡潔,這才算是好的方式,這也正是本框架對使用url 所追求的目標。

                首先來看幾個例子:

          http://www.cnblogs.com/p2
          http://www.xxx.com/index.do?page=2

          http://www.xxx.com/product/
          http://www.xxx.com/channel.do?channel=product

          http://www.xxx.com/product/mobile
          http://www.xxx.com/channel.do?channel=product&&subChannel=mobile

                相信各位看官不用我說也能明白,這幾組的實現肯定第一種實現的方式更佳。拋開它能屏蔽服務器端使用的技術這一特性不說,它還能夠更好地說明動態網站的層次結構,讓用戶在訪問時能明確知道在網站的什么位置,而不會覺得是陷入了一個迷宮。

                當然上面列舉的例子是網站前端所使用的url表現方式,因為表現方式可以多種多樣,個人喜好不同,本框架在設計時沒有給指定前端url的表現方式,而是定義接口,把這個權利留給使用的用戶。框架將考慮更多 通用性的東西而不是 個性 自由的東西。

           

                下面對框架里默認使用的url Router AMPPathRouter做詳細的介紹,包括設計的思想和實現的方式。首先AMPPathRouter的用途定位為后臺使用。為了理解快速的理解它的工作原理,先來和struts做一下對比。

                Struts關于請求的配置:

           

          <action name="login" class="com.lscmjx.action.LoginAction" method="login">
          <result name="success">
          main.jsp
          </result>
          <result name="failure">
          login.jsp
          </result>
          </action>

              它提交的url會是http://xxx.xxx.xxx/login,訪問web服務器時會把此url傳遞到struts框架交給它處理,之后struts會在struts.xml中尋找login的相關的配置,像上面例子,struts會找到LoginAction的類,并且調用其login的方法。

                寫到這里,我請問這是最好的方式嗎?當然不是,至少我在使用struts時就認為這是相當撇腳的設計。上面例子只是列舉一個login方法,假如一個系統中要對后臺調用的方法是100個,那豈不是就需要在struts.xml中寫100個與之類似的配置。想想都頭大,這樣繁瑣的工作,應該是由框架自己去處理,而不是人工給配置。

           

                再來看實現相同功能的Unicorn web框架的配置。

           

          <action class="com.mh.action.UserAction"></action>

                當然提交的url肯定需要包含多一些的信息,來保證能通過url正確調用框架Action里的方法。這里提交的url方式:http://xxx.xxx.xxx/UserAction/login/

                通過在url里附加調用的Action類的信息,可以省略為不同的方法都在xml里配置的麻煩。假如UserAction里有100個方法,框架也只需這一行的配置。

                有了大體的認識之后,來看框架的核心部分AMPPathRouter的具體實現。

           

            /**
          * 檢查url是否是此Router類要處理的,/Action/Method/Param 格式的將會被檢查合格,返回true
          *
          @param relativeUri
          *
          @param actionMap
          *
          @return
          */
          public boolean checkUrl(String relativeUri, Map<String, ActionSupport> actionMap) {
          Pattern pattern = Pattern.compile("^/\\w+/\\w+/\\S*");
          Matcher matcher = pattern.matcher(relativeUri);
          if(matcher.matches()) {
          String actionName = relativeUri.split("/")[1];
          ActionSupport actionSupport = actionMap.get(actionName);
          if(null != actionSupport) {
          String actionMethodName = relativeUri.split("/")[2];
          Class<?> actionClass = actionSupport.getClass();
          Method[] methods = actionClass.getMethods();
          for(int i = 0; i < methods.length; i++) {
          Method method = methods[i];
          String methodName = method.getName();
          if(methodName.equals(actionMethodName)) {
          return true;
          }
          }
          } else {
          return false;
          }
          }
          return false;
          }
          /**
          * 匹配規則為:
          * 1、符合/Action/method/param格式,
          * 2、并且Action在actionMap中的確存在
          * 3、method在此Action中存在
          */
          @Override
          public boolean route(String relativeUri, UrlFilter urlFilter) {
          Map<String, ActionSupport> actionMap = urlFilter.getActionMap();
          if(!this.checkUrl(relativeUri, actionMap)) {
          return false;
          }
          // 攔截Action/Method/Param方式的請求,并構建ActionSupport類的屬性
          String[] params = relativeUri.split("/");
          try {
          ActionSupport actionSupport = actionMap.get(params[1]);
          Class<?> action = actionSupport.getClass();
          Method method = action.getMethod(params[2], new Class[] {});
          if(params.length > 3) {
          this.boxingRequest(urlFilter.getRequest(), params[3]);
          }
          // 只要找到ActionSupport的子類,則初始化其所具有的屬性
          Object newInstance = action.newInstance();
          this.initActionSupport(newInstance, urlFilter);
          String result = (String) method.invoke(newInstance, new Object[] {});
          if (null == result || ActionSupport.AJAX.equals(result) || ActionSupport.FORWARD.equals(result) || ActionSupport.WEB_SERVICE.equals(result)) {
          return true;
          }
          if(ActionSupport.REDIRECT.equals(result)) {
          urlFilter.getResponse().sendRedirect(result);
          return true;
          }
          } catch (NoSuchMethodException e) {
          e.printStackTrace();
          } catch (SecurityException e) {
          e.printStackTrace();
          } catch (IllegalAccessException e) {
          e.printStackTrace();
          } catch (IllegalArgumentException e) {
          e.printStackTrace();
          } catch (InvocationTargetException e) {
          e.printStackTrace();
          } catch (InstantiationException e) {
          e.printStackTrace();
          } catch (Exception e) {
          e.printStackTrace();
          }
          return false;
          }
          /**
          * 把url中得param加入到request的attribute里
          *
          @param request
          *
          @param parameter
          */
          private void boxingRequest(HttpServletRequest request, String parameter) {
          String[] parameters = parameter.split("&");
          for (int i = 0; i < parameters.length; i++) {
          String param = parameters[i];
          String[] key_value = param.split("=");
          if(key_value.length == 2) {
          request.setAttribute(key_value[0], key_value[1]);
          }
          }
          }
          /**
          * 初始化ActionSupport類中所需的request、response、session、application等對象
          *
          @param obj
          *
          @param urlFilter
          */
          private void initActionSupport(Object obj, UrlFilter urlFilter) {
          ActionSupport action = (ActionSupport) obj;
          action.setRequest(urlFilter.getRequest());
          action.setResponse(urlFilter.getResponse());
          action.setSession(urlFilter.getSession());
          action.setApplication(urlFilter.getApplication());
          }

           

                這便是AMPPathRouter的全部內容,其中在把請求分發到ActionSupport的子類 并調用相關方法時 是通過反射實現,其他地方地方都是相當容易理解的。

                空說無憑,把框架應用到實戰中才是硬道理:

           

                好了,下一篇介紹Action 和 json。

          posted @ 2011-11-25 18:18 馬航 閱讀(270) | 評論 (0)編輯 收藏

                上篇說過,所有提交到web程序的url都被此UrlFilter攔截。攔截到請求后,UrlFilter則召集它的好多個得力干將Router 們, 詢問他們:“誰能處理此URL啊 ?”

          這時一位叫做AMPRouter 首當其沖 說:“這個url交給我了”。這時filter就會把此url全權交給AMPRouter來辦,至于如何去處理,filter也不再過問,它覺得:“我把任務都交給你了,怎么解決是你的事”。

                根據單一職責的原則,UrlFilter就負責上面情景中的分發urlRouter中的差事,url如何分發交給Router處理。并且Router實際是一個接口,使用框架的用戶完全可以自己實現Router,這樣用戶可以自主定義的url分發的策略。另外呢,框架初始化的一些操作它也是 推脫不掉的,像根據unicorn-config.xml初始化系統中的RouterAction'。下面是具體的代碼:

           

          @Override
          public void init(FilterConfig config) throws ServletException {
          	application = config.getServletContext();
          	String loadPath = Thread.currentThread().getContextClassLoader().getResource("").getPath();
          	String classPath = loadPath.substring(1, loadPath.length());
          	ArrayList<String> actions = XMLReader.getNodeValues(classPath + "unicorn-config.xml", "actions");
          	this.initActions(actions);
          	ArrayList<String> routers = XMLReader.getNodeValues(classPath + "unicorn-config.xml", "routers");
          	this.initRouters(routers);
          }

           

          @Override
          public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
          			throws IOException, ServletException {
          	HttpServletRequest request = (HttpServletRequest) servletRequest;
          	String path = request.getContextPath();
          	String uri = request.getRequestURI();
          	String relativeUri = uri.substring(path.length(), uri.length());
          	this.request = request;
          	this.session = request.getSession();
          	this.response = (HttpServletResponse) servletResponse;
          	// 用戶自定義的Router優先級最高,url先通過用戶定義的
          	Iterator<IPathRouter> iterator = routerList.iterator();
          	while(iterator.hasNext()) {
          		IPathRouter router = iterator.next();
          		if(router.route(relativeUri, this)) {
          			return ;
          		}
          	}
          	// 攔截不到的繼續訪問
          	filterChain.doFilter(servletRequest, servletResponse);
          }
          

                  其中Router類的初始化,Action類的初始化于這個類似:

          private void initRouters(ArrayList<String> routers) {
          	routerList = new ArrayList<IPathRouter>();
          	for (int i = 0; i < routers.size(); i++) {
          		String routerName = routers.get(i);
          		try {
          			Class<?> clz = Class.forName(routers.get(i));
          			// 單例模式通過方法獲取對象實例
          			IPathRouter router = (IPathRouter) clz.newInstance();
          			routerList.add(router);
          		} catch (ClassNotFoundException e) {
          			e.printStackTrace();
          		} catch (IllegalAccessException e) {
          			e.printStackTrace();
          		} catch (SecurityException e) {
          			e.printStackTrace();
          		} catch (IllegalArgumentException e) {
          			e.printStackTrace();
          		} catch (InstantiationException e) {
          			e.printStackTrace();
          		}
          	}
          	// 最后把框架默認的Router加入進來
          	routerList.add(new AMPPathRouter());
          }
          

                  其中unicorn-config.xml文件的編寫,拿其中我一個項目里的這個文件來舉例:

          <?xml version="1.0" encoding="UTF-8" ?>
          <config>
          <routers>
          <router class="com.mh.router.MySessionCheckRouter"></router>
          </routers>
          <actions>
          <action class="com.mh.action.UserAction"></action>
          <action class="com.mh.action.InformationAction"></action>
          <action class="com.mh.action.UploadInformationIconAction"></action>
          <action class="com.mh.action.TempPicAction"></action>
          <action class="com.mh.action.MobileAction"></action>
          </actions>
          </config>

                這里即定義了Action,也定義了自己的Router,并且從名稱上可以看出,這個SessionCheckRouter是要判斷所有提交到服務器的指定url的請求 是否已經登錄過,沒有登錄,可能會把此請求遣送會登錄頁。以及初始化所有的Action,在Router處理完請求,分發給action時,可以從filter里面去取。

           


          posted @ 2011-11-25 12:35 馬航 閱讀(274) | 評論 (0)編輯 收藏

                承接上篇的簡單介紹,下面詳細介紹整個框架的大致結構。

                先來看一下整個框架包的結構:

           

                可以看出框架包含的包很少,包的結構也超簡單。這里 涉及FilterActionSupportRouter等三個概念,他們之間的關系,通過下圖來表示:

           

                圖也不規范,說不上來是哪個UML圖,不過通過它也能看出一個請求到達時,框架基本的處理流程。首先由Filter攔截到所有請求,然后把請求交給所有注冊的Router類,如果請求的Url正好是一個Router要攔截的,則把此請求交給這個Router,框架不再把請求向下傳遞。Router得到請求后,分析Url,通過Url里的信息把請求交給對應的ActionSupport的子類來處理。

                這里攔截采用Filter來處理,這跟多數的web框架一樣,使用FilterServlet有更多的能力進行請求的分發。首先在一個web工程的web.xml文件中配置框架的UrlFilter類來攔截所有的請求。需要注意的一點是dispatcher 要設置為request,如果設置了forward的話,由框架內部進行的forward又會被框架攔截,從而造成無限的循環。Url-pattern設置為/*,表示所有的請求都會攔截,從而把對url分發的權利交由框架本身,而不是采用jsp規范里的url分發策略。框架在處理所有請求的url 時,依次交給各個Router類來處理,如果Router類判斷是符合自己的url格式,則分發給 action 處理。如果不能處理再交給下一級的Router,最后url經由所有Router處理完,剩下的資源文件的url,如http://xxx.xxx.xxx.jpg,則框架調用filterdoChain()方法,通過filter的過濾去訪問web里的資源。

          <filter>

                <filter-name>unicornWeb</filter-name>

                <filter-class>com.mh.mvc.filter.UrlFilter</filter-class>

          </filter>

          <filter-mapping>

              <filter-name>unicornWeb</filter-name>

              <url-pattern>/*</url-pattern>

              <dispatcher>REQUEST</dispatcher>

          </filter-mapping>

                大致的原理就是這樣,在下篇介紹框架的詳細實現。

          posted @ 2011-11-25 11:43 馬航 閱讀(350) | 評論 (0)編輯 收藏

                我承認有點標題黨了,不過題目中所說的幾項技術確實有其相似之處,欲知事情原委,且聽我詳細道來。

                項目一開始只是不滿 struts 龐大的體積,于是想自己根據其原理實現一個tiny 版。后來的開發中覺得,完全可以把上述的ajax、Restuful web service的一些思想加入進來。經過幾周的努力,便開發出了一個基本成型的web 框架,暫且起名為unicorn(獨角獸,吼吼)。下文開始便對這個自編寫的框架做一些列的介紹,并且初步打算是將其開源,希望能一起交流和完善它。

                首先,為了能快速了解它是什么,先來看一下配置文件:

          <?xml version="1.0" encoding="UTF-8" ?>
          <config>
          <routers>
          <router class="com.mh.router.MySessionCheckRouter"></router>
          </routers>
          <actions>
          <action class="com.mh.action.UserAction"></action>
          <action class="com.mh.action.InformationAction"></action>
          <action class="com.mh.action.MobileAction"></action>
          </actions>
          </config>

                上面就是整個工程的配置文件,可以看出需要配置的東西非常少,只需要制定action類 和 router類有哪些就Ok。框架奉行約定大于配置的思想,至于請求如何分發,這個不需要人工配置,框架自動解決。這里要介紹兩個概念Action 和 Router,熟悉Struts的肯定都知道Action,Action替代Servlet、JSP時代的Servlet,所有提交的請求由struts分發給不同的Action來處理。這里道理也是一樣的,Action就是經過框架處理后的請求接受者。再來說一下Router,字面意思路由器,學過計算機網絡的都知道,ip數據包在網絡上之所以能夠順利到達,就是因為路由器根據路由表來來確定出來傳輸的途徑。這里Router也是這個作用,根據訪問服務器的URL來制定分發策略。Router是完全可以自定義的,用戶可以定義自己的Router來制定URL分發的策略,并且用戶自定義的Router比系統默認的Router有更高的優先權。

          二、URL上做文章

          /UserAction/login/username=admin&&password=admin

                先來介紹系統MethodRouter的處理方式。上面的url根據"/"分為三個部分,第一部分是請求的Action類,第二部分是類中的方法Method,第三部分是提交的參數Param。這一點受上篇文章優酷的架構里URL設計的啟發。

                經過這樣的設計,就明白在上述配置文件中為何可以如此簡單了。

                當然也可以不以這樣的方式,框架提供自定義Router的支持。比如你想這樣處理URL:/前臺頁面/子欄目/子欄目

                想實現上面的方式,就可以自己定義Router,在Router里面獲取上述的URL,然后做處理、forward到相應的jsp頁面。

          三、使用Json傳輸數據

                Ajax請求很容易處理json數據,ajax可以與系統輕松交互。

                當初Web Service使用SOAP的xml格式傳輸數據,如今也有人指責這是大費周折。Restful方式提倡遵循HTTP語義,完全使用URL結合GET、POST、PUT、DELETE來傳輸請求,結果在roil陣營里廣泛使用,認為是web service更優雅的方式。所以本框架也吸取他們的優點,也完全可以通過url傳輸請求的數據,如上述URL中的Param部分。不過沒有遵循Restful強調的Http語義,全部使用Get和POST的請求方式,當然也可以制定為其他,這完全看你的心情,因為這對功能實現無關緊要。而且我覺得統一使用一種,更避免了需要指定請求方式的麻煩。

                數據的返回使用json格式,比SOAP更為輕量簡潔和優雅,而且有更多的平臺直接支持。如在android平臺,本身就支持json格式的處理, 如果使用web service 的SOAP,你可能還要導入KSOAP的第三方庫。

                在非瀏覽器的客戶端,可以借助編寫的工具類,來完成web service方式的操作,

          public interface IWebService {
          	public List<LiteInformationDTO> getInformationsOfOwnerApp(String ownerApp, int start, int limit) throws SocketTimeoutException;
          }
          

                經過這樣的封裝,已經與使用web service毫無差別,而且還會更加高效,因為處理json總比處理SOAP的xml要容易。

           

                先簡單寫這么多,之后的續篇詳細介紹。

          posted @ 2011-11-22 16:22 馬航 閱讀(285) | 評論 (0)編輯 收藏

          記得以前給大家介紹過視頻網站龍頭老大YouTube的技術架構,相信大家看了都會有不少的感觸,互聯網就是這么一個神奇的東西。今天我突然想到,優酷網在國內也算是視頻網站的老大了,不知道他的架構相對于YouTube是怎么樣的,于是帶著這個好奇心去網上找了優酷網架構的各方面資料,雖然談得沒有YouTube那么詳細,但多少還是挖掘了一點,現在總結一下,希望對喜歡架構的朋友有所幫助。

          一、網站基本數據概覽

          • 據2010年統計,優酷網日均獨立訪問人數(uv)達到了8900萬,日均訪問量(pv)更是達到了17億,優酷憑借這一數據成為google榜單中國內視頻網站排名最高的廠商。
          • 硬件方面,優酷網引進的戴爾服務器主要以 PowerEdge 1950與PowerEdge 860為主,存儲陣列以戴爾MD1000為主,2007的數據表明,優酷網已有1000多臺服務器遍布在全國各大省市,現在應該更多了吧。

          二、網站前端框架

          從一開始,優酷網就自建了一套CMS來解決前端的頁面顯示,各個模塊之間分離得比較恰當,前端可擴展性很好,UI的分離,讓開發與維護變得十分簡單和靈活,下圖是優酷前端的模塊調用關系:

          這樣,就根據module、method及params來確定調用相對獨立的模塊,顯得非常簡潔。下面附一張優酷的前端局部架構圖:

           

          三、數據庫架構

          應該說優酷的數據庫架構也是經歷了許多波折,從一開始的單臺MySQL服務器(Just Running)到簡單的MySQL主從復制、SSD優化、垂直分庫、水平sharding分庫,這一系列過程只有經歷過才會有更深的體會吧,就像MySpace的架構經歷一樣,架構也是一步步慢慢成長和成熟的。

          1、簡單的MySQL主從復制:

          MySQL的主從復制解決了數據庫的讀寫分離,并很好的提升了讀的性能,其原來圖如下:

          其主從復制的過程如下圖所示:

          但是,主從復制也帶來其他一系列性能瓶頸問題:

          1. 寫入無法擴展
          2. 寫入無法緩存
          3. 復制延時
          4. 鎖表率上升
          5. 表變大,緩存率下降

          那問題產生總得解決的,這就產生下面的優化方案,一起來看看。

           

          2、MySQL垂直分區

          如果把業務切割得足夠獨立,那把不同業務的數據放到不同的數據庫服務器將是一個不錯的方案,而且萬一其中一個業務崩潰了也不會影響其他業務的正常進行,并且也起到了負載分流的作用,大大提升了數據庫的吞吐能力。經過垂直分區后的數據庫架構圖如下:

          然而,盡管業務之間已經足夠獨立了,但是有些業務之間或多或少總會有點聯系,如用戶,基本上都會和每個業務相關聯,況且這種分區方式,也不能解決單張表數據量暴漲的問題,因此為何不試試水平sharding呢?

           

          3、MySQL水平分片(Sharding)

          這是一個非常好的思路,將用戶按一定規則(按id哈希)分組,并把該組用戶的數據存儲到一個數據庫分片中,即一個sharding,這樣隨著用戶數量的增加,只要簡單地配置一臺服務器即可,原理圖如下:

          如何來確定某個用戶所在的shard呢,可以建一張用戶和shard對應的數據表,每次請求先從這張表找用戶的shard id,再從對應shard中查詢相關數據,如下圖所示:

          但是,優酷是如何解決跨shard的查詢呢,這個是個難點,據介紹優酷是盡量不跨shard查詢,實在不行通過多維分片索引、分布式搜索引擎,下策是分布式數據庫查詢(這個非常麻煩而且耗性能)

           

          四、緩存策略

          貌似大的系統都對“緩存”情有獨鐘,從http緩存到memcached內存數據緩存,但優酷表示沒有用內存緩存,理由如下:

          1. 避免內存拷貝,避免內存鎖
          2. 如接到老大哥通知要把某個視頻撤下來,如果在緩存里是比較麻煩的

          而且Squid 的 write() 用戶進程空間有消耗,Lighttpd 1.5 的 AIO(異步I/O) 讀取文件到用戶內存導致效率也比較低下。

          但為何我們訪問優酷會如此流暢,與土豆相比優酷的視頻加載速度略勝一籌?這個要歸功于優酷建立的比較完善的內容分發網絡(CDN),它通過多種方式保證分布在全國各地的用戶進行就近訪問——用戶點擊視頻請求后,優酷網將根據用戶所處地區位置,將離用戶最近、服務狀況最好的視頻服務器地址傳送給用戶,從而保證用戶可以得到快速的視頻體驗。這就是CDN帶來的優勢,就近訪問,有關CDN的更多內容,請大家Google一下。

          好了,就總結這么多了,有興趣的同學接著補充,雖然很多資料圖片都來自網絡,但整理也不容易,歡迎轉載,轉載留個出處:青藤屋 原文鏈接

          posted @ 2011-11-02 11:23 馬航 閱讀(289) | 評論 (0)編輯 收藏

          windows系統使我們經常使用的操作系統怎么才能使用我們現在經常使用的操作系統不變的情況下繼續我們的SVN之旅,我們在綜合了好動種方法的同時感覺這些內容非常貼近我們SVN在Windows種的應用與配置.

          1.下載文件,

          下載最新版本subversion,我這里選擇svn-1.4.5-setup.exe

          下載 "Subversion Windows Service" 軟件包

          下載 TortoiseSVN shell integration utility

          2.安裝Subversion 服務器

          由于我下載的是setup.exe版本,安裝程序安裝后會自動設置系統變量.如果你下載的是zip版就需要手動設置系統變量.

          setup.exe版直接安裝就可以了.安裝到D:/Program Files/Subversion

          首先創建SVN儲存庫(repository)

          svnadmin create F:/svn/

          repository創建完畢后會在目錄下生成若干個文件和文件夾,dav目錄是提供給Apache與mod_dav_svn使用的目錄,讓它們存儲內部數據;db目錄就是所有版本控制的數據文件;hooks目錄放置hook腳本文件的目錄;locks用來放置Subversion文件庫鎖定數據的目錄,用來追蹤存取文件庫的客戶端;format文件是一個文本文件,里面只放了一個整數,表示當前文件庫配置的版本號;

          3.配置SVN服務器

          (這個位置就是在你建儲存庫的地方F:/svn)

          打開/conf/目錄,打開svnserve.conf找到一下兩句:

          # [general]

          # password-db = passwd

          # anon-access = none

          # auth-access = write

          去之每行開頭的#,其中第二行是指定身份驗證的文件名,即passwd文件.anon-access = none 是匿名用戶不能訪問,必須要有用戶名和密碼。(注意:問題就出在這,一定要注意格式去掉注釋后要頂格不能有空)

          同樣打開passwd文件,將

          # [users]

          # harry = harryssecret

          # sally = sallyssecret

                 格式為“用戶名 = 密碼”,如可插入一行:admin = admin888,即為系統添加一個用戶名為admin,密碼為admin888的用戶

          4.運行SVN服務器

          運行SVN服務

          在命令行執行

          svnserve --daemon --root F:/svn

          服務啟動,--daemon可簡寫為-d,--root可簡寫為-r,可以建立一個批處理文件并放在windows啟動組中便于開機就運行SVN服務(注意:這是臨時打開的服務,命令執行后不能關閉窗口)

          也可以制定subversion工作的端口:svnserve -d -r f:/svn --listen-port 9999

          用后臺服務的方式可以設置開機自動執行。

          D:/Program Files/Subversion/bin>sc create svnservice binpath= "C:/Program Files/Subversion/bin/svnserve.exe --service -r f:/svn  --listen-port 9999"

          就可以用net svnservice stop 或者start來啟動服務了 也可以在Sevices.msc來啟動了。

          5、用客戶端訪問

          格式:svn://服務器IP

           

          ---------------------------------------------------------------------------------------------------------

           

          基于svnserve的服務器,權限文件authz配置的常見問題及解答  
           最近在我用Subversion論壇(http://www.iUseSVN.com/bbs)經常有人提到這樣的問題: 
          為什么我的客戶端沒有寫權限? 
          為什么我的權限沒有起作用?

          總結他們的配置,發現 
          都是用svnserve作為服務器, 
          都在svnserve.conf中使用了authz-db選項

          原因可能如下:

          1,配置authz時,沒有注意svnserve啟動參數-r所指定的目錄。 
          這里有兩種情況: 
          A:-r直接指定到版本庫(稱之為單庫svnserve方式) 
          比如,有一個庫project1,位于D:/svn/project1 
          使用以下命令啟動svnserve

          [Copy to clipboard] [ - ]CODE: 
          svnserve -d -r D:/svn/project1 
          在這種情況下,一個svnserve只能為一個版本庫工作 
          authz文件如果配置成下面這樣就是錯的,

          [Copy to clipboard] [ - ]CODE: 
          [groups] 
          admin=user1 
          dev=user2 
          [project1:/] 
          @admin=rw 
          @doc=r 
          應該配置成

          [Copy to clipboard] [ - ]CODE: 
          [groups] 
          admin=user1 
          dev=user2 
          [/] 
          @admin=rw 
          @doc=r 
          因為[project1:/]表示庫project1的根目錄,而按上面的啟動參數,是沒有庫的概念的。 
          使用類似這樣的URL:svn://192.168.0.1/ 即可訪問project1

          B:-r指定到版本庫的上級目錄(稱之為多庫svnserve方式) 
          同樣,有一個庫project1,位于D:/svn/project1 
          如果使用以下命令啟動svnserve

          [Copy to clipboard] [ - ]CODE: 
          svnserve -d -r D:/svn 
          這種情況,一個svnserve可以為多個版本庫工作, 
          這時如果想限制指定庫的指定目錄,就應該指定具體的庫,像這樣

          [Copy to clipboard] [ - ]CODE: 
          [groups] 
          admin=user1 
          dev=user2 
          [project1:/] 
          @admin=rw 
          @doc=r 
          如果此時你還用[/],則表示所有庫的根目錄,同理,[/src]表示所有庫的根目錄下的src目錄 
          使用類似這樣的URL:svn://192.168.0.1/project1 即可訪問project1 
          這樣的URL:svn://192.168.0.1/project2 即可訪問project2

          2,對中文目錄進行權限控制時,沒有將權限文件authz改為utf-8格式。

          svn對于非英文文件名和目錄名使用utf-8格式編碼處理,要對中文目錄進行正確控制, 
          應該使用無BOM的utf-8格式,如何將默認的文件轉為utf-8, 
          我使用的是UltraEdit的菜單"ASCII to UTF-8 (Unicode Editing)"。在UltraEdit的配置中,可以設置有無BOM  

          posted @ 2011-10-12 17:26 馬航 閱讀(424) | 評論 (0)編輯 收藏

          SIP協議

           

          SIP協議過程概念及分析

           

          SIP入門開發之路(含SIP開發需要學習的資源及網址)

           

          SIP揭密(中文版)

           

          使用Java的SIP Servlet進行SIP開發

           

           

          Asterisk:

           

          Asterisk安裝及測試

           

          Asterisk十問十答

           

          Asterisk入門教程

           

          Asterisk介紹-Asterisk RealTime SIP

          asterisk配置文件列表及常用指令

           

          asterisk 官方文檔

           

          asterisk目錄及配置說明

           

          Asterisk功能整理

           

          Asterisk使用ODBC實現語音信箱

           

          使用Asterisk實現可視的語音交換

           

           

          OpenSIPS

           

          開源SIP服務器OpenSIPS應用介紹

           

          Opensips 安裝

           

          Opensips 配置文件

           

          Mediaproxy的安裝及其在OpenSIPS中的配置

           

          Opensips文檔之MediaProxy模塊

           

          使用OpenSIPS構建電話通信系統-8媒體服務整合

           

          使用OpenSIPS構建電話通信系統-4腳本及路由基礎

           

          Opensips文檔之TM模塊

           

          Opensips文檔之RR模塊

           

          Opensips文檔之TEXTOPS 模塊

           

          Opensips文檔之AVPOPS模塊

           

           

          NAT穿透(即SIP打洞)

           

          使用OpenSIPS構建電話通信系統-SIP穿透NAT

           

          NAT穿透問題探討

           

          完美的NAT穿透技術ICE介紹

           

          ICE-SIP穿透NAT問題的終極解決方案

           

          NAT穿透技術ICE基礎教程

          posted @ 2011-10-07 20:31 馬航 閱讀(454) | 評論 (0)編輯 收藏

               摘要: Android中有一控件是ExpandableListView,比ListView更高級,ExpandableListView的效果很實用,比如因為需要查看一堆文件的目錄結構或者開發像QQ好友那樣的界面,就應該使用Expandablelistview。 本文最終效果如下: 首先是Activity代碼,實際開發中數據(包括父item,子item及圖片,Expandablelistview...  閱讀全文

          posted @ 2011-10-06 09:37 馬航 閱讀(5471) | 評論 (0)編輯 收藏

          前言:做完了手機全能播放器的項目, 又要告別幾個月來并肩作戰,即將去北京發展的Manager zhu。準備把做過的3GP/FLV/AVI格式整理一遍, 算是對幾個月辛苦成果的總結, 也為后來者提供一些參考。

          1. 概述

          流行的文件格式背后都有大公司的支持。FLV得益于ADOBE公司推動的網絡視頻分享風潮,而AVI則是MICROSOFT首創的RIFF即視頻和音頻交織在一起同步播放。 3GP/MP4是APPLE提出并得到ISO標準支持作為NOKIA等手機的默認視頻格式。3GP是MP4格式在手機上的簡化版。MP4的codec組合一般是mpeg4 + AAC, 3GP則按版本演進分為3gpp r5(h.263/mpeg4 + AMR-NB/AMR WB), 3gpp r6(增加h.264視頻和aacPlus音頻支持)。

          有人會把MP4和MPEG4搞混, 前者是文件容器(container),后者是視頻編碼格式, 容器的作用是把壓縮編碼后的視頻和音頻數據盡可能緊湊的排布,就好像阿甘的巧克力盒子,你并不知道盒子里有什么, 但你可以按照既定的線索解開文件,取出你需要的數據。

          文件格式一般包括以下三要素:

          header: 標記文件類型,音視頻碼流的基本屬性信息
          index: 索引表,每個frame有對應的offset,size,timestamp.
          stream: 真正的音視頻流數據。
          任何文件格式都應該有以上3要素。 當然AVI視頻沒有索引也能播放,但不能拖放seek,需要自己重建索引。解析器(demuxer)根據frame_id找到其在文件中的offset和size,然后讀取出來解碼并播放。

          2. 文件格式分析

          下面來分析一下3GP/MP4文件格式。APPLE的格式有2個特點,1. 排布緊湊幾乎沒有冗余數據(AVI則有很多junk數據),2.音視頻碼流數據可隨意存放而不需按時間順序排布。

          3gp文件由一系列的box(atom)組成。每個box的結構都是4字節的size,4字節的type, 還有一些data數據。用mp4info查看3gp文件的數據排布如下圖:

          如上圖, ftyp是表示文件的版本信息, mdat存放文字,音視頻等數據。你可能要問,這些音視頻數據怎么找到呢? 是通過moov box里的子box trak,里面存放著音視頻的屬性描述以及每個sample的索引。

          3. 關于sample atoms

             video和audio的碼流屬性(如視頻width/height,codec id, 音頻采樣率聲道數等)存放在stsd box里; 下面著重介紹MP4高效壓縮的精華:stts,stss,stsc,stsz,stco五個box。對比AVI的索引表是每個sample都有對應的id,flag,offset,size,3GP的高效索引方式可以把AVI轉碼成同碼率的MP4后,文件size減小成原來的20-30%!

          1. stts atom(time to sample atoms,見quicktime format 文檔圖2-28 標準文檔點擊下載): 存儲了sample的時間信息。stts能讓很方便的根據timestamp找到對應的sample,或者獲取某個sample對應的timestamp. sttstable記錄著有相同duration的sample的數量count和時長dutation。

          2. stss atom(sync sample atom,見文檔圖2-31): 存儲了每個關鍵幀的sample id。 stss能讓你很方便的找到當前幀最近的關鍵幀。

          3. stsc atom(sample to chunk atom): sample存放在chunk里為了允許優化的數據讀取。比如音頻sample size都很小(amr-nb sample size為32字節), 每次讀取一個sample開銷太大, 可一次性讀所在chunk里一堆sample。

          4. stsz atom(sample size atom): stsz可以描述每個sample的size.

          5. stco atom(chunk offset atoms): stco描述了每個chunk在文件中的絕對偏移位置。該offset可以是32位的

          也可以是64位的,后者用來支持處理超大文件。

          4 .使用sample atoms來處理播放流程

          · 查找sample         

          1.確定時間,相對于媒體時間坐標系統

          2.檢查time-to-sample atom來確定給定時間的sample序號。

          3.檢查sample-to-chunk atom來發現對應該sample的chunk。

          4.從chunk offset atom中提取該trunk的偏移量。

          5.利用sample size atom找到sample在trunk內的偏移量和sample的大小。

          例如,如果要找第1秒的視頻數據,過程如下:

          1. 第1秒的視頻數據相對于此電影的時間為600

          2. 檢查time-to-sample atom,得出每個sample的duration是40,從而得出需要尋找第600/40 = 15 + 1 = 16個sample

          3. 檢查sample-to-chunk atom,得到該sample屬于第5個chunk的第一個sample,該chunk共有4個sample

          4. 檢查chunk offset atom找到第5個trunk的偏移量是20472

          5. 由于第16個sample是第5個trunk的第一個sample,所以不用檢查sample size atom,trunk的偏移量即是該sample的偏移量20472。如果是這個trunk的第二個sample,則從sample size atom中找到該trunk的前一個sample的大小,然后加上偏移量即可得到實際位置。

          6. 得到位置后,即可取出相應數據進行解碼,播放

          ·       查找關鍵幀      

          查找過程與查找sample的過程非常類似,只是需要利用sync sample atom來確定key frame的sample序號

          確定給定時間的sample序號 
          檢查sync sample atom來發現這個sample序號之后的key frame 
          檢查sample-to-chunk atom來發現對應該sample的chunk 
          從chunk offset atom中提取該trunk的偏移量 
          利用sample size atom找到sample在trunk內的偏移量和sample的大小


          5 .3GP/MP4相關資源

               quicktime file format specification: 最權威的格式文檔 點擊下載
               開源的3GP/MP4解析器: ffmpeg, GPAC, helix, google opencore等 

          posted @ 2011-10-03 10:54 馬航 閱讀(696) | 評論 (0)編輯 收藏

          Android開發又將帶來新一輪熱潮,很多開發者都投入到這個浪潮中去了,創造了許許多多相當優秀的應用。其中也有許許多多的開發者提供了應用開 源項目,貢獻出他們的智慧和創造力。學習開源代碼是掌握技術的一個最佳方式。下面推薦幾個應用開源項目,這些項目不僅提供了優秀的創意,也可以直接掌握 Android內核的接口使用:

          1、Android團隊提供的示例項目

          如果不是從學習Android SDK中提供的那些樣例代碼開始,可能沒有更好的方法來掌握在Android這個框架上開發。由Android的核心開發團隊提供了15個優秀的示例項目,包含了游戲、圖像處理、時間顯示、開始菜單快捷方式等。
          地址:http://code.google.com/p/apps-for-android/

          2、 Remote Droid

          RemoteDroid是一個Android應用,能夠讓用戶使用自己的無線網絡使用無線鍵盤、觸摸屏操作手機。這個項目為開發者提供了如網絡連接、觸摸屏手指運動等很好的樣例。
          地址:http://code.google.com/p/remotedroid/

          3、 TorProxy和Shadow

          TorProxy應用實現了Android手機無線電電傳通訊(TOR),和Shadow應用一起使用,可以使用手機匿名上網。從該項目源代碼中,可以掌握socket連接、管理cookie等方法。
          地址:http://www.cl.cam.ac.uk/research/dtg/code/svn/android-tor/

          4、 Android SMSPopup

          SMSPopup可以截獲短信內容顯示在一個泡泡形狀的窗口中。從這個項目中可以掌握到如何使用內置的短信SMS接口。
          地址:http://code.google.com/p/android-smspopup/

          5、 Standup Timer

          Standup Timer應用用于控制站立會議時間,類似秒表倒計時,可以提醒每個人的講話時間已到,從而保證每個與會者使用時間一樣。從該項目的代碼中,可以學會如何使用時間函數。另外,這個項目的代碼是采用視圖view、模型model嚴格分離的設計思路。
          地址:http://github.com/jwood/standup-timer

          6、 Foursquare

          是Foursquare.com的一個客戶端應用,該應用主要分為兩個模塊:API(com.joelapenna.foursquare)和界面前端 (com.joelapenna.foursquared)兩部分。從該項目代碼中,可以學會如何同步、多線程、HTTP連接等技術。
          地址:http://code.google.com/p/foursquared/

          7、 Pedometer

          Pedometer應用用于記錄你每天走路步數的。盡管記錄不一定精準,但是從這個項目中,可以學習幾個不同的技術:加速器交互、語音更新、后臺運行服務等。
          地址:http://code.google.com/p/pedometer/

          8、 OpenSudoku-android

          OpenSudoku是一個簡單的九宮格數獨游戲。從代碼中可以學習到如何在視圖中顯示表格數據,以及如何和一個網站交互等技術。
          地址:http://code.google.com/p/opensudoku-android/

          9、 ConnectBot

          ConnectBot是Android平臺的一個客戶端安全殼應用。從該項目代碼中,可以學習到很多Android安全方面的內容,這些是你在開發應用時經常需要考慮的安全問題。
          地址:http://code.google.com/p/connectbot/

          10、 WordPress的Android應用

          當然在最后不能不提WordPress的Android應用了,這是WordPress官方開發團隊提供的一個項目。從代碼中可以學習到XMLRPC調用(當然還有更多的優秀內容)。
          地址:http://android.svn.wordpress.org/trunk/

          posted @ 2011-10-03 09:47 馬航 閱讀(482) | 評論 (0)編輯 收藏

          導讀:對于Android開發者來說,成系列的技術文章對他們的技術成長幫助最大。如下是我們向您強烈推薦的主題為Android開發的第一個系列文章。

          文章皆來自CSDN網友maxleng的專欄,maxleng是名Android愛好者,長期從事嵌入式系統及手機軟件系統研究,自2010年4月起,在CSDN上先后發表28篇《Android核心分析》系列博文,收到網友們的極高評價。《Android核心分析》整理如下:

          1. 方法論探討之設計意圖

          2. 方法論探討之概念空間篇

          3. 手機之硬件形態

          4. 手機的軟件形態

          5. Android基本空間劃分

          6. IPC框架分析(Binder,Service,Service manager)

          7. Service詳解

          8. Android啟動過程詳解

          9. Zygote Service詳解

          10.Android GWES基本原理篇

          11.Android GWES消息系統篇

          12.Android核心分析之Android GEWS窗口管理基本架構篇

          13.Android GWES窗口管理詳解

          14.Android GWES輸入系統篇

          15.Android GWES輸入系統之輸入路徑詳解

          16.Android電話系統-概述篇

          17.Android電話系統之Rild服務詳解

          18.Android電話系統之GSMCallTracker

          19.Android電話系統之RIL-Java

          20.Android應用程序框架之無邊界設計意圖

          21.Android應用框架之AndroidApplication

          22.Android應用框架之Activity

          22.Andoird GDI之基本原理及其總體框架

          23.Android GDI之顯示緩沖管理

          24.Android GDI之共享緩沖區機制

          25.Android GDI之共享緩沖區機制

          26.Android GDI之SurfaceFlinger

          27.Android GDI之SurfaceFlinger之動態結構示意圖

          28.Android GDI之Surface&Canvas

          原文地址:http://mobile.csdn.net/a/20110209/291511.html

          posted @ 2011-09-23 15:34 馬航 閱讀(109) | 評論 (0)編輯 收藏

          新手學堂:嵌入式Linux操作系統學習規劃
          ARM+LINUX路線,主攻嵌入式Linux操作系統及其上應用軟件開發目標:
          (1) 掌握主流嵌入式微處理器的結構與原理(初步定為arm9)
          (2) 必須掌握一個嵌入式操作系統 (初步定為uclinux或linux,版本待定)
          (3) 必須熟悉嵌入式軟件開發流程并至少做一個嵌入式軟件項目。
          從事嵌入式軟件開發的好處是:
          (1)目前國內外這方面的人都很稀缺。這一領域入門門檻較高,所以非專業IT人員很難切入這一領域;另一方面,是因為這一領域較新,目前發展太快,大多數人無條件接觸。
          (2)與企業計算等應用軟件不同,嵌入式領域人才的工作強度通常低一些(但收入不低)。
          (3)哪天若想創業,搞自已的產品,嵌入式不像應用軟件那樣容易被盜版。硬件設計一般都是請其它公司給訂做(這叫“貼牌”:OEM),都是通用的硬件,我們只管設計軟件就變成自己的產品了。
          (4)興趣所在,這是最主要的。
          從事嵌入式軟件開發的缺點是:
          (1)入門起點較高,所用到的技術往往都有一定難度,若軟硬件基礎不好,特別是操作系統級軟件功底不深,則可能不適于此行。
          (2)這方面的企業數量要遠少于企業計算類企業。
          (3)有少數公司經常要碩士以上的人搞嵌入式,主要是基于嵌入式的難度。但大多數公司也并無此要求,只要有經驗即可。
          (4)平臺依托強,換平臺比較辛苦。
          興趣的由來:
          1、成功觀念不同,不虛度此生,就是我的成功。
          2、喜歡思考,挑戰邏輯思維。
          3、喜歡C
          C是一種能發揮思維極限的語言。關于C的精神的一些方面可以被概述成短句如下:
          相信程序員。
          不要阻止程序員做那些需要去做的。
          保持語言短小精干。
          一種方法做一個操作。
          使得它運行的夠快,盡管它并不能保證將是可移植的。
          4、喜歡底層開發,討厭vb類開發工具(并不是說vb不好)。
          5、發展前景好,適合創業,不想自己要死了的時候還是一個工程師。
          方法步驟:
          1、基礎知識:
          目的:能看懂硬件工作原理,但重點在嵌入式軟件,特別是操作系統級軟件,那將是我的優勢。
          科目:數字電路、計算機組成原理、嵌入式微處理器結構。
          匯編語言、C/C++、編譯原理、離散數學。
          數據結構和算法、操作系統、軟件工程、網絡、數據庫。
          方法:雖科目眾多,但都是較簡單的基礎,且大部分已掌握。不一定全學,可根據需要選修。
          主攻書籍:the c++ programming language(一直沒時間讀)、數據結構-C2。

          2、學習linux:
          目的:深入掌握linux系統。
          方法:使用linux—〉linxu系統編程開發—〉驅動開發和分析linux內核。先看深,那主講原理。看幾遍后,看情景分析,對照深看,兩本交叉,深是綱,情是目。剖析則是0.11版,適合學習。最后深入代碼。
          主攻書籍:linux內核完全剖析、unix環境高級編程、深入理解linux內核、情景分析和源代。
          3、學習嵌入式linux:
          目的:掌握嵌入式處理器其及系統。
          方法:(1)嵌入式微處理器結構與應用:直接arm原理及匯編即可,不要重復x86。
          (2)嵌入式操作系統類:ucOS/II簡單,開源,可供入門。而后深入研究uClinux。
          (3)必須有塊開發板(arm9以上),有條件可參加培訓(進步快,能認識些朋友)。
          主攻書籍:毛德操的《嵌入式系統》及其他arm9手冊與arm匯編指令等。

          4、深入學習:
          A、數字圖像壓縮技術:主要是應掌握MPEG、mp3等編解碼算法和技術。
          B、通信協議及編程技術:TCP/IP協議、802.11,Bluetooth,GPRS、GSM、CDMA等。
          C、網絡與信息安全技術:如加密技術,數字證書CA等。
          D、DSP技術:Digital Signal Process,DSP處理器通過硬件實現數字信號處理算法。
          說明:太多細節未說明,可根據實際情況調整。重點在于1、3,不必完全按照順序作。對于學習c++,理由是c++不只是一種語言,一種工具,她還是一種藝 術,一種文化,一種哲學理念、但不是拿來炫耀得東西。對于linux內核,學習編程,讀一些優秀代碼也是有必要的。
          注意: 要學會舉一反多,有強大的基礎,很多東西簡單看看就能會。想成為合格的程序員,前提是必須熟練至少一種編程語言,并具有良好的邏輯思維。一定要理論結合實踐。
          不要一味鉆研技術,雖然擠出時間是很難做到的,但還是要留點余地去完善其他的愛好,比如宇宙,素描、機械、管理,心理學、游戲、科幻電影。還有一些不愿意做但必須要做的!
          技術是通過編程編程在編程編出來的。永遠不要夢想一步登天,不要做浮躁的人,不要覺得路途漫上。而是要編程編程在編程,完了在編程,在編程!等機會來了在創業(不要相信有奇跡發生,盲目創業很難成功,即便成功了發展空間也不一定很大)。
          嵌入式書籍推薦

          Linux基礎
          1、《Linux與Unix Shell 編程指南》
          C語言基礎
          1、《C Primer Plus,5th Edition》【美】Stephen Prata著
          2、《The C Programming Language, 2nd Edition》【美】Brian W. Kernighan David M. Rithie(K & R)著
          3、《Advanced Programming in the UNIX Environment,2nd Edition》(APUE)
          4、《嵌入式Linux應用程序開發詳解》
          Linux內核
          1、《深入理解Linux內核》(第三版)
          2、《Linux內核源代碼情景分析》毛德操 胡希明著
          研發方向
          1、《UNIX Network Programming》(UNP)
          2、《TCP/IP詳解》
          3、《Linux內核編程》
          4、《Linux設備驅動開發》(LDD)

          5、《Linux高級程序設計》 楊宗德著
          硬件基礎
          1、《ARM體系結構與編程》杜春雷著
          2、S3C2410 Datasheet
          英語基礎
          1、《計算機與通信專業英語》
          系統教程
          1、《嵌入式系統――體系結構、編程與設計》
          2、《嵌入式系統――采用公開源代碼和StrongARM/Xscale處理器》毛德操 胡希明著
          3、《Building Embedded Linux Systems》

          4、《嵌入式ARM系統原理與實例開發》 楊宗德著
          理論基礎
          1、《算法導論》
          2、《數據結構(C語言版)》
          3、《計算機組織與體系結構?性能分析》
          4、《深入理解計算機系統》【美】Randal E. Bryant David O’Hallaron著
          5、《操作系統:精髓與設計原理》
          6、《編譯原理》
          7、《數據通信與計算機網絡》
          8、《數據壓縮原理與應用》

          C語言書籍推薦

          1. The C programming language 《C程序設計語言》
          2. Pointers on C 《C和指針》
          3. C traps and pitfalls 《C陷阱與缺陷》
          4. Expert C Lanuage 《專家C編程》
          5. Writing Clean Code —–Microsoft Techiniques for Developing Bug-free C Programs
          《編程精粹–Microsoft 編寫優質無錯C程序秘訣》
          6. Programming Embedded Systems in C and C++ 《嵌入式系統編程》
          7.《C語言嵌入式系統編程修煉》
          8.《高質量C++/C編程指南》林銳

          盡可能多的編碼,要學好C,不能只注重C本身。算法,架構方式等都很重要。

          posted @ 2011-09-22 14:25 馬航 閱讀(107) | 評論 (0)編輯 收藏

          網上搜了N多解決方法,但是很多將log級別的,用法的,更多的是如何在logcat中設置filter進行log的過濾與查看,但是我遇到的問題是,模擬器怎么著都OK,但真機、手機進行開發調試的時候卻看不到log信息,這是很惱人的事情(畢竟模擬器跑起來太慢了)。

          剛開始沒有查到好的方法,就用try catch把exception打到一個alertdialog中,但是這樣只能看個大概,繞這個圈子沒用,最后還是在eoe的論壇上看到了解決辦法,恐怕原因是rom本身沒有打開log的開關

          問題表現:連接手機與電腦后,驅動安裝正確,USB調試模式打開,在DDMS中可以看到device及其進程的信息,但是logcat中就是沒有信息輸出
          問題原因:一些rom默認關閉logcat
          問題說明:ddms中設備名字顯示為問號不影響,即adb get-serialno顯示為問號不影響.
          解決方法:
          1.需要root權限(部分rom不需要)
          2.打開logcat,并設置level,執行命令如下(android 升級之后 adb 在 platform-tools中,不在tools中)
          adb shell
          echo 1 > /sys/kernel/logger/log_main/enable
          說明:將1寫入日志開關文件,1為開,0為關
          echo 2 >/sys/kernel/logger/log_main/priority
          說明:將代表level的2寫入優先級文件
          3.重啟adb,如果使用eclipse,先關閉eclipse,再重啟adb,再啟動eclipse
          adb kill-server
          adb start-server
          4.此時logcat應該可以工作了,如果仍舊不工作,則更新adb
          android update adb
          5.重復第三步,此時logcat應該可以工作了,如果仍舊不工作,找到個人主目錄下的android目錄,如C:\Documents and Settings\Administrator\.android
          找到這個目錄下的adb_usb.ini文件,其內容默認只有三行,全為注釋,在后面添加一行,內容為0x12d1
          6.重復第三步,此時logcat應該可以工作了

          轉自:http://www.gobbin.cn/2011/02/16/android-phone-logcat/

          posted @ 2011-09-06 16:10 馬航 閱讀(11242) | 評論 (0)編輯 收藏

          主站蜘蛛池模板: 安仁县| 武胜县| 富川| 岑溪市| 桓台县| 清河县| 双桥区| 广德县| 石河子市| 吴川市| 平湖市| 鲁山县| 临泽县| 塔城市| 苍梧县| 德保县| 宕昌县| 来安县| 鄂伦春自治旗| 湘西| 刚察县| 商洛市| 东安县| 安丘市| 砀山县| 论坛| 玉溪市| 建始县| 双城市| 民丰县| 漯河市| 托克托县| 仁布县| 土默特左旗| 曲阳县| 文山县| 平泉县| 博爱县| 巩留县| 庆安县| 新建县|