從c/c++語言轉(zhuǎn)向
java開發(fā),學(xué)習(xí)java語言list遍歷的三種方法,順便
測(cè)試各種遍歷方法的性能,測(cè)試方法為在ArrayList中插入1千萬條記錄,然后遍歷ArrayList,發(fā)現(xiàn)了一個(gè)奇怪的現(xiàn)象,測(cè)試代碼例如以下:
package com.hisense.tiger.list; import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class ListTest { public static void main(String[] args) { List<String> list = new ArrayList<String>(); long t1,t2; for(int j = 0; j < 10000000; j++) { list.add("aaaaaa" + j); } System.out.println("List first visit method:"); t1=System.currentTimeMillis(); for(String tmp:list) { //System.out.println(tmp); } t2=System.currentTimeMillis(); System.out.println("Run Time:" + (t2 -t1) + "(ms)"); System.out.println("List second visit method:"); t1=System.currentTimeMillis(); for(int i = 0; i < list.size(); i++) { list.get(i); //System.out.println(list.get(i)); } t2=System.currentTimeMillis(); System.out.println("Run Time:" + (t2 -t1) + "(ms)"); System.out.println("List Third visit method:"); Iterator<String> iter = list.iterator(); t1=System.currentTimeMillis(); while(iter.hasNext()) { iter.next(); //System.out.println(iter.next()); } t2=System.currentTimeMillis(); System.out.println("Run Time:" + (t2 -t1) + "(ms)"); System.out.println("Finished!!!!!!!!"); } } |
測(cè)試結(jié)果例如以下:
List first visit method:
Run Time:170(ms)
List second visit method:
Run Time:10(ms)
List Third visit method:
Run Time:34(ms)
Finished!!!!!!!!
測(cè)試的結(jié)論非常奇怪,第一種方法是java語言支持的新語法,代碼最簡(jiǎn)潔,可是在三種方法中,性能確是最差的,取size進(jìn)行遍歷性能是最高的,求牛人解釋?
English » | | | | | | | | |
Text-to-speech function is limited to 100 characters
1.背景
對(duì)于一般性的地圖顯示需求,我們只需要知道地圖的一個(gè)固定URL,然后知道要顯示的范圍和要顯示的級(jí)別以及每個(gè)級(jí)別的scale等即可。
但是如果我們遇到下面幾種情況時(shí),又該如何。
(1)需要顯示的圖層的不同級(jí)別來自于不同的服務(wù)器(URL不同):如前幾個(gè)級(jí)別由一個(gè)固定URL提供,后幾個(gè)級(jí)別由另外一個(gè)URL提供。
(2)需要同時(shí)疊加幾張圖層:如需要疊加地形圖和注記圖,且圖層的顯示有層級(jí)之分。
(3)需要同時(shí)疊加幾張圖層,并且每個(gè)圖層初始顯示級(jí)別不一樣。
(4)需要同時(shí)疊加幾張圖層,圖層的URL的請(qǐng)求方式均有不同:如其中一個(gè)圖層由AGS提供,一個(gè)圖層是天地圖服務(wù)提供,還有一個(gè)圖層是當(dāng)?shù)爻枪芫痔峁詈筮€有一個(gè)圖層是由本地未發(fā)布的緩存瓦片提供。
諸如類似于以上的地圖顯示需求還有很多,如果我們單純的對(duì)每一種情況進(jìn)行一個(gè)代碼上的分支當(dāng)然也是能解決的。但是這并不是最好的一種解決方法,每次新的需求提出時(shí),都需要對(duì)代碼修改,這不符合設(shè)計(jì)模式中的開放封閉原則。雖然我們可以用簡(jiǎn)單工廠等模式來努力改善這種情況,不過如果有更好的方式,不需要修改任何代碼,不需要用設(shè)計(jì)模式,就能解決以上的問題是否更好?
下面我將給出一種通過
數(shù)據(jù)庫(kù)配置來實(shí)現(xiàn)上面所有問題的解決方案。此方案在多個(gè)項(xiàng)目中已經(jīng)開始使用。
2.配置(表)的設(shè)計(jì)
2.1原理
首先我們必須對(duì)以上多種地圖顯示的需求進(jìn)行一個(gè)分析,提出他們的共同點(diǎn)。
(1)對(duì)圖層開始顯示的級(jí)別有需求(startLevel)。
(2)多張圖層疊加,并且圖層疊加有從上自下的順序(layerDisplayOrder)。
(3)圖層可能的URL不同(ServiceURL)
(4)每個(gè)圖層的URL格式可以不一樣,比如URL可能天地圖的WMTS格式,可能是AGS發(fā)布的請(qǐng)求方式(level\row\col),也有可能是Geoserver發(fā)布的WMS格式。并且有的服務(wù)提供商還需要token字段來判斷是否有權(quán)限得到服務(wù),或者不同的服務(wù)商提供的WMTS格式中對(duì)col和row以及l(fā)evel的表述字段名稱不一樣(通過這個(gè)分析,可以提煉出Xfield、Yfield、LevelFieldName、Token字段來對(duì)不同的需求進(jìn)行配置)。
(5)所有的圖層,如果要疊加,需要用同一個(gè)空間參考,同一個(gè)瓦片大小,同一個(gè)地圖起始原點(diǎn),以及同一套地圖比例尺。
(6)變化的只是URL,其核心瓦片行列號(hào)和地圖級(jí)別是每種瓦片請(qǐng)求URL均需要的。
2.2設(shè)計(jì)
2.2.1圖層列表(tcMaplayerList)的設(shè)計(jì)
首先我給出圖層列表設(shè)計(jì)的截圖:
(1)每一個(gè)圖層均有一個(gè)圖層名
(2)每一個(gè)圖層均有自己的圖層類型,比如AGS類型的、WMTS類型的等。這是為了程序中對(duì)不同的類型的URL進(jìn)行解析。
(3)每一個(gè)圖層有其自己的顯示順序,為了正確的疊加圖層之用。
(4)每一個(gè)圖層也有自己開始顯示的級(jí)別。如有的圖層想第一級(jí)別開始顯示,有的圖層希望地圖放大到第二級(jí)別時(shí)才開始顯示。
2.2.2圖層詳細(xì)內(nèi)容列表(tcgismapservicedetail)的設(shè)計(jì)
同樣,這里先給出表的截圖:
(1)ItemID為每個(gè)記錄的主碼。
(2)layerName與tcMaplayerList中的圖層名是對(duì)應(yīng)的。
(3)圖層級(jí)別表示的是該圖層在此級(jí)別時(shí)的信息。
(4)圖層在該級(jí)別的URL有一個(gè)固定的部分,比如WMTS請(qǐng)求中,變化的只是行列號(hào),而前面的部分均是不定的。
(5)Token、XFieldName、YFieldName、LevelFieldName均是為擴(kuò)展之用,當(dāng)URL需要給行列號(hào)以及級(jí)別一個(gè)固定的名稱時(shí)等,則配置。否則不用。
3.工作流程
3.1流程圖
3.2流程詳解
3.2.1得到需要顯示的圖層列表
在顯示地圖之前,需要先向后臺(tái)發(fā)出請(qǐng)求,此請(qǐng)求的參數(shù)主要是layerType,后臺(tái)根據(jù)layerType將tcMapLayerList表中符合需求的內(nèi)容讀出返回。
3.2.2 解析當(dāng)前地圖級(jí)別下的各個(gè)圖層信息,并順序顯示
在解析了需要顯示的圖層列表后,每個(gè)圖層均會(huì)給后臺(tái)發(fā)出自己的信息,信息中包括了此時(shí)地圖的級(jí)別,以及需要得到的瓦片行列號(hào)和自己的圖層名。
但是此時(shí)的地圖級(jí)別并不是圖層發(fā)給后臺(tái)的級(jí)別參數(shù),真是的地圖級(jí)別是:
factLayerLevel=layerLevel+startLayerLevel。
根據(jù)factlayerLevel和layerName,在tcgismapservicedetail中找到對(duì)應(yīng)的信息,如果有信息,則表示該圖層在此真實(shí)級(jí)別下是需要顯示的,然后根據(jù)該圖層的layerType將此時(shí)的URL拼接出來,下載瓦片然后返回此瓦片。
如果沒有查到數(shù)據(jù)則不顯示此地圖級(jí)別下的該圖層。
4.成果展示
4.1測(cè)繪局地圖+本地瓦片
4.2 天地圖地形圖層+天地圖注記圖層+Geoserver發(fā)布的行政區(qū)劃圖層
4.3測(cè)繪局提供的管線WMTS圖層+本地AGS發(fā)布的地形圖層
5.總結(jié)
通過此配置基本可以實(shí)現(xiàn)項(xiàng)目中遇到的絕大部分地圖需求。改進(jìn)后,雖然不再需要對(duì)各種需求進(jìn)行大規(guī)模的代碼編寫,但是針對(duì)不同的瓦片類型的URL獲取依然是要走分支的,這里可以通過策略模式來讓代碼更加規(guī)范。
斷了一個(gè)多月沒寫博,WebGIS的原理系列會(huì)繼續(xù)寫下去的,希望大家持續(xù)關(guān)注。
English » | | | | | | | | |
Text-to-speech function is limited to 100 characters
很久以前就看到了Burp suite這個(gè)工具了,當(dāng)時(shí)感覺好NB,但全英文的用起來很是蛋疼,網(wǎng)上也沒找到什么教程,就把這事給忘了。今天準(zhǔn)備開始好好
學(xué)習(xí)這個(gè)滲透神器,也正好給大家分享下。(注:內(nèi)容大部分是
百度的,我只是分享下自已的學(xué)習(xí)過程)
Burp Suite 是用于攻擊
web 應(yīng)用程序的集成平臺(tái)。它包含了許多工具,并為這些工具設(shè)計(jì)了許多接口,以促進(jìn)加快攻擊應(yīng)用程序的過程。所有的工具都共享一個(gè)能處理并顯示HTTP 消息,持久性,認(rèn)證,代理,日志,警報(bào)的一個(gè)強(qiáng)大的可擴(kuò)展的框架。
Burp Suite 能高效率地與單個(gè)工具一起工作,例如: 一個(gè)中心站點(diǎn)地圖是用于匯總收集到的目標(biāo)應(yīng)用程序信息,并通過確定的范圍來指導(dǎo)單個(gè)程序工作。
在一個(gè)工具處理HTTP 請(qǐng)求和響應(yīng)時(shí),它可以選擇調(diào)用其他任意的Burp工具。例如:
代理記錄的請(qǐng)求可被Intruder 用來構(gòu)造一個(gè)自定義的自動(dòng)攻擊的準(zhǔn)則,也可被Repeater 用來手動(dòng)攻擊,也可被Scanner 用來分析漏洞,或者被Spider(網(wǎng)絡(luò)爬蟲)用來自動(dòng)搜索內(nèi)容。應(yīng)用程序可以是“被動(dòng)地”運(yùn)行,而不是產(chǎn)生大量的自動(dòng)請(qǐng)求。Burp Proxy 把所有通過的請(qǐng)求和響應(yīng)解析為連接和形式,同時(shí)站點(diǎn)地圖也相應(yīng)地更新。由于完全的控制了每一個(gè)請(qǐng)求,你就可以以一種非入侵的方式來探測(cè)敏感的應(yīng)用程序。
當(dāng)你瀏覽網(wǎng)頁(這取決于定義的目標(biāo)范圍)時(shí),通過自動(dòng)掃描經(jīng)過代理的請(qǐng)求就能發(fā)現(xiàn)安全漏洞。
IburpExtender 是用來擴(kuò)展Burp Suite 和單個(gè)工具的功能。一個(gè)工具處理的數(shù)據(jù)結(jié)果,可以被其他工具隨意的使用,并產(chǎn)生相應(yīng)的結(jié)果。
BurpSuite工具箱
Proxy——是一個(gè)攔截HTTP/S的代理服務(wù)器,作為一個(gè)在瀏覽器和目標(biāo)應(yīng)用程序之間的中間人,允許你攔截,查看,修改在兩個(gè)方向上的原始數(shù)據(jù)流。
Spider——是一個(gè)應(yīng)用智能感應(yīng)的網(wǎng)絡(luò)爬蟲,它能完整的枚舉應(yīng)用程序的內(nèi)容和功能。
Scanner[僅限專業(yè)版]——是一個(gè)高級(jí)的工具,執(zhí)行后,它能自動(dòng)地發(fā)現(xiàn)web 應(yīng)用程序的安全漏洞。
Intruder——是一個(gè)定制的高度可配置的工具,對(duì)web應(yīng)用程序進(jìn)行自動(dòng)化攻擊,如:枚舉標(biāo)識(shí)符,收集有用的數(shù)據(jù),以及使用fuzzing 技術(shù)探測(cè)常規(guī)漏洞。
Repeater——是一個(gè)靠手動(dòng)操作來補(bǔ)發(fā)單獨(dú)的HTTP 請(qǐng)求,并分析應(yīng)用程序響應(yīng)的工具。
Sequencer——是一個(gè)用來分析那些不可預(yù)知的應(yīng)用程序會(huì)話令牌和重要數(shù)據(jù)項(xiàng)的隨機(jī)性的工具。
Decoder——是一個(gè)進(jìn)行手動(dòng)執(zhí)行或?qū)?yīng)用程序數(shù)據(jù)者智能解碼編碼的工具。
Comparer——是一個(gè)實(shí)用的工具,通常是通過一些相關(guān)的請(qǐng)求和響應(yīng)得到兩項(xiàng)數(shù)據(jù)的一個(gè)可視化的“差異”。
BurpSuite的使用
當(dāng)Burp Suite 運(yùn)行后,Burp Proxy 開起默認(rèn)的8080 端口作為本地代理接口。通過置一個(gè)web 瀏覽器使用其代理服務(wù)器,所有的網(wǎng)站流量可以被攔截,查看和修改。默認(rèn)情況下,對(duì)非媒體資源的請(qǐng)求將被攔截并顯示(可以通過Burp Proxy 選項(xiàng)里的options 選項(xiàng)修改默認(rèn)值)。對(duì)所有通過Burp Proxy 網(wǎng)站流量使用預(yù)設(shè)的方案進(jìn)行分析,然后納入到目標(biāo)站點(diǎn)地圖中,來勾勒出一張包含訪問的應(yīng)用程序的內(nèi)容和功能的畫面。在Burp Suite 專業(yè)版中,默認(rèn)情況下,Burp Scanner是被動(dòng)地分析所有的請(qǐng)求來確定一系列的安全漏洞。
在你開始認(rèn)真的工作之前,你最好為指定工作范圍。最簡(jiǎn)單的方法就是瀏覽訪問目標(biāo)應(yīng)用程序,然后找到相關(guān)主機(jī)或目錄的站點(diǎn)地圖,并使用上下菜單添加URL 路徑范圍。通過配置的這個(gè)中心范圍,能以任意方式控制單個(gè)Burp 工具的運(yùn)行。
當(dāng)你瀏覽目標(biāo)應(yīng)用程序時(shí),你可以手動(dòng)編輯代理截獲的請(qǐng)求和響應(yīng),或者把攔截完全關(guān)閉。在攔截關(guān)閉后,每一個(gè)請(qǐng)求,響應(yīng)和內(nèi)容的歷史記錄仍能再站點(diǎn)地圖中積累下來。
和修改代理內(nèi)截獲的消息一樣,你可以把這些消息發(fā)送到其他Burp 工具執(zhí)行一些操作:
你可以把請(qǐng)求發(fā)送到Repeater,手動(dòng)微調(diào)這些對(duì)應(yīng)用程序的攻擊,并重新發(fā)送多次的單獨(dú)請(qǐng)求。
[專業(yè)版]你可以把請(qǐng)求發(fā)送到Scanner,執(zhí)行主動(dòng)或被動(dòng)的漏洞掃描。
你可以把請(qǐng)求發(fā)送到Intruer,加載一個(gè)自定義的自動(dòng)攻擊方案,進(jìn)行確定一些常規(guī)漏洞。
如果你看到一個(gè)響應(yīng),包含不可預(yù)知內(nèi)容的會(huì)話令牌或其他標(biāo)識(shí)符,你可以把它發(fā)送到Sequencer 來
測(cè)試它的隨機(jī)性。
當(dāng)請(qǐng)求或響應(yīng)中包含不透明數(shù)據(jù)時(shí),可以把它發(fā)送到Decoder 進(jìn)行智能解碼和識(shí)別一些隱藏的信息。
[專業(yè)版]你可使用一些engagement 工具使你的工作更快更有效。
你在代理歷史記錄的項(xiàng)目,單個(gè)主機(jī),站點(diǎn)地圖里目錄和文件,或者請(qǐng)求響應(yīng)上顯示可以使用工具的任意地方上執(zhí)行任意以上的操作。
可以通過一個(gè)中央日志記錄的功能,來記錄所單個(gè)工具或整個(gè)套件發(fā)出的請(qǐng)求和響應(yīng)。
這些工具可以運(yùn)行在一個(gè)單一的選項(xiàng)卡窗口或者一個(gè)被分離的單個(gè)窗口。所有的工具和套件的配置信息是可選為通過程序持久性的加載。在Burp Suite 專業(yè)版中,你可以保存整個(gè)組件工具的設(shè)置狀態(tài),在下次加載過來恢復(fù)你的工具。
burpsuite專業(yè)版的個(gè)人感受
不知不覺使用burpsuite也有點(diǎn)年頭了。它在我日常進(jìn)行安全評(píng)估,它已經(jīng)變得日益重要。
現(xiàn)在已經(jīng)變成我在日常滲透測(cè)試中不可缺少的工具之一。burpsuite官方現(xiàn)在已經(jīng)更新到1.5,與之前的一點(diǎn)1.4相比。界面做了比較大的變化。而且還增加了自定義快捷鍵功能。burpsuite1.5缺點(diǎn)是對(duì)中文字符一如既往的亂碼。burpsuite入門的難點(diǎn)是:入門很難,參數(shù)復(fù)雜,但是一旦掌握它的使用方法,在日常工作中肯定會(huì)如虎添翼。
網(wǎng)上有破解版的下載,請(qǐng)自行百度。
一 快速入門(Burpsuite的安裝使用與改包上傳)
BlAck.Eagle
Burp suite 是一個(gè)
安全測(cè)試框架,它整合了很多的安全工具,對(duì)于滲透的朋友來說,是不可多得的一款囊中工具包,今天筆者帶領(lǐng)大家來解讀如何通過該工具迅速處理“截?cái)嗌蟼?#8221;的漏洞。如果對(duì)該漏洞還不熟悉,就該讀下以前的黑客X檔案補(bǔ)習(xí)下了。
由于該工具是通過
Java寫的,所以需要安裝 JDK,關(guān)于 JDK 的安裝,筆者簡(jiǎn)單介紹 下。基本是傻瓜化安裝,安裝完成后需要簡(jiǎn)單配置下環(huán)境變量,右鍵 ”我的電腦”->”屬 性”->”高級(jí)”->”環(huán)境變量”,在系統(tǒng)變量中查找 Path,然后點(diǎn)擊編輯,把 JDK 的 bin 目 錄寫在 path 的最后即可。如圖 1
圖 1
通過 CMD 執(zhí)行下 javac 看是否成功安裝。安裝配置成功則會(huì)顯示下圖信息。如圖 2
圖 2 這里的測(cè)試網(wǎng)址是筆者幫朋友測(cè)試某站點(diǎn)時(shí)獲取的,登陸后臺(tái)后可以發(fā)表新聞,但是只能上 傳圖片。然后發(fā)現(xiàn)新聞的圖片目錄在 upload/newsimg 下。如圖 3
圖 3
后臺(tái)有個(gè)” 網(wǎng)站資料設(shè)置”的功能,可以自行定義新聞圖片的路徑,但是當(dāng)嘗試把新聞圖片
路徑改為”upload/newsimg.asp/”時(shí),上傳圖片竟然上傳失敗了,所以這種方法失效。 如圖 4、
圖 4
接下來我們嘗試上傳截?cái)嗦┒矗赡艽蠹医?jīng)常用的是通過 WSockExpert 抓包,修改后通過 nc 來提交獲取 shell,但是大家會(huì)發(fā)現(xiàn)那樣有點(diǎn)繁瑣,我們看看今天的方法是多么高效: 首先允許 burpsuite.jar,然后點(diǎn)擊”proxy” 標(biāo)簽,會(huì)發(fā)現(xiàn) burp suite 默認(rèn)的代理監(jiān)聽端 口為 8080,如果怕跟自己電腦上的某個(gè)端口沖突的話,可以點(diǎn)擊”edit”進(jìn)行編輯。筆者 使用默認(rèn)端口。如圖 5
圖 5
然后打開本地瀏覽器的代理設(shè)置的地方,IE 一般為”工具”->”Internet 選項(xiàng)” –>”連 接”->”局域網(wǎng)設(shè)置”,其他瀏覽器大致相同。如圖 6
圖 6
設(shè)置代理之后,我們到后臺(tái)的某個(gè)上傳新聞圖片的地方上傳一個(gè)圖片木馬,我這里的圖片木 馬為asp 一句話。如圖 7
圖 7
點(diǎn)擊上傳之后,我們到 proxy 的”history”選項(xiàng),會(huì)發(fā)現(xiàn)該網(wǎng)站的某個(gè) POST 提交請(qǐng)求, 我們選中該鏈接后,右鍵選擇”send to repeater”,如圖 8
圖 8
我們會(huì)發(fā)現(xiàn)剛才提交的請(qǐng)求的數(shù)據(jù)包,那么我們看一下,有一項(xiàng)是上傳路徑的地方,我們以
前 進(jìn) 行 截 斷 上 傳 的 時(shí) 候 經(jīng) 常 修 改 這 個(gè) 地 方 , 這 次 也 不 例 外 , 我 們 把 上 傳 路 徑 改 為”upload/shell.asp ”后面有一個(gè)空格,如圖 9
English » | | | | | | | | |
Text-to-speech function is limited to 100 characters
半夜起來看世界杯,沒啥激情,但是又怕錯(cuò)誤意大利和英格蘭的比賽,就看了rhel7
相關(guān)新功能的介紹。
安裝還算順利,安裝的界面比以前簡(jiǎn)潔的多,很清爽,分類很是明確。
有些奇怪的是,我安裝的時(shí)候,怕有些基礎(chǔ)的包沒有裝上去,所以選定了mini和Web的類型,結(jié)果還是有些基礎(chǔ)的包沒有安裝,比如 ifconfig 。
虛擬機(jī)的網(wǎng)卡,被識(shí)別為ens,有意思。
yum groupinstall Base
這樣的話,就可以把一些基礎(chǔ)的包打上。可以正常的時(shí)候ifconfig lsof 。
這里需要說明的是,redhat7的
測(cè)試的repo源貌似不能用,我跟著地址看了下。壓根就沒有,我想應(yīng)該還是測(cè)試版的原因吧。 直接mount /dev/cdrom /mnt用的。
[rhel-iso]
name=Red Hat Enterprise
Linux 7
baseurl=file:///mnt/
enabled=1
系統(tǒng)的分區(qū)默認(rèn)是xfs格式,當(dāng)然你還是可以用ext3,ext4的
[root@localhost ~]# df -T
文件系統(tǒng) 類型 1K-blocks 已用 可用 已用% 掛載點(diǎn)
/dev/mapper/rhel-root xfs 39262208 3591304 35670904 10% /
devtmpfs devtmpfs 500772 0 500772 0% /dev
tmpfs tmpfs 507508 0 507508 0% /dev/shm
tmpfs tmpfs 507508 2604 504904 1% /run
tmpfs tmpfs 507508 0 507508 0% /sys/fs/cgroup
/dev/sda1 xfs 494940 95444 399496 20% /boot
發(fā)現(xiàn)rhel7的開發(fā)軟件版本不低。
python 是2.7.5的了,和ubuntu一樣。 java默認(rèn)也給你裝上了。perl在centos6應(yīng)該是5.10的 ,現(xiàn)在更新到了5.16.3 。 至于為什么更新到perl6,估計(jì)和python3一樣吧。
[root@localhost ~]#
[root@localhost ~]#
[root@localhost ~]# python -V
Python 2.7.5
[root@localhost ~]#
java -version
java version "1.7.0_45"
OpenJDK Runtime Environment (rhel-2.4.3.4.el7-x86_64 u45-b15)
OpenJDK 64-Bit Server VM (build 24.45-b08, mixed mode)
[root@localhost ~]#
[root@localhost ~]#
[root@localhost ~]# perl -v
This is perl 5, version 16, subversion 3 (v5.16.3) built for x86_64-linux-thread-multi
(with 24 registered patches, see perl -V for more detail)
想安裝pip但是iso沒有python-pip這個(gè)包。rhel7的官方源又打不開,郁悶。本來打算用epel6試試,用不了,到epel官網(wǎng)一瞅。epel居然已經(jīng)有對(duì)于rhel7的源了。

簡(jiǎn)單測(cè)試下rhel7的openlmi,什么是openlmi,我看了下一些文檔,他是一個(gè)類似func、但又不屬于puppet這類的集群接口工具。
安裝 yum install openlmi
安裝 yum -y install openlmi-scripts*
scp root@10.10.10.71:/etc/Pegasus/client.pem /etc/pki/ca-trust/source/anchors/managed-machine-cert.pem
[root@localhost ~]# lmi -h 10.10.10.71
lmi> hwinfo
username: pegasus
password:
error : Failed to make a connection to "10.10.10.71": (0, 'Socket error: [Errno 113] No route to host')
error : No successful connection made.
lmi>
lmi>
lmi>
原因不詳,我看了下官網(wǎng)對(duì)于openlmi的一些介紹,使用方面也是相當(dāng)?shù)暮?jiǎn)練。
lmi -h ${hostname}
lmi> help
...
lmi> sw search django
...
lmi> sw install python-django
...
lmi> exit
rhel7 用systemd替換了咱們熟悉的sysv ,說是這東西很強(qiáng)大,說實(shí)話,資料還是少,這里就簡(jiǎn)單講解下systemd的用法。
# CentOS 6.4 service httpd (start|stop) # rhel7 systemctl (start|stop) httpd.service # CentOS 6.4 chkconfig httpd (on|off) # rhel7 systemctl (enable|disable) httpd.service $ cat /usr/lib/systemd/system/httpd.service [Unit] Description=The Apache HTTP Server After=network.target remote-fs.target nss-lookup.target [Service] Type=notify EnvironmentFile=/etc/sysconfig/httpd ExecStart=/usr/sbin/httpd $OPTIONS -DFOREGROUND ExecReload=/usr/sbin/httpd $OPTIONS -k graceful ExecStop=/usr/sbin/httpd $OPTIONS -k graceful-stop # We want systemd to give httpd some time to finish gracefully, but still want # it to kill httpd after TimeoutStopSec if something went wrong during the # graceful stop. Normally, Systemd sends SIGTERM signal right after the # ExecStop, which would kill httpd. We are sending useless SIGCONT here to give # httpd time to finish. KillSignal=SIGCONT PrivateTmp=true [Install] WantedBy=multi-user.target |
會(huì)發(fā)現(xiàn)其實(shí),用systemd參數(shù)更加的清晰,在sysv下,啟動(dòng)start、關(guān)閉stop、重啟restart都是用$1來傳遞參數(shù),但是在systemctl下,更直白點(diǎn)。很是像supervisord這個(gè)daemon程序。
[root@localhost ~]# chkconfig --list|grep samba
注意:該輸出結(jié)果只顯示 SysV 服務(wù),并不包含原生 systemd 服務(wù)。SysV 配置數(shù)據(jù)可能被原生 systemd 配置覆蓋。
如果您想列出 systemd 服務(wù),請(qǐng)執(zhí)行 'systemctl list-unit-files'。
欲查看對(duì)特定 target 啟用的服務(wù)請(qǐng)執(zhí)行
'systemctl list-dependencies [target]'。
[root@localhost ~]#
[root@localhost ~]#
[root@localhost ~]# systemctl list-dependencies samba
samba.service
[root@localhost ~]#
數(shù)據(jù)庫(kù)方面真的是轉(zhuǎn)向到mariadb,當(dāng)我去安裝mysql的時(shí)候,他會(huì)直接去安裝mariadb ,看來mariadb大勢(shì)所趨呀。
[root@localhost ~]# 原文:http://rfyiamcool.blog.51cto.com/1030776/1426550
[root@localhost ~]# yum -y install mysql
已加載插件:langpacks, product-id, subscription-manager
This system is not registered to Red Hat Subscription Management. You can use subscription-manager to register.
file:///mnt/repodata/repomd.xml: [Errno 14] curl#37 - "Couldn't open file /mnt/repodata/repomd.xml"
正在嘗試其它鏡像。
軟件包 1:mariadb-5.5.33a-3.el7.x86_64 已安裝并且是最新版本
無須任何處理
[root@localhost ~]#
[root@localhost ~]#
[root@localhost ~]# yum -y install mysql-server
已加載插件:langpacks, product-id, subscription-manager
This system is not registered to Red Hat Subscription Management. You can use subscription-manager to register.
file:///mnt/repodata/repomd.xml: [Errno 14] curl#37 - "Couldn't open file /mnt/repodata/repomd.xml"
正在嘗試其它鏡像。
正在解決依賴關(guān)系
--> 正在檢查事務(wù)
---> 軟件包 mariadb-galera-server.x86_64.1.5.5.37-2.el7 將被 安裝
--> 正在處理依賴關(guān)系 mariadb-galera-common(x86-64) = 1:5.5.37-2.el7,它被軟件包 1:mariadb-galera-server-5.5.37-2.el7.x86_64 需要
--> 正在處理依賴關(guān)系 galera >= 25.3.3,它被軟件包 1:mariadb-galera-server-5.5.37-2.el7.x86_64 需要
--> 正在處理依賴關(guān)系 perl-DBI,它被軟件包 1:mariadb-galera-server-5.5.37-2.el7.x86_64 需要
--> 正在處理依賴關(guān)系 perl-DBD-MySQL,它被軟件包 1:mariadb-galera-server-5.5.37-2.el7.x86_64 需要
--> 正在處理依賴關(guān)系 perl(DBI),它被軟件包 1:mariadb-galera-server-5.5.37-2.el7.x86_64 需要
--> 正在檢查事務(wù)
---> 軟件包 galera.x86_64.0.25.3.5-5.el7 將被 安裝
--> 正在處理依賴關(guān)系 nmap-ncat,它被軟件包 galera-25.3.5-5.el7.x86_64 需要
---> 軟件包 mariadb-galera-common.x86_64.1.5.5.37-2.el7 將被 安裝
---> 軟件包 perl-DBD-MySQL.x86_64.0.4.023-2.el7 將被 安裝
---> 軟件包 perl-DBI.x86_64.0.1.627-1.el7 將被 安裝
--> 正在處理依賴關(guān)系 perl(RPC::PlClient) >= 0.2000,它被軟件包 perl-DBI-1.627-1.el7.x86_64 需要
--> 正在處理依賴關(guān)系 perl(RPC::PlServer) >= 0.2001,它被軟件包 perl-DBI-1.627-1.el7.x86_64 需要
--> 正在檢查事務(wù)
---> 軟件包 nmap-ncat.x86_64.2.6.40-2.el7 將被 安裝
---> 軟件包 perl-PlRPC.noarch.0.0.2020-12.el7 將被 安裝
--> 正在處理依賴關(guān)系 perl(Net::Daemon) >= 0.13,它被軟件包 perl-PlRPC-0.2020-12.el7.noarch 需要
--> 正在處理依賴關(guān)系 perl(Net::Daemon::Log),它被軟件包 perl-PlRPC-0.2020-12.el7.noarch 需要
--> 正在處理依賴關(guān)系 perl(Net::Daemon::Test),它被軟件包 perl-PlRPC-0.2020-12.el7.noarch 需要
--> 正在檢查事務(wù)
---> 軟件包 perl-Net-Daemon.noarch.0.0.48-4.el7 將被 安裝
--> 解決依賴關(guān)系完成
依賴關(guān)系解決
======================================================================================================================================
Package 架構(gòu) 版本 源 大小
======================================================================================================================================
正在安裝:
mariadb-galera-server x86_64 1:5.5.37-2.el7 epel 11 M
為依賴而安裝:
galera x86_64 25.3.5-5.el7 epel 1.1 M
mariadb-galera-common x86_64 1:5.5.37-2.el7 epel 212 k
nmap-ncat x86_64 2:6.40-2.el7 rhel-iso 198 k
perl-DBD-MySQL x86_64 4.023-2.el7 rhel-iso 140 k
perl-DBI x86_64 1.627-1.el7 rhel-iso 801 k
perl-Net-Daemon noarch 0.48-4.el7 rhel-iso 51 k
perl-PlRPC noarch 0.2020-12.el7
期待centos7的到來,用rhel7,總是覺得不順手,心里別扭。 先這樣,有時(shí)間再搞。
English » | | | | | | | | |
Text-to-speech function is limited to 100 characters
1.測(cè)試對(duì)象
這次測(cè)了一些http接口和幾個(gè)網(wǎng)頁。
2.測(cè)試策略
2.1 基準(zhǔn)
測(cè)試:?jiǎn)蝹€(gè)調(diào)用各接口循環(huán)100次計(jì)算平均響應(yīng)時(shí)間
2.2
性能測(cè)試:?jiǎn)蝹€(gè)接口調(diào)用以50并發(fā)用戶數(shù)為單位,逐步加壓直到預(yù)估的實(shí)際負(fù)載300并發(fā)用戶,觀察測(cè)試指標(biāo)變化
2.3
壓力測(cè)試:?jiǎn)蝹€(gè)接口調(diào)用以50并發(fā)用戶數(shù)為單位,逐步加壓直到錯(cuò)誤率過高或服務(wù)器資源使用率過高,觀察測(cè)試指標(biāo)變化
2.4 負(fù)載測(cè)試:預(yù)估實(shí)際負(fù)載為300并發(fā)用戶數(shù),在此基礎(chǔ)上持續(xù)測(cè)試5分鐘左右,觀察測(cè)試指標(biāo)是否達(dá)標(biāo)
2.5 穩(wěn)定性測(cè)試:預(yù)估實(shí)際負(fù)載為300并發(fā)用戶數(shù),在此基礎(chǔ)上持續(xù)測(cè)試60分鐘左右,觀察測(cè)試指標(biāo)是否達(dá)標(biāo),重點(diǎn)觀察錯(cuò)誤率
2.6 疲勞性測(cè)試:預(yù)估實(shí)際負(fù)載為300并發(fā)用戶數(shù),在此基礎(chǔ)上持續(xù)測(cè)試240分鐘左右,觀察測(cè)試指標(biāo)是否達(dá)標(biāo),重點(diǎn)觀察錯(cuò)誤率
2.7 組合測(cè)試:對(duì)2.2-2.5的測(cè)試采用不同接口同時(shí)調(diào)用(即系統(tǒng)不同模塊同時(shí)測(cè)試)
2.8 其他:以不同ip地址加壓,測(cè)試服務(wù)器負(fù)載均衡效果。
以上,本次只做了2.2、2.3、2.4、2.8
3.測(cè)試指標(biāo)
測(cè)響應(yīng)時(shí)間、錯(cuò)誤率;同時(shí)專人監(jiān)控服務(wù)器硬件資源使用狀況、監(jiān)控tomcat應(yīng)用服務(wù)器等。
計(jì)算和監(jiān)控吞吐量(測(cè)試工具自動(dòng)計(jì)算測(cè)試執(zhí)行過程中的吞吐量(每秒鐘處理請(qǐng)求數(shù)),同時(shí)服務(wù)器監(jiān)控軟件業(yè)監(jiān)控到了測(cè)試執(zhí)行時(shí)服務(wù)器的吞吐量)
本次實(shí)際測(cè)試得到吞吐量距離預(yù)估有較大差距;錯(cuò)誤率超出預(yù)期;且測(cè)試數(shù)據(jù)準(zhǔn)備有一定問題。
4.測(cè)試工具
需設(shè)置語言為英文,默認(rèn)中文翻譯不完整。
5.測(cè)試腳本編寫、調(diào)試
5.1 提前對(duì)接口、網(wǎng)頁進(jìn)行錄制。每個(gè)待測(cè)接口、網(wǎng)頁需要加斷言。 斷言多采用JQuery斷言和Regular Expression斷言
5.2 重點(diǎn)在測(cè)試數(shù)據(jù)的準(zhǔn)備。
5.3 采用了本地
web應(yīng)用提供數(shù)據(jù),jmeter獲取這些數(shù)據(jù),再發(fā)送給服務(wù)器的方法(這次發(fā)現(xiàn)這個(gè)本地應(yīng)用生成的數(shù)據(jù)在較高并發(fā)時(shí)有重復(fù),導(dǎo)致了不必要的錯(cuò)誤率)
5.4 測(cè)試結(jié)果監(jiān)聽器: assertion results, summary report, aggregate report, result tree, result table
5.5 測(cè)試接口調(diào)用時(shí),可用網(wǎng)頁、
數(shù)據(jù)庫(kù)等其他方法確認(rèn)接口調(diào)用成功。觀察接口調(diào)用是否生效,是否和網(wǎng)頁同樣效果。
6.測(cè)試執(zhí)行
6.1 一臺(tái)電腦加壓300-600并發(fā)用戶。如果需要更多則需要增加電腦。
6.2 以不同ip地址加壓,測(cè)試服務(wù)器負(fù)載均衡效果。
6.3 機(jī)房測(cè)試,排除internet網(wǎng)絡(luò)延遲問題
6.4 數(shù)據(jù)備份和還原,排除性能測(cè)試對(duì)數(shù)據(jù)的改變
6.5 生產(chǎn)環(huán)境測(cè)試(系統(tǒng)未上線),排除測(cè)試環(huán)境的影響
7.測(cè)試報(bào)告
7.1 截取了jmeter監(jiān)聽器的結(jié)果,可以截取服務(wù)器監(jiān)控的截圖
8.調(diào)優(yōu)
本次測(cè)試結(jié)果不理想,服務(wù)器因硬件強(qiáng)大,幾乎無負(fù)載,但應(yīng)用本身有
java出錯(cuò)。并發(fā)現(xiàn)接口調(diào)用結(jié)果未正確影響網(wǎng)頁的bug。
后續(xù)需要等開發(fā)修復(fù)、優(yōu)化之后再次測(cè)試
English » | | | | | | | | |
Text-to-speech function is limited to 100 characters
一、什么是 ARC ?
所謂ARC就是Automatic Reference Counting , 即自動(dòng)引用計(jì)數(shù)。ARC是自iOS5引入的。ARC機(jī)制的引入是為了簡(jiǎn)化開發(fā)過程的內(nèi)存管理的。相對(duì)于之前的MRC (Manual Reference Counting) , ARC機(jī)制顯得更加自動(dòng)化。在使用ARC開發(fā)過程中,開發(fā)者只需考慮strong / weak 的使用,不再需要考慮對(duì)象何時(shí)要retain,release/autorealease。使用ARC一般不會(huì)降低程序的效率。
ARC一個(gè)很重要的原則是:只要某個(gè)對(duì)象被任一strong指針指向,那么它將不會(huì)被銷毀。如果對(duì)象沒有被任何strong指針指向,那么就將被銷毀。
ARC是基于引用計(jì)數(shù)的,當(dāng)某個(gè)對(duì)象被一個(gè)strong指針指向時(shí),它的計(jì)數(shù)+1。當(dāng)沒有strong指針指向時(shí),其計(jì)數(shù)為0,此時(shí)對(duì)象會(huì)被銷毀。只要一個(gè)對(duì)象有至少一個(gè)strong指針指向時(shí),它就不會(huì)被銷毀。但ARC容易造成一個(gè) Strong Reference Cycle 的問題,這樣即使AddBook 和 Entry 這兩個(gè)對(duì)象都不再使用了,但是由于ARC機(jī)制,這兩個(gè)對(duì)象都互相有strong指針指向,所以這兩個(gè)對(duì)象都不會(huì)被回收,從而造成內(nèi)存無法被釋放。
針對(duì)上面的情況,有一種解決方法:在其中一個(gè)對(duì)象中引入weak,替換其strong
引入weak后,當(dāng)entry使用完后,由于指向AddrBook沒有strong指針,所以AddrBook會(huì)首先被釋放,然后由于AddrBook被釋放,指向Entry的Strong指針也會(huì)銷毀,此時(shí)沒有指向Entry的strong指針,所以Entry也會(huì)被釋放。這樣就不會(huì)出現(xiàn)內(nèi)存無法被釋放的情況。
這里就有一個(gè)問題了,什么時(shí)候應(yīng)該用strong,什么時(shí)候應(yīng)該用weak呢?看以下解析:
如圖所示,ViewController直接持有View,所以ViewController應(yīng)該要有一個(gè)strong指向view。同理,view直接持有subviews,所以也應(yīng)該要有strong指向subviews。由于viewcontroller要使用subviews對(duì)象,但又不想直接持有subviews,所以只好通過weak指向subviews。這樣的話,可以在viewcontroller中不改變view的持有關(guān)系,就可以使用subviews對(duì)象。從圖中可以得出一個(gè)通用的規(guī)律:對(duì)于有直接持有的關(guān)系,持有者要通過strong指向被持有者。對(duì)于有間接持有關(guān)系的,間接持有者需通過weak指向間接被持有者。
English » | | | | | | | | |
Text-to-speech function is limited to 100 characters
Java遠(yuǎn)程方法調(diào)用,即Java RMI(Java Remote Method Invocation)是Java編程語言里,一種用于實(shí)現(xiàn)遠(yuǎn)程過程調(diào)用的應(yīng)用程序編程接口。它使客戶機(jī)上運(yùn)行的程序可以調(diào)用遠(yuǎn)程服務(wù)器上的對(duì)象。遠(yuǎn)程方法調(diào)用特性使Java編程人員能夠在網(wǎng)絡(luò)環(huán)境中分布操作。RMI全部的宗旨就是盡可能簡(jiǎn)化遠(yuǎn)程接口對(duì)象的使用。
一、創(chuàng)建RMI程序的4個(gè)步驟
1、定義一個(gè)遠(yuǎn)程接口的接口,該接口中的每一個(gè)方法必須聲明它將產(chǎn)生一個(gè)RemoteException異常。
2、定義一個(gè)實(shí)現(xiàn)該接口的類。
3、創(chuàng)建一個(gè)服務(wù),用于發(fā)布2中定義的類。
4、創(chuàng)建一個(gè)客戶程序進(jìn)行RMI調(diào)用。
二、程序的詳細(xì)實(shí)現(xiàn)
1.首先我們先創(chuàng)建一個(gè)實(shí)體類,這個(gè)類需要實(shí)現(xiàn)Serializable接口,用于信息的傳輸。
1 import java.io.Serializable; 3 public class Student implements Serializable { 5 private String name; 7 private int age; 9 public String getName() { 11 return name; 13 } 15 public void setName(String name) { 17 this.name = name; 19 } 21 public int getAge() { 23 return age; 25 } 27 public void setAge(int age) { 29 this.age = age; 31 } 33 } |
2.定義一個(gè)接口,這個(gè)接口需要繼承Remote接口,這個(gè)接口中的方法必須聲明RemoteException異常。
1 import java.rmi.Remote;
3 import java.rmi.RemoteException;
5 import java.util.List;
6 public interface StudentService extends Remote {
12 List<Student> getList() throws RemoteException;
14 }
3.創(chuàng)建一個(gè)類,并實(shí)現(xiàn)步驟2中的接口,但還需要繼承UnicastRemoteObject類和顯示寫出無參的構(gòu)造函數(shù)。
1 import java.rmi.RemoteException; 3 import java.rmi.server.UnicastRemoteObject; 5 import java.util.ArrayList; 7 import java.util.List; 11 public class StudentServiceImpl extends UnicastRemoteObject implements 13 StudentService { 15 public StudentServiceImpl() throws RemoteException { 17 } 21 public List<Student> getList() throws RemoteException { 23 List<Student> list=new ArrayList<Student>(); 25 Student s1=new Student(); 27 s1.setName("張三"); 29 s1.setAge(15); 31 Student s2=new Student(); 33 s2.setName("李四"); 35 s2.setAge(20); 37 list.add(s1); 39 list.add(s2); 41 return list; 43 } 45 } |
4.創(chuàng)建服務(wù)并啟動(dòng)服務(wù)
1 import java.rmi.Naming; 2 import java.rmi.registry.LocateRegistry; 4 public class SetService { 6 public static void main(String[] args) { 8 try { 10 StudentService studentService=new StudentServiceImpl(); 12 LocateRegistry.createRegistry(5008);//定義端口號(hào) 14 Naming.rebind("rmi://127.0.0.1:5008/StudentService", studentService); 16 System.out.println("服務(wù)已啟動(dòng)"); 18 } catch (Exception e) { 20 e.printStackTrace(); 22 } 24 } 26 } |
5. 創(chuàng)建一個(gè)客戶程序進(jìn)行RMI調(diào)用。
1 import java.rmi.Naming; 3 import java.util.List; 5 public class GetService { 9 public static void main(String[] args) { 11 try { 13 StudentService studentService=(StudentService) Naming.lookup("rmi://127.0.0.1:5008/StudentService"); 15 List<Student> list = studentService.getList(); 17 for (Student s : list) { 19 System.out.println("姓名:"+s.getName()+",年齡:"+s.getAge()); 21 } 23 } catch (Exception e) { 25 e.printStackTrace(); 27 } 29 } 33 } |
6.控制臺(tái)顯示結(jié)果
=============控制臺(tái)============
姓名:張三,年齡:15
姓名:李四,年齡:20
===============================
在Spring中配置Rmi服務(wù)
將Rmi和Spring結(jié)合起來用的話,比上面實(shí)現(xiàn)Rmi服務(wù)要方便的多。
1.首先我們定義接口,此時(shí)定義的接口不需要繼承其他接口,只是一個(gè)普通的接口
1 package service;
3 import java.util.List;
5 public interface StudentService {
7 List<Student> getList();
9 }
2.定義一個(gè)類,實(shí)現(xiàn)這個(gè)接口,這個(gè)類也只需實(shí)現(xiàn)步驟一定義的接口,不需要額外的操作
1 package service; 4 import java.util.ArrayList; 6 import java.util.List; 9 public class StudentServiceImpl implements StudentService { 11 public List<Student> getList() { 13 List<Student> list=new ArrayList<Student>(); 15 Student s1=new Student(); 17 s1.setName("張三"); 19 s1.setAge(15); 21 Student s2=new Student(); 23 s2.setName("李四"); 25 s2.setAge(20); 27 list.add(s1); 29 list.add(s2); 31 return list; 33 } 35 } |
3.接一下來在applicationContext.xml配置需要的信息
a.首先定義服務(wù)bean
<bean id="studentService" class="service.StudentServiceImpl"></bean>
b.定義導(dǎo)出服務(wù)
<bean class="org.springframework.remoting.rmi.RmiServiceExporter"
p:service-ref="studentService"
p:serviceInterface="service.StudentService"
p:serviceName="StudentService"
p:registryPort="5008"
/>
也可以增加p:registryHost屬性設(shè)置主機(jī)
c.在客戶端的applicationContext.xml中定義得到服務(wù)的bean(這里的例子是把導(dǎo)出服務(wù)bean和客戶端的bean放在一個(gè)applicationContext.xml中的)
<bean id="getStudentService"
class="org.springframework.remoting.rmi.RmiProxyFactoryBean"
p:serviceUrl="rmi://127.0.0.1:5008/StudentService"
p:serviceInterface="service.StudentService"
/>
d.配置的東西就這么多,是不是比上面的現(xiàn)實(shí)要方便的多呀!現(xiàn)在我們來測(cè)試一下
1 package service; 2 import java.util.List; 3 import org.springframework.context.ApplicationContext; 4 import org.springframework.context.support.ClassPathXmlApplicationContext; 5 public class Test { 6 public static void main(String[] args) { 7 ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml"); 8 StudentService studentService=(StudentService) ctx.getBean("getStudentService"); 9 List<Student> list = studentService.getList(); 10 for (Student s : list) { 11 System.out.println("姓名:"+s.getName()+",年齡:"+s.getAge()); 12 } 13 } 14 } |
=============控制臺(tái)============
姓名:張三,年齡:15
姓名:李四,年齡:20
=============================
上面的mian方法運(yùn)行可能會(huì)報(bào)錯(cuò),應(yīng)該是spring的jar少了,自己注意添加。
English » | | | | | | | | |
Text-to-speech function is limited to 100 characters
關(guān)于<<提高代碼質(zhì)量系列>>
這是我新開的一個(gè)系列,旨在記錄我對(duì)整個(gè)編碼規(guī)范,代碼風(fēng)格,語法習(xí)慣,架構(gòu)設(shè)計(jì)的一些思考,感悟和總結(jié).
前言
不知道大家會(huì)不會(huì)覺得我的標(biāo)題很噱頭,不是一般應(yīng)該提倡寫注釋的么?首先我得解釋下,我這句話有兩個(gè)意思!
1,絕非提倡不寫注釋,而是不要寫不必要的注釋.
2,命名規(guī)范的作用大于注釋
好吧,這么一說,其實(shí)還是有點(diǎn)噱頭的感覺的,因?yàn)槲疫@篇文其實(shí)重心更放在強(qiáng)調(diào)命名規(guī)范和設(shè)計(jì)規(guī)范上面,良好的規(guī)范,讓你的代碼有自釋性,省去了注釋的步驟.
還要強(qiáng)調(diào)下的是:這個(gè)觀點(diǎn)絕非我自己主觀臆斷,憑空瞎想出來的. 而是實(shí)實(shí)在在由項(xiàng)目開發(fā)里面總結(jié)出來的.
為什么我有這個(gè)想法呢?請(qǐng)繼續(xù)看我的蛋疼經(jīng)歷.
正文
先上段奇葩代碼
/// <summary> /// 根據(jù)產(chǎn)品ID獲取產(chǎn)品列表 /// </summary> /// <param name="columnID">關(guān)鍵字</param> public DataTable GetColumnInfoByColumnID(int columnID) { return DALColumn.GetColumnInfoByColumnID(columnID); } /// <summary> /// 根據(jù)產(chǎn)品名稱獲取產(chǎn)品列表 /// </summary> /// <param name="columnID">關(guān)鍵字</param> public DataTable GetColumnInfoByColumnID(string columnName) { return DALColumn.GetColumnInfoByColumnID(columnName); } |
這是我現(xiàn)在維護(hù)的一個(gè)老項(xiàng)目了,經(jīng)手的人比較多,代碼寫的比較垃圾,我們先不吐槽這種純粹是脫褲子放屁的所謂三層和明明返回的是dataTable又扯什么info,就說這兩個(gè)函數(shù),tm功能應(yīng)該是不一樣的吧,為啥名字一模一樣?這是在鬧哪樣?
其實(shí),造成這種情況的原因,我們都知道,就是某類程序員的ctrl c+v大法,這兩個(gè)函數(shù)底層邏輯比較相似,懶得重構(gòu),直接copy了改改多快!copy就copy吧,好歹名字改一下啊!也許這位前輩會(huì)說,我不是寫了注釋了嗎,看到注釋,不就知道這個(gè)函數(shù)是干嘛的了?但問題是,其他調(diào)用的人,首先看到的,肯定是函數(shù)名啊,GetColumnInfoByColumnID,多直觀 通過id來查找唄.雖然這里有兩個(gè)比較違和的地方,一是參數(shù)默認(rèn)名字是columnName,二是參數(shù)類型不是int而是string,但反正這項(xiàng)目的代碼不規(guī)范,如果調(diào)用的人也夠粗心,那么,一個(gè)隱晦的bug,就這么產(chǎn)生了.
如果改下名字,叫 GetTableByColumnName,這種錯(cuò)誤發(fā)生的概率無疑會(huì)減少很多了,
Ps:其實(shí)現(xiàn)在ide功能這么強(qiáng)大,只要你確定沒有反射調(diào)用這個(gè)函數(shù)的地方,完全可以使用全局重命名的方法,一步到位.
看到這里讀者朋友們可能會(huì)說,這是命名不規(guī)范嘛,和寫不寫注釋有什么關(guān)系呢?
我們可以假想一種這樣的情況,同樣是拷貝代碼,拷貝者改了函數(shù)名,這個(gè)名字語義清晰,表意清楚, 但他卻忘記改注釋了,結(jié)果函數(shù)是新的函數(shù)簽名,函數(shù)的注釋卻是其他一段莫名其妙的注釋.
或者再假想一種情況.
原來的一個(gè)函數(shù),名字和注釋是對(duì)應(yīng)的,隨便舉個(gè)例子,叫GetTypeByColumnId吧,注釋為"通過產(chǎn)品id取得產(chǎn)品類型"
一切ok,是吧! 但是現(xiàn)在邏輯變了,比如說Type和產(chǎn)品無關(guān)了,需要通過生產(chǎn)批次來確定,于是一個(gè)代碼維護(hù)者,將函數(shù)重寫了一下功能ok,滿足新需求!!同時(shí)他比上個(gè)人好一點(diǎn),他記得改函數(shù)名,然后他改為了GetTypeBySerialId,這名字也很ok,一切也都看起來很好.但偏偏他漏掉了注釋,但代碼仍然運(yùn)行的很ok,畢竟注釋可不受.net的元數(shù)據(jù)的支持,ide也不可能知道你這里犯了這么一個(gè)錯(cuò)誤是吧!
然后,接下來的場(chǎng)景大家很容易就可以聯(lián)想到,
如果是細(xì)心的調(diào)用者:
尼瑪!函數(shù)注釋讓我傳"產(chǎn)品id",但函數(shù)名和參數(shù)默認(rèn)名字又是"SerialId"(流水號(hào)),這尼瑪鬧哪樣?
如果是粗心的調(diào)用者呢?兩種情況唄:
1.看了函數(shù)名字和默認(rèn)參數(shù)名字 ,沒注意到注釋,ok,算這個(gè)粗心的小伙伴幸運(yùn),
2.看了注釋,然后這小伙伴不認(rèn)識(shí)SerialId這個(gè)單詞的意思. 然后,一個(gè)悲傷的故事就這么發(fā)生了!!
其實(shí)我以上舉例的一些函數(shù),都是功能比較具體,業(yè)務(wù)比較單純,也容易用幾個(gè)單詞描述.對(duì)于這些函數(shù),我個(gè)人的意見是,完全不需要去寫注釋,
有以下幾個(gè)原因:
1.浪費(fèi)精力去寫,
2.調(diào)用的人需要把一段話讀兩遍(函數(shù)名和注釋)
3.寫了還需要人去維護(hù),(改了代碼,得同步去改注釋)
4.如果強(qiáng)類型的參數(shù)傳遞不匹配,ide或者resharper插件會(huì)馬上指出你的錯(cuò)誤,但如果注釋和代碼不匹配,則除了通過人力CodeReview,沒有其他任何辦法去找出這種錯(cuò)誤.
其中尤其是4,完全就是埋在項(xiàng)目中的地雷,除非你踩到了,不然很難排查.
當(dāng)然,如果是反之,邏輯復(fù)雜,甚至有調(diào)用的前置約束,那肯定該寫注釋還是得寫了.
同時(shí),這里還提一個(gè)觀點(diǎn),注釋比代碼更有價(jià)值,因?yàn)榇a畢竟大部分還是在講怎么做(how do),而注釋是講做什么(do what)?抽象程度更高,對(duì)于比較復(fù)雜的代碼,如果有注釋,調(diào)用者一般都會(huì)優(yōu)先去閱讀注釋,而不是去閱讀代碼,所以:輕易不寫注釋,但如果你寫了,請(qǐng)一定要對(duì)你的注釋負(fù)責(zé),它比代碼更需要你的細(xì)心呵護(hù)!!
好吧,我會(huì)說這篇文最大的作用,其實(shí)是可以讓我吐槽發(fā)泄一下么?
我感覺自己現(xiàn)在就是在這種地雷坑里,天天過著提醒吊膽的日子.
以上例子皆非我刻意編造,來源于工作中的真實(shí)經(jīng)歷,只是稍作修飾,隱去了和業(yè)務(wù)有關(guān)的信息.
根據(jù)回復(fù)的補(bǔ)充:
相信很多博友有這樣的經(jīng)歷,這個(gè)函數(shù)好復(fù)雜呀!我必須寫注釋啊,不然一段時(shí)間之后,我自己都看不明白了,
有些時(shí)候是確實(shí)很復(fù)雜,但也有時(shí)候是設(shè)計(jì)的問題,這時(shí)候,寫注釋其實(shí)是一種逃避了.逃避你需要繼續(xù)深入思考這個(gè)函數(shù)的業(yè)務(wù)和功能的設(shè)計(jì)是否合理.
其實(shí)我這標(biāo)題還有第三個(gè)意思:
在盡可能少寫注釋的前提下,如果一個(gè)函數(shù)的注釋仍然超過了2處,那么我認(rèn)為這個(gè)函數(shù)的設(shè)計(jì)是有問題的.
這個(gè)函數(shù)是否太大,是否是反模式里面提到的萬應(yīng)靈或屠龍術(shù)?
所以有時(shí)候說的 "因?yàn)闃I(yè)務(wù)復(fù)雜,很難用幾個(gè)單詞去描述,所以很難命名",就是如此.
你的業(yè)務(wù)抽象粒度是否太大?導(dǎo)致一個(gè)業(yè)務(wù)模塊承擔(dān)了過多的業(yè)務(wù).
你是否把幾個(gè)流程放在了一個(gè)節(jié)點(diǎn)上?導(dǎo)致引入了額外的邏輯判斷甚至是多余的邏輯分支.
如果是這樣,你想用幾個(gè)單詞來描述這么復(fù)雜的邏輯,當(dāng)然是不可能了.
這點(diǎn)我會(huì)在后續(xù)的重構(gòu)系列里面談?wù)勎易约旱睦斫?
補(bǔ)充下自己的理解.
我始終認(rèn)為好的設(shè)計(jì),大部分情況下,函數(shù)名就足以解釋它的功能,如果你遇到了兩三個(gè)單詞不能解釋函數(shù)功能的情況----說明你該分解函數(shù)了!
比如一個(gè)大函數(shù),OutPutMetaData,輸入是源數(shù)據(jù)路徑,使用的模板 返回解析之后的元數(shù)據(jù)
流程大概是 采集數(shù)據(jù)->分析數(shù)據(jù)->匹配模板->生成MetaData
代碼是大約1-2k行,如果寫在一個(gè)函數(shù)里面,當(dāng)然也似可以的,但你想用注釋解釋清楚,必須在每個(gè)流程的關(guān)鍵節(jié)點(diǎn)寫注釋,遇到數(shù)據(jù)有前后關(guān)聯(lián)關(guān)系的,還得思維反復(fù)跳來跳去.
但如果寫成下面這種模式的代碼,基本就像是閱讀英文說明(注釋),一樣閱讀代碼了
public MetaData OutPutMetaData(string sourcePath, MetaTemplate template) { var metaDataFactory = new MetaDataFactory(); if (!metaDataFactory.CheckInput(sourcePath)) { throw new ErrorSourceException(); } if (!metaDataFactory.TransformSourceData(template)) { throw new ErrorFormatException(); } return metaDataFactory.CreateMetaData(); } |
這樣寫雖然多了很多的類和方法,還要額外定義一些中間數(shù)據(jù)的實(shí)體類型和自定義異常,但是經(jīng)過合理的封裝和命名之后,整個(gè)結(jié)構(gòu)非常清晰,定位錯(cuò)誤和修改流程也方便.
代碼閱讀速度基本和描述語句(注釋)的閱讀速度相當(dāng), 這就是代碼即注釋.
最后總結(jié):
其實(shí)我認(rèn)為最關(guān)鍵是要形成自己的編碼規(guī)范,這個(gè)"規(guī)范"不僅僅指的是狹義的命名規(guī)則和代碼格式,縮進(jìn),文件組織結(jié)構(gòu)等.更關(guān)鍵的是,要形成一套有邏輯性,能自洽,有良性導(dǎo)向的一套思維模式,并時(shí)刻堅(jiān)持遵守它,思考它,改進(jìn)它.
這套思維模式你可以自由的去擴(kuò)展,只要不偏離它的中心思想.比如我給自己擴(kuò)展的一些要求:
1.函數(shù)一律使用動(dòng)賓結(jié)構(gòu),如InitFactory,而不用FactoryInit,其實(shí)這兩者沒什么優(yōu)劣,僅僅只是讓自己習(xí)慣,以后思考和閱讀自己代碼的時(shí)候,能更快的帶入過去的自己的思維,更快的理解自己的代碼,同時(shí)找api也能節(jié)約一點(diǎn)時(shí)間.
2.html標(biāo)簽樣式id小寫開頭,class大寫開頭,同理,其實(shí)也沒啥原因,就是個(gè)習(xí)慣.
3.描述一個(gè)事物的時(shí)候要區(qū)分是what it is(名詞,形容詞)還是what it can do(動(dòng)詞,動(dòng)名詞,動(dòng)賓短語)比如doClose, 是某個(gè)事物的動(dòng)作,closing,和 closed則代表它的狀態(tài)
再就是結(jié)構(gòu)設(shè)計(jì)上的一些感覺了,這個(gè)比較抽象,不好用文字很準(zhǔn)確的描述,大致意思就是我會(huì)從一些緯度對(duì)功能進(jìn)行切分,access business viewModel show interaction 等,不一定都能分的非常清楚,也不強(qiáng)求一個(gè)區(qū)分度很高的邊際,但至少要有個(gè)模糊的定位.
如果能長(zhǎng)期堅(jiān)持下來,以后閱讀自己的代碼是非常容易的,即使是沒有(少量)注釋.
Ps:錘煉自己的這套思維模式的方法也很簡(jiǎn)單,也就三點(diǎn)
多看優(yōu)秀代碼,自己動(dòng)手多寫,多思考總結(jié).
English » | | | | | | | | |
Text-to-speech function is limited to 100 characters
一、Webbench簡(jiǎn)單介紹
在一個(gè)網(wǎng)站上線前, 通常我們應(yīng)該做一些相關(guān)的
壓力測(cè)試, 以便了解當(dāng)前
Web服務(wù)器在高并發(fā)高負(fù)載情況下的響應(yīng)狀況和速度,方便對(duì)Web服務(wù)器進(jìn)行優(yōu)化和重構(gòu)。目前有很多免費(fèi)的web壓力測(cè)試工具可以幫助我們完成測(cè)試, 例如: 十個(gè)免費(fèi)的Web壓力測(cè)試工具h(yuǎn)ttp://coolshell.cn/articles/2589.html,但在真實(shí)項(xiàng)目中使用Apache ab和Webbench來完成壓力測(cè)試。Apache的優(yōu)點(diǎn):Apache的ab使用非常簡(jiǎn)單, 而且只要是安裝了Apache了,就會(huì)自帶其ab工具,缺點(diǎn):就是不能模擬高并發(fā)狀態(tài)下的測(cè)試, 好像最多可以模擬100-200次/秒的并發(fā). 如果需要模擬更高負(fù)載的壓力測(cè)試, 就需要使用Webbench。
Webbench是有名的網(wǎng)站
壓力測(cè)試工具,它是由 Lionbridge公司(http://www.lionbridge.com)開發(fā)。Webbech能測(cè)試處在相同硬件上,不同服務(wù)的性能以及不同硬件上同一個(gè)服務(wù)的運(yùn)行狀況。webBech的標(biāo)準(zhǔn)測(cè)試可以向我們展示服務(wù)器的兩項(xiàng) 內(nèi)容:每秒鐘相應(yīng)請(qǐng)求數(shù)和每秒鐘傳輸數(shù)據(jù)量。webbench不但能具有便準(zhǔn)靜態(tài)頁面的測(cè)試能力,還能對(duì)動(dòng)態(tài)頁面(ASP,PHP,JAVA,CGI)進(jìn)行測(cè)試的能力。還有就是他支持對(duì)含有SSL的安全網(wǎng)站例如電子商務(wù)網(wǎng)站進(jìn)行靜態(tài)或動(dòng)態(tài)的
性能測(cè)試,webbench最多可以模擬3萬個(gè)并發(fā)連接去測(cè)試網(wǎng)站的負(fù)載能力。缺點(diǎn)測(cè)試的結(jié)果太簡(jiǎn)單了。
二、安裝Webbench
注意點(diǎn):為了測(cè)試準(zhǔn)確,請(qǐng)將 webbench 安裝在別的linux服務(wù)器上,(因?yàn)閣ebbench 做壓力測(cè)試時(shí),自身也會(huì)消耗CPU和內(nèi)存資源, 否則很可能把自己服務(wù)器搞掛掉)
目前Webbench最新的版本為webbench-1.5.tar.gz下載地址 http://home.tiscali.cz/~cz210552/distfiles/webbench-1.5.tar.gz
1.先安裝依賴包:yum install ctags
2.安裝Webbench:
tar zxvfwebbench-1.5.tar.gz
cd webbench-1.5
make &&make install
如果出現(xiàn)以下報(bào)錯(cuò)信息:
ctags *.c /bin/sh: ctags: command not found make: [tags] Error 127 (ignored) install -s webbench /usr/local/bin install -m 644 webbench.1 /usr/local/man/man1 install: cannot create regular file `/usr/local/man/man1': No such file ordirectory make: *** [install] Error 1 |
解決方法:
mkdir -p /usr/local/man
chmod 644 /usr/local/man
再次執(zhí)行make && make install
看到如下界面,說明安裝成功
make: Nothing to be done for `all'. install -s webbench /usr/local/bin install -m 644 webbench.1/usr/local/man/man1 install -d /usr/local/share/doc/webbench install -m 644 debian/copyright/usr/local/share/doc/webbench install -m 644 debian/changelog/usr/local/share/doc/webbench |
三、使用
[root@centos ~]# webbench -c 400 -t 20 http://10.43.2.192/ Webbench - Simple Web Benchmark 1.5 Copyright (c) Radim Kolar 1997-2004, GPL Open Source Software. Benchmarking: GET http://10.43.2.192/ 400 clients, running 20 sec. Speed=392676 pages/min, 1603427 bytes/sec. Requests: 130892 susceed, 0 failed. |
參數(shù)說明:-c表示并發(fā)數(shù),-t表示時(shí)間(秒)
每秒鐘傳輸數(shù)據(jù)量:1603427 bytes/sec每秒鐘相應(yīng)請(qǐng)求數(shù):392676/60= 6544 pages/sec
這里有一個(gè)特別要注意的點(diǎn):10.43.2.192/后面的“/”一定不要忘記
English » | | | | | | | | |
Text-to-speech function is limited to 100 characters
摘要: 簡(jiǎn)介 Selenium 是一個(gè)健壯的工具集合,跨很多平臺(tái)支持針對(duì)基于 web 的應(yīng)用程序的測(cè)試自動(dòng)化的敏捷開發(fā)。它是一個(gè)開源的、輕量級(jí)的自動(dòng)化工具,很容易集成到各種項(xiàng)目中,支持多種編程語言,比如 .NET、Perl、Python、Ruby 和 Java? 編程語言。 利用 Selenium 測(cè)試 Ajax 應(yīng)用程序 Asynchronous JavaS...
閱讀全文