|
在JDBC應(yīng)用中,如果你已經(jīng)是稍有水平開(kāi)發(fā)者,你就應(yīng)該始終以PreparedStatement代替Statement.也就是說(shuō),在任何時(shí)候都不要使用Statement.
基于以下的原因:
一.代碼的可讀性和可維護(hù)性.
雖然用PreparedStatement來(lái)代替Statement會(huì)使代碼多出幾行,但這樣的代碼無(wú)論從可讀性還是可維護(hù)性上來(lái)說(shuō).都比直接用Statement的代碼高很多檔次:
stmt.executeUpdate("insert into tb_name (col1,col2,col2,col4) values ('"+var1+"','"+var2+"',"+var3+",'"+var4+"')");
perstmt = con.prepareStatement("insert into tb_name (col1,col2,col2,col4) values (?,?,?,?)");
perstmt.setString(1,var1);
perstmt.setString(2,var2);
perstmt.setString(3,var3);
perstmt.setString(4,var4);
perstmt.executeUpdate();
不用我多說(shuō),對(duì)于第一種方法.別說(shuō)其他人去讀你的代碼,就是你自己過(guò)一段時(shí)間再去讀,都會(huì)覺(jué)得傷心.
二.PreparedStatement盡最大可能提高性能.
每一種數(shù)據(jù)庫(kù)都會(huì)盡最大努力對(duì)預(yù)編譯語(yǔ)句提供最大的性能優(yōu)化.因?yàn)轭A(yù)編譯語(yǔ)句有可能被重復(fù)調(diào)用.所以語(yǔ)句在被DB的編譯器編譯后的執(zhí)行代碼被緩存下來(lái),那么下次調(diào)用時(shí)只要是相同的預(yù)編譯語(yǔ)句就不需要編譯,只要將參數(shù)直接傳入編譯過(guò)的語(yǔ)句執(zhí)行代碼中(相當(dāng)于一個(gè)涵數(shù))就會(huì)得到執(zhí)行.這并不是說(shuō)只有一個(gè) Connection中多次執(zhí)行的預(yù)編譯語(yǔ)句被緩存,而是對(duì)于整個(gè)DB中,只要預(yù)編譯的語(yǔ)句語(yǔ)法和緩存中匹配.那么在任何時(shí)候就可以不需要再次編譯而可以直接執(zhí)行.而statement的語(yǔ)句中,即使是相同一操作,而由于每次操作的數(shù)據(jù)不同所以使整個(gè)語(yǔ)句相匹配的機(jī)會(huì)極小,幾乎不太可能匹配.比如:
insert into tb_name (col1,col2) values ('11','22');
insert into tb_name (col1,col2) values ('11','23');
即使是相同操作但因?yàn)閿?shù)據(jù)內(nèi)容不一樣,所以整個(gè)個(gè)語(yǔ)句本身不能匹配,沒(méi)有緩存語(yǔ)句的意義.事實(shí)是沒(méi)有數(shù)據(jù)庫(kù)會(huì)對(duì)普通語(yǔ)句編譯后的執(zhí)行代碼緩存.這樣每執(zhí)行一次都要對(duì)傳入的語(yǔ)句編譯一次.
當(dāng)然并不是所以預(yù)編譯語(yǔ)句都一定會(huì)被緩存,數(shù)據(jù)庫(kù)本身會(huì)用一種策略,比如使用頻度等因素來(lái)決定什么時(shí)候不再緩存已有的預(yù)編譯結(jié)果.以保存有更多的空間存儲(chǔ)新的預(yù)編譯語(yǔ)句.
三.最重要的一點(diǎn)是極大地提高了安全性.
即使到目前為止,仍有一些人連基本的惡義SQL語(yǔ)法都不知道.
String sql = "select * from tb_name where name= '"+varname+"' and passwd='"+varpasswd+"'";
如果我們把[' or '1' = '1]作為varpasswd傳入進(jìn)來(lái).用戶名隨意,看看會(huì)成為什么?
select * from tb_name = '隨意' and passwd = '' or '1' = '1';
因?yàn)?1'='1'肯定成立,所以可以任何通過(guò)驗(yàn)證.更有甚者:
把[';drop table tb_name;]作為varpasswd傳入進(jìn)來(lái),則:
select * from tb_name = '隨意' and passwd = '';drop table tb_name;有些數(shù)據(jù)庫(kù)是不會(huì)讓你成功的,但也有很多數(shù)據(jù)庫(kù)就可以使這些語(yǔ)句得到執(zhí)行.
而如果你使用預(yù)編譯語(yǔ)句.你傳入的任何內(nèi)容就不會(huì)和原來(lái)的語(yǔ)句發(fā)生任何匹配的關(guān)系.(前提是數(shù)據(jù)庫(kù)本身支持預(yù)編譯,但上前可能沒(méi)有什么服務(wù)端數(shù)據(jù)庫(kù)不支持編譯了,只有少數(shù)的桌面數(shù)據(jù)庫(kù),就是直接文件訪問(wèn)的那些)只要全使用預(yù)編譯語(yǔ)句,你就用不著對(duì)傳入的數(shù)據(jù)做任何過(guò)慮.而如果使用普通的statement, 有可能要對(duì)drop,;等做費(fèi)盡心機(jī)的判斷和過(guò)慮.
上面的幾個(gè)原因,還不足讓你在任何時(shí)候都使用PreparedStatement嗎?
有的新人可能此時(shí)對(duì)于用法還不太理解下面給個(gè)小例子
Code Fragment 1:
String updateString = "UPDATE COFFEES SET SALES = 75 " + "WHERE COF_NAME LIKE ′Colombian′";
stmt.executeUpdate(updateString);
Code Fragment 2:
PreparedStatement updateSales = con.prepareStatement("UPDATE COFFEES SET SALES = ? WHERE COF_NAME LIKE ? ");
updateSales.setInt(1, 75);
updateSales.setString(2, "Colombian");
updateSales.executeUpdate();
set中的1對(duì)應(yīng)第一個(gè)? 2對(duì)應(yīng)第二個(gè)? 同時(shí)注意你set 的類型 是int還是string 哈哈很簡(jiǎn)單吧
原文出處:http://blog.csdn.net/spcusa/archive/2009/05/09/4164076.aspx
//ValueObject類
//調(diào)用任務(wù)類
//主函數(shù)
個(gè)人賬戶類:
主函數(shù)測(cè)試:
Memcached,人所皆知的remote distribute cache(不知道的可以javaeye一下下,或者google一下下,或者baidu一下下,但是鑒于baidu的排名商業(yè)味道太濃(從最近得某某事件可以看出),所以還是建議javaeye一下下),使用起來(lái)也非常的簡(jiǎn)單,它被用在了很多網(wǎng)站上面,幾乎很少有大型的網(wǎng)站不會(huì)使用memcached。
清零取位要用與,某位置一可用或
若要取反和交換,輕輕松松用異或
移位運(yùn)算
要點(diǎn) 1 它們都是雙目運(yùn)算符,兩個(gè)運(yùn)算分量都是整形,結(jié)果也是整形。
2 "<<" 左移:右邊空出的位上補(bǔ)0,左邊的位將從字頭擠掉,其值相當(dāng)于乘2。
3 ">>"右移:右邊的位被擠掉。對(duì)于左邊移出的空位,如果是正數(shù)則空位補(bǔ)0,若為負(fù)數(shù),可能補(bǔ)0或補(bǔ)1,這取決于所用的計(jì)算機(jī)系統(tǒng)。
4 ">>>"運(yùn)算符,右邊的位被擠掉,對(duì)于左邊移出的空位一概補(bǔ)上0。
位運(yùn)算符的應(yīng)用 (源操作數(shù)s 掩碼mask)
(1) 按位與-- &
1 清零特定位 (mask中特定位置0,其它位為1,s=s&mask)
2 取某數(shù)中指定位 (mask中特定位置1,其它位為0,s=s&mask)
(2) 按位或-- |
常用來(lái)將源操作數(shù)某些位置1,其它位不變。 (mask中特定位置1,其它位為0 s=s|mask)
(3) 位異或-- ^
1 使特定位的值取反 (mask中特定位置1,其它位為0 s=s^mask)
2 不引入第三變量,交換兩個(gè)變量的值 (設(shè) a=a1,b=b1)
目 標(biāo) 操 作 操作后狀態(tài)
a=a1^b1 a=a^b a=a1^b1,b=b1
b=a1^b1^b1 b=a^b a=a1^b1,b=a1
a=b1^a1^a1 a=a^b a=b1,b=a1
二進(jìn)制補(bǔ)碼運(yùn)算公式:
-x = ~x + 1 = ~(x-1)
~x = -x-1
-(~x) = x+1
~(-x) = x-1
x+y = x - ~y - 1 = (x|y)+(x&y)
x-y = x + ~y + 1 = (x|~y)-(~x&y)
x^y = (x|y)-(x&y)
x|y = (x&~y)+y
x&y = (~x|y)-~x
x==y: ~(x-y|y-x)
x!=y: x-y|y-x
x< y: (x-y)^((x^y)&((x-y)^x))
x<=y: (x|~y)&((x^y)|~(y-x))
x< y: (~x&y)|((~x|y)&(x-y))//無(wú)符號(hào)x,y比較
x<=y: (~x|y)&((x^y)|~(y-x))//無(wú)符號(hào)x,y比較
應(yīng)用舉例
(1) 判斷int型變量a是奇數(shù)還是偶數(shù)
a&1 = 0 偶數(shù)
a&1 = 1 奇數(shù)
(2) 取int型變量a的第k位 (k=0,1,2……sizeof(int)),即a>>k&1
(3) 將int型變量a的第k位清0,即a=a&~(1<<k)
(4) 將int型變量a的第k位置1, 即a=a|(1<<k)
(5) int型變量循環(huán)左移k次,即a=a<<k|a>>16-k (設(shè)sizeof(int)=16)
(6) int型變量a循環(huán)右移k次,即a=a>>k|a<<16-k (設(shè)sizeof(int)=16)
(7)整數(shù)的平均值
對(duì)于兩個(gè)整數(shù)x,y,如果用 (x+y)/2 求平均值,會(huì)產(chǎn)生溢出,因?yàn)?x+y 可能會(huì)大于INT_MAX,但是我們知道它們的平均值是肯定不會(huì)溢出的,我們用如下算法:
int average(int x, int y) //返回X,Y 的平均值
{
return (x&y)+((x^y)>>1);
}
(8)判斷一個(gè)整數(shù)是不是2的冪,對(duì)于一個(gè)數(shù) x >= 0,判斷他是不是2的冪
boolean power2(int x)
{
return ((x&(x-1))==0)&&(x!=0);
}
(9)不用temp交換兩個(gè)整數(shù)
void swap(int x , int y)
{
x ^= y;
y ^= x;
x ^= y;
}
(10)計(jì)算絕對(duì)值
int abs( int x )
{
int y ;
y = x >> 31 ;
return (x^y)-y ; //or: (x+y)^y
}
(11)取模運(yùn)算轉(zhuǎn)化成位運(yùn)算 (在不產(chǎn)生溢出的情況下)
a % (2^n) 等價(jià)于 a & (2^n - 1)
(12)乘法運(yùn)算轉(zhuǎn)化成位運(yùn)算 (在不產(chǎn)生溢出的情況下)
a * (2^n) 等價(jià)于 a<< n
(13)除法運(yùn)算轉(zhuǎn)化成位運(yùn)算 (在不產(chǎn)生溢出的情況下)
a / (2^n) 等價(jià)于 a>> n
例: 12/8 == 12>>3
(14) a % 2 等價(jià)于 a & 1
(15) if (x == a) x= b;
else x= a;
等價(jià)于 x= a ^ b ^ x;
(16) x 的 相反數(shù) 表示為 (~x+1)
線程,是指正在執(zhí)行的一個(gè)指點(diǎn)令序列。在java平臺(tái)上是指從一個(gè)線程對(duì)象的start()開(kāi)始。運(yùn)行run方法體中的那一段相對(duì)獨(dú)立的過(guò)程。
在過(guò)去的電腦都已單CPU作為主要的處理方式,無(wú)論是PC或者是服務(wù)器都是如此。系統(tǒng)調(diào)用某一個(gè)時(shí)刻只能有一個(gè)線程運(yùn)行。當(dāng)然這當(dāng)中采用了比較多的策略來(lái)做時(shí)間片輪詢。通過(guò)不斷的調(diào)度切換來(lái)運(yùn)行線程運(yùn)行,而這種方式就叫做并發(fā)(concurrent)。
隨著工藝水平的逐漸提升,CPU的技術(shù)也在不斷增進(jìn)。因此在如今多個(gè)CPU已經(jīng)不是什么特別的,而大家常常以SMP的方式來(lái)形容多個(gè)CPU來(lái)處理兩個(gè)或者兩個(gè)以上的線程運(yùn)行方式就稱為并行(parallel)。
繼承Thread,實(shí)現(xiàn)start()方法
要實(shí)現(xiàn)線程運(yùn)行,JAVA中有兩種方式:
實(shí)現(xiàn)Runnable,然后再傳遞給Thread實(shí)例
注意:線程對(duì)象和線程是兩個(gè)截然不同的概念。
線程對(duì)象是JVM產(chǎn)生的一個(gè)普通的Object子類
線程是CPU分配給這個(gè)對(duì)象的一個(gè)運(yùn)行過(guò)程
public class Test {
public static void main(String[] args) throws Exception{
MyThread mt = new MyThread();
mt.start();
mt.join();
Thread.sleep(3000);
mt.start();
}
}
當(dāng)線程對(duì)象mt運(yùn)行完成后,我們讓主線程休息一下,然后我們?cè)俅卧谶@個(gè)線程對(duì)象上啟動(dòng)線程.結(jié)果我們看到:
Exception in thread "main" java.lang.IllegalThreadStateException
根本原因是在以下源代碼中找出:
public synchronized void start() {
if (started)
throw new IllegalThreadStateException();
started = true;
group.add(this);
start0();
}
一個(gè)Thread的實(shí)例一旦調(diào)用start()方法,這個(gè)實(shí)例的started標(biāo)記就標(biāo)記為true,事實(shí)中不管這個(gè)線程后來(lái)有沒(méi)有執(zhí)行到底,只要調(diào)用了一次start()就再也沒(méi)有機(jī)會(huì)運(yùn)行了,這意味著:
【通過(guò)Thread實(shí)例的start(),一個(gè)Thread的實(shí)例只能產(chǎn)生一個(gè)線程】
當(dāng)一個(gè)線程對(duì)象調(diào)用interrupt()方法,它對(duì)應(yīng)的線程并沒(méi)有被中斷,只是改變了它的中斷狀態(tài)。使當(dāng)前線程的狀態(tài)變以中斷狀態(tài),如果沒(méi)有其它影響,線程還會(huì)自己繼續(xù)執(zhí)行。只有當(dāng)線程執(zhí)行到sleep,wait,join等方法時(shí),或者自己檢查中斷狀態(tài)而拋出異常的情況下,線程才會(huì)拋出異常。
join()方法,正如第一節(jié)所言,在一個(gè)線程對(duì)象上調(diào)用join方法,是當(dāng)前線程等待這個(gè)線程對(duì)象對(duì)應(yīng)的線程結(jié)束
例如:有兩個(gè)工作,工作A要耗時(shí)10秒鐘,工作B要耗時(shí)10秒或更多。我們?cè)诔绦蛑邢壬梢粋€(gè)線程去做工作B,然后做工作A。
new B().start();//做工作B
A();//做工作A
工作A完成后,下面要等待工作B的結(jié)果來(lái)進(jìn)行處理。如果工作B還沒(méi)有完成我就不能進(jìn)行下面的工作C,所以:
B b = new B();
b.start();//做工作B
A();//做工作A
b.join();//等工作B完成.
C();//繼續(xù)工作C
原則:【join是測(cè)試其它工作狀態(tài)的唯一正確方法】
yield()方法也是類方法,只在當(dāng)前線程上調(diào)用,理由同上,它主是讓當(dāng)前線程放棄本次分配到的時(shí)間片,調(diào)用這個(gè)方法不會(huì)提高任何效率,只是降低了CPU的總周期上面介紹的線程一些方法,基于(基礎(chǔ)篇)而言只能簡(jiǎn)單提及。以后具體應(yīng)用中我會(huì)結(jié)合實(shí)例詳細(xì)論述。
原則:【不是非常必要的情況下,沒(méi)有理由調(diào)用它】
首先明確一點(diǎn)他們的屬于普通對(duì)象方法,并非是線程對(duì)象方法;其次它們只能在同步方法中調(diào)用。線程要想調(diào)用一個(gè)對(duì)象的wait()方法就要先獲得該對(duì)象的監(jiān)視鎖,而一旦調(diào)用wait()后又立即釋放該鎖。
多個(gè)線程同時(shí)操作某一對(duì)象時(shí),一個(gè)線程對(duì)該對(duì)象的操作可能會(huì)改變其狀態(tài),而該狀態(tài)會(huì)影響另一線程對(duì)該對(duì)象的真正結(jié)果。
把一個(gè)單元聲明為synchornized,就可以讓在同一時(shí)間只有一個(gè)線程操作該方法。作為記憶可以把synchronized看作是一個(gè)鎖。但是我們要理解鎖是被動(dòng)的,還是主動(dòng)的呢?換而言之它到底鎖什么了?鎖誰(shuí)了?
例如:
synchronized(obj){
//todo…
}
如果代碼運(yùn)行到此處,synchronized首先獲取obj參數(shù)對(duì)象的鎖,若沒(méi)有獲取線程只能等待,如果多個(gè)線程運(yùn)行到這只能有一個(gè)線程獲取obj的鎖,然后再執(zhí)行{}中的代碼。因此obj作用范圍不同,控制程序也不同。
如果一個(gè)方法聲明為synchornized的,則等同于把在為個(gè)方法上調(diào)用synchornized(this)。
如果一個(gè)靜態(tài)方法被聲明為synchornized,則等同于把在為個(gè)方法上調(diào)用synchornized(類.class)
要讓一個(gè)線程得到真正意義的停止,需要了解當(dāng)前的線程在干什么,如果線程當(dāng)前沒(méi)有做什么,那立刻讓對(duì)方退出,當(dāng)然是沒(méi)有任何問(wèn)題,但是如果對(duì)方正在手頭趕工,那就必須讓他停止,然后收拾殘局。因此,首先需要了解步驟:
1. 正常運(yùn)行;
2. 處理結(jié)束前的工作,也就是準(zhǔn)備結(jié)束;
3. 結(jié)束退出。
注:以上部分概括出自某位牛人大哥的筆記,經(jīng)常拜讀他的博客對(duì)于這本書(shū)的閱讀,說(shuō)來(lái)也很慚愧。過(guò)去黎敏基本對(duì)于他翻譯過(guò)的書(shū),都有郵寄送給我,書(shū)拿到手后,都是內(nèi)心的高興——哇,不用花錢的書(shū),爽!(自己YY下)唯一要求就是能夠讀后能寫(xiě)個(gè)讀后感,但是很多次都抱歉的忽悠了他。盡管如此他這次翻譯的書(shū)還是一如既往的郵寄給我(當(dāng)然也是在我厚臉皮的去索要的前提下,哈哈),同樣答應(yīng)寫(xiě)一篇讀后感,可是遲到的讀后感一直到現(xiàn)在才肯出爐,確實(shí)有點(diǎn)對(duì)不住他。這本書(shū)是在我每天早早擠車一個(gè)星期多讀出來(lái)的,那個(gè)汽車真叫熱啊,嘿嘿。切入正題,談?wù)剬?duì)于本書(shū)的一個(gè)看法和意見(jiàn)。
這本書(shū)整體風(fēng)格基本還是沿襲了第一版本的套路,把每個(gè)重點(diǎn)都寫(xiě)成一個(gè)條目來(lái)針對(duì)性的闡述,本書(shū)總共條目為七十八條(第一版書(shū)共有五十七條)。當(dāng)中很多是在JDK5基礎(chǔ)上作為第一版的更新(與第一版比較明顯特征是把原有第一版的第五章,第六章的結(jié)構(gòu)化特征和方法換成JDK5的新特性:泛型,枚舉,方法)。
這本書(shū)我到現(xiàn)在都懷疑出版社沒(méi)有花很多時(shí)間在排版上,為什么這么說(shuō)?在黎敏在翻譯階段也就有拿書(shū)的樣稿給我看過(guò),我第一看到就是封面問(wèn)題——居然是黃色的,當(dāng)時(shí)就跟他提出來(lái),這個(gè)需要他和出版社去很好的斟酌一番。當(dāng)時(shí)黎敏也說(shuō)已經(jīng)跟出版社商量過(guò),哪知道最后拿到手上的居然還是“黃色”。可見(jiàn)出版社不知道是出于什么來(lái)考慮,讓我來(lái)猜想下:難道是怕大伙都是色盲非要用黃色來(lái)提醒大家嗎?更為失望的居然標(biāo)題使用紅色,暈啊!其次就要說(shuō)書(shū)紙張也未免太扯淡了吧?我第一感覺(jué)紙張就是草稿紙一般,實(shí)在無(wú)語(yǔ)。在代碼處理方面,顯得不如第一版的那種爽朗,是不是出版社考慮節(jié)省紙張啊?非要把很多代碼的間隔弄的特小,這樣對(duì)于可讀性來(lái)說(shuō)確實(shí)很有疲勞感。所以這里向提醒以后的出版社——你忽悠是可以,但是別把讀者當(dāng)傻瓜。
上面是談到在書(shū)的編排和效果的問(wèn)題。現(xiàn)在談?wù)剷?shū)中內(nèi)容的一些感受。整體上說(shuō)書(shū)翻譯還是可以,不過(guò)當(dāng)中也不乏一些乏味用詞過(guò)當(dāng)?shù)膯?wèn)題,這里要說(shuō)到最明顯的就是書(shū)中出現(xiàn)很多在每一個(gè)條目后的總結(jié)詞匯都或多或少帶有“本條目”一詞,個(gè)人覺(jué)得偶爾寫(xiě)寫(xiě)是沒(méi)很大問(wèn)題,但是過(guò)多重復(fù)顯得機(jī)械化的審美疲勞,甚至有時(shí)候過(guò)多這樣的詞匯對(duì)于閱讀流暢性稍微欠佳。像這樣類似的詞匯還有——“不嚴(yán)格地講”,“簡(jiǎn)而言之”,這些詞匯確實(shí)稍微影響閱讀感。這里小糾下不爽或者錯(cuò)誤的位置:P240處第二段第三行和第四行中出現(xiàn)兩個(gè)“現(xiàn)在”,這個(gè)可能在校正時(shí)沒(méi)有很好去潤(rùn)色。P216倒數(shù)第二段第三行有一個(gè)估計(jì)是印刷錯(cuò)誤:【原】?jī)H僅一個(gè)異常就會(huì)導(dǎo)致該方法不得不外于… 如果沒(méi)有錯(cuò)的話,這個(gè)字應(yīng)該是:處。
還有類似第二章談到的:靜態(tài)工廠方法與構(gòu)造器不同的第三的優(yōu)勢(shì)在于,它們可以返回原返回類型的任何子類型的對(duì)象。就這句話,老實(shí)講我真看了很久才明白啥意思。
以上是談到一些不足的細(xì)微之處,不過(guò)閱讀此書(shū)后,確實(shí)對(duì)于以前一些不起眼的所謂了解語(yǔ)法也很好的得到一次重新的認(rèn)識(shí)。比如以前在使用非檢測(cè)警告上,以前很習(xí)慣的直接在整個(gè)類上直接使用標(biāo)記表示;對(duì)于了解for-each的循環(huán)上得到進(jìn)一步的認(rèn)識(shí);對(duì)于枚舉類型的使用上更加靈活。這些都是個(gè)人對(duì)于此書(shū)泛讀之后的一些淺薄的看法。如果對(duì)于譯者有不敬之處還望原諒!
摘要: Xml Schema的用途 1. 定義一個(gè)Xml文檔中都有什么元素 2. 定義一個(gè)Xml文檔中都會(huì)有什么屬性 3. 定義某個(gè)節(jié)點(diǎn)的都有什么樣的子節(jié)點(diǎn),可以有多少個(gè)子節(jié)點(diǎn),子節(jié)點(diǎn)出現(xiàn)的順序 4. 定義元素或者屬性的數(shù)據(jù)類型 5. 定義元素或者屬性的默認(rèn)值或者固定值 Xml Schema的根元素: <?xml version="1.... 閱讀全文 引言HTTP是一個(gè)屬于應(yīng)用層的面向?qū)ο蟮膮f(xié)議,由于其簡(jiǎn)捷、快速的方式,適用于分布式超媒體信息系統(tǒng)。它于1990年提出,經(jīng)過(guò)幾年的
使用與發(fā)展,得到不斷地完善和擴(kuò)展。目前在WWW中使用的是HTTP/1.0的第六版,HTTP/1.1的規(guī)范化工作正在進(jìn)行之中,而且HTTP-
NG(Next Generation of HTTP)的建議已經(jīng)提出。
HTTP協(xié)議的主要特點(diǎn)可概括如下:
1.支持客戶/服務(wù)器模式。
2.簡(jiǎn)單快速:客戶向服務(wù)器請(qǐng)求服務(wù)時(shí),只需傳送請(qǐng)求方法和路徑。請(qǐng)求方法常用的有GET、HEAD、POST。每種方法規(guī)定了客戶與服
務(wù)器聯(lián)系的類型不同。由于HTTP協(xié)議簡(jiǎn)單,使得HTTP服務(wù)器的程序規(guī)模小,因而通信速度很快。
3.靈活:HTTP允許傳輸任意類型的數(shù)據(jù)對(duì)象。正在傳輸?shù)念愋陀蒀ontent-Type加以標(biāo)記。
4.無(wú)連接:無(wú)連接的含義是限制每次連接只處理一個(gè)請(qǐng)求。服務(wù)器處理完客戶的請(qǐng)求,并收到客戶的應(yīng)答后,即斷開(kāi)連接。采用這種方
式可以節(jié)省傳輸時(shí)間。
5.無(wú)狀態(tài):HTTP協(xié)議是無(wú)狀態(tài)協(xié)議。無(wú)狀態(tài)是指協(xié)議對(duì)于事務(wù)處理沒(méi)有記憶能力。缺少狀態(tài)意味著如果后續(xù)處理需要前面的信息,則
它必須重傳,這樣可能導(dǎo)致每次連接傳送的數(shù)據(jù)量增大。另一方面,在服務(wù)器不需要先前信息時(shí)它的應(yīng)答就較快。
一、HTTP協(xié)議詳解之URL篇
http(超文本傳輸協(xié)議)是一個(gè)基于請(qǐng)求與響應(yīng)模式的、無(wú)狀態(tài)的、應(yīng)用層的協(xié)議,常基于TCP的連接方
式,HTTP1.1版本中給出一種持續(xù)連接的機(jī)制,絕大多數(shù)的Web開(kāi)發(fā),都是構(gòu)建在HTTP協(xié)議之上的Web應(yīng)用。
HTTP URL (URL是一種特殊類型的URI,包含了用于查找某個(gè)資源的足夠的信息)的格式如下:
http://host[":"port][abs_path]
http表示要通過(guò)HTTP協(xié)議來(lái)定位網(wǎng)絡(luò)資源;host表示合法的Internet主機(jī)域名或者IP地址;port指定一個(gè)端口號(hào),
為空則使用缺省端口80;abs_path指定請(qǐng)求資源的URI;如果URL中沒(méi)有給出abs_path,那么當(dāng)它作為請(qǐng)求URI
時(shí),必須以“/”的形式給出,通常這個(gè)工作瀏覽器自動(dòng)幫我們完成。
eg:
1、輸入:www.guet.edu.cn
瀏覽器自動(dòng)轉(zhuǎn)換成:http://www.guet.edu.cn/
2、http:192.168.0.116:8080/index.jsp
二、HTTP協(xié)議詳解之請(qǐng)求篇
http請(qǐng)求由三部分組成,分別是:請(qǐng)求行、消息報(bào)頭、請(qǐng)求正文
1、請(qǐng)求行以一個(gè)方法符號(hào)開(kāi)頭,以空格分開(kāi),后面跟著請(qǐng)求的URI和協(xié)議的版本,格式如下:Method Request-
URI HTTP-Version CRLF
其中 Method表示請(qǐng)求方法;Request-URI是一個(gè)統(tǒng)一資源標(biāo)識(shí)符;HTTP-Version表示請(qǐng)求的HTTP協(xié)議版本;
CRLF表示回車和換行(除了作為結(jié)尾的CRLF外,不允許出現(xiàn)單獨(dú)的CR或LF字符)。
請(qǐng)求方法(所有方法全為大寫(xiě))有多種,各個(gè)方法的解釋如下:
GET 請(qǐng)求獲取Request-URI所標(biāo)識(shí)的資源
POST 在Request-URI所標(biāo)識(shí)的資源后附加新的數(shù)據(jù)
HEAD 請(qǐng)求獲取由Request-URI所標(biāo)識(shí)的資源的響應(yīng)消息報(bào)頭
PUT 請(qǐng)求服務(wù)器存儲(chǔ)一個(gè)資源,并用Request-URI作為其標(biāo)識(shí)
DELETE 請(qǐng)求服務(wù)器刪除Request-URI所標(biāo)識(shí)的資源
TRACE 請(qǐng)求服務(wù)器回送收到的請(qǐng)求信息,主要用于測(cè)試或診斷
CONNECT 保留將來(lái)使用
OPTIONS 請(qǐng)求查詢服務(wù)器的性能,或者查詢與資源相關(guān)的選項(xiàng)和需求
應(yīng)用舉例:
GET方法:在瀏覽器的地址欄中輸入網(wǎng)址的方式訪問(wèn)網(wǎng)頁(yè)時(shí),瀏覽器采用GET方法向服務(wù)器獲取資源,
eg:GET /form.html HTTP/1.1 (CRLF)
POST方法要求被請(qǐng)求服務(wù)器接受附在請(qǐng)求后面的數(shù)據(jù),常用于提交表單。
eg:POST /reg.jsp HTTP/ (CRLF)
Accept:image/gif,image/x-xbit,... (CRLF)
...
HOST:www.guet.edu.cn (CRLF)
Content-Length:22 (CRLF)
Connection:Keep-Alive (CRLF)
Cache-Control:no-cache (CRLF)
(CRLF) //該CRLF表示消息報(bào)頭已經(jīng)結(jié)束,在此之前為消息報(bào)頭
user=jeffrey&pwd=1234 //此行以下為提交的數(shù)據(jù)
HEAD方法與GET方法幾乎是一樣的,對(duì)于HEAD請(qǐng)求的回應(yīng)部分來(lái)說(shuō),它的HTTP頭部中包含的信息與通過(guò)
GET請(qǐng)求所得到的信息是相同的。利用這個(gè)方法,不必傳輸整個(gè)資源內(nèi)容,就可以得到Request-URI所標(biāo)識(shí)的資
源的信息。該方法常用于測(cè)試超鏈接的有效性,是否可以訪問(wèn),以及最近是否更新。
2、請(qǐng)求報(bào)頭后述
3、請(qǐng)求正文(略)
三、HTTP協(xié)議詳解之響應(yīng)篇
在接收和解釋請(qǐng)求消息后,服務(wù)器返回一個(gè)HTTP響應(yīng)消息。
HTTP響應(yīng)也是由三個(gè)部分組成,分別是:狀態(tài)行、消息報(bào)頭、響應(yīng)正文
1、狀態(tài)行格式如下:
HTTP-Version Status-Code Reason-Phrase CRLF
其中,HTTP-Version表示服務(wù)器HTTP協(xié)議的版本;Status-Code表示服務(wù)器發(fā)回的響應(yīng)狀態(tài)代碼;Reason-Phrase
表示狀態(tài)代碼的文本描述。
狀態(tài)代碼有三位數(shù)字組成,第一個(gè)數(shù)字定義了響應(yīng)的類別,且有五種可能取值:
1xx:指示信息--表示請(qǐng)求已接收,繼續(xù)處理
2xx:成功--表示請(qǐng)求已被成功接收、理解、接受
3xx:重定向--要完成請(qǐng)求必須進(jìn)行更進(jìn)一步的操作
4xx:客戶端錯(cuò)誤--請(qǐng)求有語(yǔ)法錯(cuò)誤或請(qǐng)求無(wú)法實(shí)現(xiàn)
5xx:服務(wù)器端錯(cuò)誤--服務(wù)器未能實(shí)現(xiàn)合法的請(qǐng)求
常見(jiàn)狀態(tài)代碼、狀態(tài)描述、說(shuō)明:
200 OK //客戶端請(qǐng)求成功
400 Bad Request //客戶端請(qǐng)求有語(yǔ)法錯(cuò)誤,不能被服務(wù)器所理解
401 Unauthorized //請(qǐng)求未經(jīng)授權(quán),這個(gè)狀態(tài)代碼必須和WWW-Authenticate報(bào) //頭域一起使用
403 Forbidden //服務(wù)器收到請(qǐng)求,但是拒絕提供服務(wù)
404 Not Found //請(qǐng)求資源不存在,eg:輸入了錯(cuò)誤的URL
500 Internal Server Error //服務(wù)器發(fā)生不可預(yù)期的錯(cuò)誤
503 Server Unavailable //服務(wù)器當(dāng)前不能處理客戶端的請(qǐng)求,一段時(shí)間后, //可能恢復(fù)正常
eg:HTTP/1.1 200 OK (CRLF)
2、響應(yīng)報(bào)頭后述
3、響應(yīng)正文就是服務(wù)器返回的資源的內(nèi)容
四、HTTP協(xié)議詳解之消息報(bào)頭篇
HTTP消息由客戶端到服務(wù)器的請(qǐng)求和服務(wù)器到客戶端的響應(yīng)組成。請(qǐng)求消息和響應(yīng)消息都是由開(kāi)始行(對(duì)
于請(qǐng)求消息,開(kāi)始行就是請(qǐng)求行,對(duì)于響應(yīng)消息,開(kāi)始行就是狀態(tài)行),消息報(bào)頭(可選),空行(只有
CRLF的行),消息正文(可選)組成。
HTTP消息報(bào)頭包括普通報(bào)頭、請(qǐng)求報(bào)頭、響應(yīng)報(bào)頭、實(shí)體報(bào)頭。
每一個(gè)報(bào)頭域都是由名字+“:”+空格+值 組成,消息報(bào)頭域的名字是大小寫(xiě)無(wú)關(guān)的。
1、普通報(bào)頭
在普通報(bào)頭中,有少數(shù)報(bào)頭域用于所有的請(qǐng)求和響應(yīng)消息,但并不用于被傳輸?shù)膶?shí)體,只用于傳輸?shù)南ⅰ?br />
eg:
Cache-Control 用于指定緩存指令,緩存指令是單向的(響應(yīng)中出現(xiàn)的緩存指令在請(qǐng)求中未必會(huì)出現(xiàn)),且是
獨(dú)立的(一個(gè)消息的緩存指令不會(huì)影響另一個(gè)消息處理的緩存機(jī)制),HTTP1.0使用的類似的報(bào)頭域?yàn)镻ragma。
請(qǐng)求時(shí)的緩存指令包括:no-cache(用于指示請(qǐng)求或響應(yīng)消息不能緩存)、no-store、max-age、max-stale、min-
fresh、only-if-cached;
響應(yīng)時(shí)的緩存指令包括:public、private、no-cache、no-store、no-transform、must-revalidate、proxy-revalidate、
max-age、s-maxage.
eg:為了指示IE瀏覽器(客戶端)不要緩存頁(yè)面,服務(wù)器端的JSP程序可以編寫(xiě)如下:response.sehHeader
("Cache-Control","no-cache");
//response.setHeader("Pragma","no-cache");作用相當(dāng)于上述代碼,通常兩者//合用
這句代碼將在發(fā)送的響應(yīng)消息中設(shè)置普通報(bào)頭域:Cache-Control:no-cache
Date普通報(bào)頭域表示消息產(chǎn)生的日期和時(shí)間
Connection普通報(bào)頭域允許發(fā)送指定連接的選項(xiàng)。例如指定連接是連續(xù),或者指定“close”選項(xiàng),通知服務(wù)
器,在響應(yīng)完成后,關(guān)閉連接
2、請(qǐng)求報(bào)頭
請(qǐng)求報(bào)頭允許客戶端向服務(wù)器端傳遞請(qǐng)求的附加信息以及客戶端自身的信息。
常用的請(qǐng)求報(bào)頭
Accept
Accept請(qǐng)求報(bào)頭域用于指定客戶端接受哪些類型的信息。eg:Accept:image/gif,表明客戶端希望接受GIF圖象
格式的資源;Accept:text/html,表明客戶端希望接受html文本。
Accept-Charset
Accept-Charset請(qǐng)求報(bào)頭域用于指定客戶端接受的字符集。eg:Accept-Charset:iso-8859-1,gb2312.如果在請(qǐng)求消
息中沒(méi)有設(shè)置這個(gè)域,缺省是任何字符集都可以接受。
Accept-Encoding
Accept-Encoding請(qǐng)求報(bào)頭域類似于Accept,但是它是用于指定可接受的內(nèi)容編碼。eg:Accept-Encoding:gzip.deflate.如果請(qǐng)求消息中沒(méi)有設(shè)置這個(gè)域服務(wù)器假定客戶端對(duì)各種內(nèi)容編碼都可以接受。
Accept-Language
Accept-Language請(qǐng)求報(bào)頭域類似于Accept,但是它是用于指定一種自然語(yǔ)言。eg:Accept-Language:zh-cn.如果請(qǐng)
求消息中沒(méi)有設(shè)置這個(gè)報(bào)頭域,服務(wù)器假定客戶端對(duì)各種語(yǔ)言都可以接受。
Authorization
Authorization請(qǐng)求報(bào)頭域主要用于證明客戶端有權(quán)查看某個(gè)資源。當(dāng)瀏覽器訪問(wèn)一個(gè)頁(yè)面時(shí),如果收到服務(wù)器
的響應(yīng)代碼為401(未授權(quán)),可以發(fā)送一個(gè)包含Authorization請(qǐng)求報(bào)頭域的請(qǐng)求,要求服務(wù)器對(duì)其進(jìn)行驗(yàn)證。
Host(發(fā)送請(qǐng)求時(shí),該報(bào)頭域是必需的)
Host請(qǐng)求報(bào)頭域主要用于指定被請(qǐng)求資源的Internet主機(jī)和端口號(hào),它通常從HTTP URL中提取出來(lái)的,eg:
我們?cè)跒g覽器中輸入:http://www.guet.edu.cn/index.html
瀏覽器發(fā)送的請(qǐng)求消息中,就會(huì)包含Host請(qǐng)求報(bào)頭域,如下:
Host:www.guet.edu.cn
此處使用缺省端口號(hào)80,若指定了端口號(hào),則變成:Host:www.guet.edu.cn:指定端口號(hào)
User-Agent
我們上網(wǎng)登陸論壇的時(shí)候,往往會(huì)看到一些歡迎信息,其中列出了你的操作系統(tǒng)的名稱和版本,你所使用的
瀏覽器的名稱和版本,這往往讓很多人感到很神奇,實(shí)際上,服務(wù)器應(yīng)用程序就是從User-Agent這個(gè)請(qǐng)求報(bào)頭
域中獲取到這些信息。User-Agent請(qǐng)求報(bào)頭域允許客戶端將它的操作系統(tǒng)、瀏覽器和其它屬性告訴服務(wù)器。不
過(guò),這個(gè)報(bào)頭域不是必需的,如果我們自己編寫(xiě)一個(gè)瀏覽器,不使用User-Agent請(qǐng)求報(bào)頭域,那么服務(wù)器端就
無(wú)法得知我們的信息了。
請(qǐng)求報(bào)頭舉例:
GET /form.html HTTP/1.1 (CRLF)
Accept:image/gif,image/x-xbitmap,image/jpeg,application/x-shockwave-flash,application/vnd.ms-excel,application/vnd.ms-
powerpoint,application/msword,*/* (CRLF)
Accept-Language:zh-cn (CRLF)
Accept-Encoding:gzip,deflate (CRLF)
If-Modified-Since:Wed,05 Jan 2007 11:21:25 GMT (CRLF)
If-None-Match:W/"80b1a4c018f3c41:8317" (CRLF)
User-Agent:Mozilla/4.0(compatible;MSIE6.0;Windows NT 5.0) (CRLF)
Host:www.guet.edu.cn (CRLF)
Connection:Keep-Alive (CRLF)
(CRLF)
3、響應(yīng)報(bào)頭
響應(yīng)報(bào)頭允許服務(wù)器傳遞不能放在狀態(tài)行中的附加響應(yīng)信息,以及關(guān)于服務(wù)器的信息和對(duì)Request-URI所標(biāo)識(shí)
的資源進(jìn)行下一步訪問(wèn)的信息。
常用的響應(yīng)報(bào)頭
Location
Location響應(yīng)報(bào)頭域用于重定向接受者到一個(gè)新的位置。Location響應(yīng)報(bào)頭域常用在更換域名的時(shí)候。
Server
Server響應(yīng)報(bào)頭域包含了服務(wù)器用來(lái)處理請(qǐng)求的軟件信息。與User-Agent請(qǐng)求報(bào)頭域是相對(duì)應(yīng)的。下面是
Server響應(yīng)報(bào)頭域的一個(gè)例子:
Server:Apache-Coyote/1.1
WWW-Authenticate
WWW-Authenticate響應(yīng)報(bào)頭域必須被包含在401(未授權(quán)的)響應(yīng)消息中,客戶端收到401響應(yīng)消息時(shí)候,并發(fā)
送Authorization報(bào)頭域請(qǐng)求服務(wù)器對(duì)其進(jìn)行驗(yàn)證時(shí),服務(wù)端響應(yīng)報(bào)頭就包含該報(bào)頭域。
eg:WWW-Authenticate:Basic realm="Basic Auth Test!" //可以看出服務(wù)器對(duì)請(qǐng)求資源采用的是基本驗(yàn)證機(jī)制。
4、實(shí)體報(bào)頭
請(qǐng)求和響應(yīng)消息都可以傳送一個(gè)實(shí)體。一個(gè)實(shí)體由實(shí)體報(bào)頭域和實(shí)體正文組成,但并不是說(shuō)實(shí)體報(bào)頭域和實(shí)體正文要在一起發(fā)送,可以只發(fā)送實(shí)體報(bào)頭域。實(shí)體報(bào)頭定義了關(guān)于實(shí)體正文(eg:有無(wú)實(shí)體正文)和請(qǐng)求所標(biāo)識(shí)的資源的元信息。
常用的實(shí)體報(bào)頭
Content-Encoding
Content-Encoding實(shí)體報(bào)頭域被用作媒體類型的修飾符,它的值指示了已經(jīng)被應(yīng)用到實(shí)體正文的附加內(nèi)容的編
碼,因而要獲得Content-Type報(bào)頭域中所引用的媒體類型,必須采用相應(yīng)的解碼機(jī)制。Content-Encoding這樣用
于記錄文檔的壓縮方法,eg:Content-Encoding:gzip
Content-Language
Content-Language實(shí)體報(bào)頭域描述了資源所用的自然語(yǔ)言。沒(méi)有設(shè)置該域則認(rèn)為實(shí)體內(nèi)容將提供給所有的語(yǔ)言
閱讀
者。eg:Content-Language:da
Content-Length
Content-Length實(shí)體報(bào)頭域用于指明實(shí)體正文的長(zhǎng)度,以字節(jié)方式存儲(chǔ)的十進(jìn)制數(shù)字來(lái)表示。
Content-Type
Content-Type實(shí)體報(bào)頭域用語(yǔ)指明發(fā)送給接收者的實(shí)體正文的媒體類型。eg:
Content-Type:text/html;charset=ISO-8859-1
Content-Type:text/html;charset=GB2312
Last-Modified
Last-Modified實(shí)體報(bào)頭域用于指示資源的最后修改日期和時(shí)間。
Expires
Expires實(shí)體報(bào)頭域給出響應(yīng)過(guò)期的日期和時(shí)間。為了讓代理服務(wù)器或?yàn)g覽器在一段時(shí)間以后更新緩存中(再次
訪問(wèn)曾訪問(wèn)過(guò)的頁(yè)面時(shí),直接從緩存中加載,縮短響應(yīng)時(shí)間和降低服務(wù)器負(fù)載)的頁(yè)面,我們可以使用Expires
實(shí)體報(bào)頭域指定頁(yè)面過(guò)期的時(shí)間。eg:Expires:Thu,15 Sep 2006 16:23:12 GMT
HTTP1.1的客戶端和緩存必須將其他非法的日期格式(包括0)看作已經(jīng)過(guò)期。eg:為了讓瀏覽器不要緩存頁(yè)
面,我們也可以利用Expires實(shí)體報(bào)頭域,設(shè)置為0,jsp中程序如下:response.setDateHeader("Expires","0");
五、利用telnet觀察http協(xié)議的通訊過(guò)程
實(shí)驗(yàn)?zāi)康募霸恚?br />
利用MS的telnet工具,通過(guò)手動(dòng)輸入http請(qǐng)求信息的方式,向服務(wù)器發(fā)出請(qǐng)求,服務(wù)器接收、解釋和接受請(qǐng)求
后,會(huì)返回一個(gè)響應(yīng),該響應(yīng)會(huì)在telnet窗口上顯示出來(lái),從而從感性上加深對(duì)http協(xié)議的通訊過(guò)程的認(rèn)識(shí)。
實(shí)驗(yàn)步驟:
1、打開(kāi)telnet
1.1 打開(kāi)telnet
運(yùn)行-->cmd-->telnet
1.2 打開(kāi)telnet回顯功能
set localecho
2、連接服務(wù)器并發(fā)送請(qǐng)求
2.1 open www.guet.edu.cn 80 //注意端口號(hào)不能省略
HEAD /index.asp HTTP/1.0
Host:www.guet.edu.cn
/*我們可以變換請(qǐng)求方法,請(qǐng)求桂林電子主頁(yè)內(nèi)容,輸入消息如下*/
open www.guet.edu.cn 80
GET /index.asp HTTP/1.0 //請(qǐng)求資源的內(nèi)容
Host:www.guet.edu.cn
2.2 open www.sina.com.cn 80 //在命令提示符號(hào)下直接輸入telnet www.sina.com.cn 80
HEAD /index.asp HTTP/1.0
Host:www.sina.com.cn
3 實(shí)驗(yàn)結(jié)果:
3.1 請(qǐng)求信息2.1得到的響應(yīng)是:
HTTP/1.1 200 OK //請(qǐng)求成功
Server: Microsoft-IIS/5.0 //web服務(wù)器
Date: Thu,08 Mar 200707:17:51 GMT
Connection: Keep-Alive
Content-Length: 23330
Content-Type: text/html
Expries: Thu,08 Mar 2007 07:16:51 GMT
Set-Cookie: ASPSESSIONIDQAQBQQQB=BEJCDGKADEDJKLKKAJEOIMMH; path=/
Cache-control: private
//資源內(nèi)容省略
3.2 請(qǐng)求信息2.2得到的響應(yīng)是:
HTTP/1.0 404 Not Found //請(qǐng)求失敗
Date: Thu, 08 Mar 2007 07:50:50 GMT
Server: Apache/2.0.54 <Unix>
Last-Modified: Thu, 30 Nov 2006 11:35:41 GMT
ETag: "6277a-415-e7c76980"
Accept-Ranges: bytes
X-Powered-By: mod_xlayout_jh/0.0.1vhs.markII.remix
Vary: Accept-Encoding
Content-Type: text/html
X-Cache: MISS from zjm152-78.sina.com.cn
Via: 1.0 zjm152-78.sina.com.cn:80<squid/2.6.STABLES-20061207>
X-Cache: MISS from th-143.sina.com.cn
Connection: close
失去了跟主機(jī)的連接
按任意鍵繼續(xù)...
4 .注意事項(xiàng):1、出現(xiàn)輸入錯(cuò)誤,則請(qǐng)求不會(huì)成功。
2、報(bào)頭域不分大小寫(xiě)。
3、更深一步了解HTTP協(xié)議,可以查看RFC2616,在http://www.letf.org/rfc上找到該文件。
4、開(kāi)發(fā)后臺(tái)程序必須掌握http協(xié)議
六、HTTP協(xié)議相關(guān)技術(shù)補(bǔ)充
1、基礎(chǔ):
高層協(xié)議有:文件傳輸協(xié)議FTP、電子郵件傳輸協(xié)議SMTP、域名系統(tǒng)服務(wù)DNS、網(wǎng)絡(luò)新聞傳輸協(xié)議NNTP和
HTTP協(xié)議等
中介由三種:代理(Proxy)、網(wǎng)關(guān)(Gateway)和通道(Tunnel),一個(gè)代理根據(jù)URI的絕對(duì)格式來(lái)接受請(qǐng)求,重寫(xiě)全部
或部分消息,通過(guò) URI的標(biāo)識(shí)把已格式化過(guò)的請(qǐng)求發(fā)送到服務(wù)器。網(wǎng)關(guān)是一個(gè)接收代理,作為一些其它服務(wù)
器的上層,并且如果必須的話,可以把請(qǐng)求翻譯給下層的服務(wù)器協(xié)議。一 個(gè)通道作為不改變消息的兩個(gè)連接
之間的中繼點(diǎn)。當(dāng)通訊需要通過(guò)一個(gè)中介(例如:防火墻等)或者是中介不能識(shí)別消息的內(nèi)容時(shí),通道經(jīng)常被使
用。
代理(Proxy):一個(gè)中間程序,它可以充當(dāng)一個(gè)服務(wù)器,也可以充當(dāng)一個(gè)客戶機(jī),為其它客戶機(jī)建立請(qǐng)求。
請(qǐng)求是通過(guò)可能的翻譯在內(nèi)部或經(jīng)過(guò)傳遞到其它的 服務(wù)器中。一個(gè)代理在發(fā)送請(qǐng)求信息之前,必須解釋并且
如果可能重寫(xiě)它。代理經(jīng)常作為通過(guò)防火墻的客戶機(jī)端的門戶,代理還可以作為一個(gè)幫助應(yīng)用來(lái)通過(guò)協(xié)議處
理沒(méi)有被用戶代理完成的請(qǐng)求。
網(wǎng)關(guān)(Gateway):一個(gè)作為其它服務(wù)器中間媒介的服務(wù)器。與代理不同的是,網(wǎng)關(guān)接受請(qǐng)求就好象對(duì)被請(qǐng)求的
資源來(lái)說(shuō)它就是源服務(wù)器;發(fā)出請(qǐng)求的客戶機(jī)并沒(méi)有意識(shí)到它在同網(wǎng)關(guān)打交道。
網(wǎng)關(guān)經(jīng)常作為通過(guò)防火墻的服務(wù)器端的門戶,網(wǎng)關(guān)還可以作為一個(gè)協(xié)議翻譯器以便存取那些存儲(chǔ)在非
HTTP系統(tǒng)中的資源。
通道(Tunnel):是作為兩個(gè)連接中繼的中介程序。一旦激活,通道便被認(rèn)為不屬于HTTP通訊,盡管通道可能
是被一個(gè)HTTP請(qǐng)求初始化的。當(dāng)被中繼 的連接兩端關(guān)閉時(shí),通道便消失。當(dāng)一個(gè)門戶(Portal)必須存在或中介
(Intermediary)不能解釋中繼的通訊時(shí)通道被經(jīng)常使用。
2、協(xié)議分析的優(yōu)勢(shì)—HTTP分析器檢測(cè)網(wǎng)絡(luò)攻擊
以模塊化的方式對(duì)高層協(xié)議進(jìn)行分析處理,將是未來(lái)入侵檢測(cè)的方向。
HTTP及其代理的常用端口80、3128和8080在network部分用port標(biāo)簽進(jìn)行了規(guī)定
3、HTTP協(xié)議Content Lenth限制漏洞導(dǎo)致拒絕服務(wù)攻擊
使用POST方法時(shí),可以設(shè)置ContentLenth來(lái)定義需要傳送的數(shù)據(jù)長(zhǎng)度,例如ContentLenth:999999999,在傳送完
成前,內(nèi) 存不會(huì)釋放,攻擊者可以利用這個(gè)缺陷,連續(xù)向WEB服務(wù)器發(fā)送垃圾數(shù)據(jù)直至WEB服務(wù)器內(nèi)存耗
盡。這種攻擊方法基本不會(huì)留下痕跡。
http://www.cnpaf.net/Class/HTTP/0532918532667330.html
4、利用HTTP協(xié)議的特性進(jìn)行拒絕服務(wù)攻擊的一些構(gòu)思
服務(wù)器端忙于處理攻擊者偽造的TCP連接請(qǐng)求而無(wú)暇理睬客戶的正常請(qǐng)求(畢竟客戶端的正常請(qǐng)求比率非常之
小),此時(shí)從正常客戶的角度看來(lái),服務(wù)器失去響應(yīng),這種情況我們稱作:服務(wù)器端受到了SYNFlood攻擊(SYN洪水攻擊)。
而Smurf、TearDrop等是利用ICMP報(bào)文來(lái)Flood和IP碎片攻擊的。本文用“正常連接”的方法來(lái)產(chǎn)生拒絕服務(wù)攻擊。
19端口在早期已經(jīng)有人用來(lái)做Chargen攻擊了,即Chargen_Denial_of_Service,但是!他們用的方法是在兩臺(tái)
Chargen 服務(wù)器之間產(chǎn)生UDP連接,讓服務(wù)器處理過(guò)多信息而DOWN掉,那么,干掉一臺(tái)WEB服務(wù)器的條件就
必須有2個(gè):1.有Chargen服務(wù)2.有HTTP 服務(wù)
方法:攻擊者偽造源IP給N臺(tái)Chargen發(fā)送連接請(qǐng)求(Connect),Chargen接收到連接后就會(huì)返回每秒72字節(jié)的
字符流(實(shí)際上根據(jù)網(wǎng)絡(luò)實(shí)際情況,這個(gè)速度更快)給服務(wù)器。
5、Http指紋識(shí)別技術(shù)
Http指紋識(shí)別的原理大致上也是相同的:記錄不同服務(wù)器對(duì)Http協(xié)議執(zhí)行中的微小差別進(jìn)行識(shí)別.Http指紋識(shí)
別比TCP/IP堆棧指紋識(shí)別復(fù)雜許 多,理由是定制Http服務(wù)器的配置文件、增加插件或組件使得更改Http的響應(yīng)
信息變的很容易,這樣使得識(shí)別變的困難;然而定制TCP/IP堆棧的行為 需要對(duì)核心層進(jìn)行修改,所以就容易識(shí)
別.
要讓服務(wù)器返回不同的Banner信息的設(shè)置是很簡(jiǎn)單的,象Apache這樣的開(kāi)放源代碼的Http服務(wù)器,用戶可以在
源代碼里修改Banner信息,然 后重起Http服務(wù)就生效了;對(duì)于沒(méi)有公開(kāi)源代碼的Http服務(wù)器比如微軟的IIS或者
是Netscape,可以在存放Banner信息的Dll文件中修 改,相關(guān)的文章有討論的,這里不再贅述,當(dāng)然這樣的修改的效果
還是不錯(cuò)的.另外一種模糊Banner信息的方法是使用插件。
常用測(cè)試請(qǐng)求:
1:HEAD/Http/1.0發(fā)送基本的Http請(qǐng)求
2:DELETE/Http/1.0發(fā)送那些不被允許的請(qǐng)求,比如Delete請(qǐng)求
3:GET/Http/3.0發(fā)送一個(gè)非法版本的Http協(xié)議請(qǐng)求
4:GET/JUNK/1.0發(fā)送一個(gè)不正確規(guī)格的Http協(xié)議請(qǐng)求
Http指紋識(shí)別工具Httprint,它通過(guò)運(yùn)用統(tǒng)計(jì)學(xué)原理,組合模糊的邏輯學(xué)技術(shù),能很有效的確定Http服務(wù)器的類型.它
可以被用來(lái)收集和分析不同Http服務(wù)器產(chǎn)生的簽名。
6、其他:為了提高用戶使用瀏覽器時(shí)的性能,現(xiàn)代瀏覽器還支持并發(fā)的訪問(wèn)方式,瀏覽一個(gè)網(wǎng)頁(yè)時(shí)同時(shí)建立
多個(gè)連接,以迅速獲得一個(gè)網(wǎng)頁(yè)上的多個(gè)圖標(biāo),這樣能更快速完成整個(gè)網(wǎng)頁(yè)的傳輸。
HTTP1.1中提供了這種持續(xù)連接的方式,而下一代HTTP協(xié)議:HTTP-NG更增加了有關(guān)會(huì)話控制、豐富的內(nèi)容
協(xié)商等方式的支持,來(lái)提供
更高效率的連接。
數(shù)據(jù)對(duì)于輸入和輸出的操作耗時(shí)是非常嚴(yán)重的問(wèn)題,如果把這個(gè)問(wèn)題放入到網(wǎng)絡(luò)上去看待更甚是值得注意的一個(gè)問(wèn)題了。假如結(jié)合基礎(chǔ)的OS知識(shí)我們也知道如果要減少這種I/O操作的耗時(shí)或者也可以說(shuō)提升這種效率的話,最大的可能就是減少物理讀寫(xiě)的次數(shù),而且盡可能做到主存數(shù)據(jù)的重讀性(操作系統(tǒng)也在加強(qiáng)說(shuō)明更多減少抖動(dòng)現(xiàn)象的產(chǎn)生)。
在java.nio包中我們可以直接來(lái)操作相對(duì)應(yīng)的API了。可以讓java更加方便的直接控制和運(yùn)用緩沖區(qū)。緩沖區(qū)有幾個(gè)需要了解的特定概念需要詳盡來(lái)解釋,才能更好的知道我們下面一些列需要針對(duì)的問(wèn)題實(shí)質(zhì)。
容量(capacity):顧名思義就是表示緩沖區(qū)中可以保存多少數(shù)據(jù);
極限(limit):緩沖區(qū)中的當(dāng)前數(shù)據(jù)終結(jié)點(diǎn)。不過(guò)它是可以動(dòng)態(tài)改變的,這樣做的好處也是充分利用重用性;
位置(position):這個(gè)也好理解,其實(shí)就是指明下一個(gè)需要讀寫(xiě)數(shù)據(jù)的位置。
上面上個(gè)關(guān)系還可以具體用圖示的方式來(lái)表達(dá)整體概念,如下圖所示:
l clear():首先把極限設(shè)置為容量,再者就是需要把位置設(shè)置為0;
l flip():把極限設(shè)置為位置區(qū),再者就是需要把位置設(shè)置為0;
l rewind():不改變極限,不過(guò)還是需要把位置設(shè)置為0。
最為最基礎(chǔ)的緩沖區(qū)ByteBuffer,它存放的數(shù)據(jù)單元是字節(jié)。首先要強(qiáng)調(diào)的是ByteBuffer沒(méi)有提供公開(kāi)的構(gòu)造方法,只是提供了兩個(gè)靜態(tài)的工廠方法。
l allocate(int capacity):返回一個(gè)ByteBuffer對(duì)象,參數(shù)表示緩沖區(qū)容量大小。
l allocateDirect (int capacity):返回一個(gè)ByteBuffer對(duì)象,參數(shù)也是一樣表示緩沖區(qū)容量大小。
在這里需要注意的是在使用兩者的時(shí)候需要特別小心,allocateDirect和當(dāng)前操作系統(tǒng)聯(lián)系的非常緊密,它牽涉到使用native method的方法,大家知道一旦本地方法就是需要考慮調(diào)用dll(動(dòng)態(tài)鏈接庫(kù))這個(gè)時(shí)候基本也就失去了JAVA語(yǔ)言的特性,言外之意對(duì)于耗資源非常大。所以如果考慮到當(dāng)前使用的緩存區(qū)比較龐大而且是一個(gè)長(zhǎng)期駐留使用的,這個(gè)時(shí)候可以考慮使用它。
摘要: 在上篇blog中談到RMI的問(wèn)世由來(lái)只是大致的把一些概念結(jié)構(gòu)說(shuō)明了下,自己靜靜想想要有好的說(shuō)明干脆用代碼說(shuō)明比較妥當(dāng)也最為有說(shuō)明性。事后自己倒騰了一個(gè)簡(jiǎn)單的代碼DEMO。代碼中有個(gè)簡(jiǎn)單的場(chǎng)景,比如你是屬于某地區(qū)醫(yī)保范圍內(nèi)的成員,到醫(yī)院看病,這個(gè)候醫(yī)院為了審核你的相關(guān)個(gè)人資料需要到醫(yī)保管理部門調(diào)閱信息,你只需要給出用戶名稱或者其他一個(gè)有... 閱讀全文
Rmi自從JDK1.1就已經(jīng)出現(xiàn)了。而對(duì)于為什么在JAVA的世界里需要一個(gè)這樣 思想理念就需要看下:RMI問(wèn)世由來(lái)。其實(shí)真正在國(guó)內(nèi)使用到它的比較少,不過(guò)在前些年比較火的EJB就是在它的基礎(chǔ)上進(jìn)一步深化的。從本質(zhì)上來(lái)講RMI的興起正是為了設(shè)計(jì)分布式的客戶、服務(wù)器結(jié)構(gòu)需求而應(yīng)運(yùn)而生的,而它的這種B/S結(jié)構(gòu)思想能否和我們通常的JAVA編程更加貼切呢?言外之意就是能否讓這種分布式的狀態(tài)做到更加透明,作為開(kāi)發(fā)人員只需要按照往常一樣開(kāi)發(fā)JAVA應(yīng)用程序一樣來(lái)開(kāi)發(fā)分布式的結(jié)構(gòu)。那現(xiàn)在的問(wèn)題是如何來(lái)劃平這個(gè)鴻溝呢?首先我們來(lái)分析下在JAVA世界里它的一些特點(diǎn)因素:
l JAVA使用垃圾收集確定對(duì)象的生命周期。
l JAVA使用異常處理來(lái)報(bào)告運(yùn)行期間的錯(cuò)誤。這里就要和我們網(wǎng)絡(luò)通訊中的異常相聯(lián)系起來(lái)了。在B/S結(jié)構(gòu)的網(wǎng)絡(luò)體系中我們的這種錯(cuò)誤性是非常常見(jiàn)的。
l JAVA編寫(xiě)的對(duì)象通過(guò)調(diào)用方法來(lái)調(diào)用。由于網(wǎng)絡(luò)通訊把我們的客戶與服務(wù)器之間阻隔開(kāi)了。但是代理的一種方式可以很好的提供一種這樣的假象,讓開(kāi)發(fā)人員或者使用者都感覺(jué)是在本地調(diào)用。
l JAVA允許一種高級(jí)的使用類加載器(CLassLoader)機(jī)制提供系統(tǒng)類路徑中沒(méi)有的類。這話什么意思?
上面說(shuō)到了分布式的方式和我們的JAVA中如何更好的劃平這個(gè)鴻溝,需要具備的特質(zhì)。
那這里我們來(lái)看看我們所謂的RMI到底跟我們普通的JAVA(或者說(shuō)JavaBean)存在一些什么樣的差異:
l RMI遠(yuǎn)程異常(Remote Exception):在上面我們也提到了一個(gè)網(wǎng)絡(luò)通訊難免有一些無(wú)論是軟件級(jí)別的還是硬件級(jí)別的異常現(xiàn)象,有時(shí)候這些異常或許是一種無(wú)法預(yù)知的結(jié)果。讓我們開(kāi)發(fā)人緣如何來(lái)回溯這種異常信息,這個(gè)是我們開(kāi)發(fā)人員要關(guān)心的。因此在調(diào)用遠(yuǎn)程對(duì)象的方法中我們必須在遠(yuǎn)程接口中(接口是一種規(guī)范的標(biāo)準(zhǔn)行為)所以在調(diào)用的這個(gè)方法體上需要簽名注明:java.rmi,RemoteException.。這也就注明了此方法是需要調(diào)用遠(yuǎn)程對(duì)象的。
l 值傳遞 :當(dāng)把對(duì)象作為參數(shù)傳遞給一個(gè)普通的JAVA對(duì)象方法調(diào)用時(shí),只是傳遞該對(duì)象的引用。請(qǐng)注意這里談到的是對(duì)象的“引用”一詞,如果在修改該參數(shù)的時(shí)候,是直接修改原始對(duì)象。它并不是所謂的一個(gè)對(duì)象的備份或者說(shuō)拷貝(說(shuō)白了就是在本JVM內(nèi)存中的對(duì)象)。但是如果說(shuō)使用的是RMI對(duì)象,則完全是拷貝的。這與普通對(duì)象有著鮮明的對(duì)比。也正是由于這種拷貝的資源消耗造就了下面要說(shuō)到的性能缺失了。
l 調(diào)用開(kāi)銷:凡是經(jīng)過(guò)網(wǎng)絡(luò)通訊理論上來(lái)說(shuō)都是一種資源的消耗。它需要通過(guò)編組與反編組方式不斷解析類對(duì)象。而且RMI本身也是一種需要返回值的一個(gè)過(guò)程定義。
l 安全性:一談到網(wǎng)絡(luò)通訊勢(shì)必會(huì)說(shuō)到如何保證安全的進(jìn)行。
在開(kāi)始進(jìn)行原理梳理之前我們需要定義清楚幾個(gè)名詞。對(duì)于這些名詞的理解影響到后的深入進(jìn)行。
1. Stub(存根,有些書(shū)上也翻譯成:樁基在EJB的相關(guān)書(shū)籍中尤為體現(xiàn)這個(gè)意思):
這里舉例說(shuō)明這個(gè)概念起(或許不夠恰當(dāng))。例如大家因公出差后,都有存在一些報(bào)銷的發(fā)票或者說(shuō)小票。對(duì)于你當(dāng)前手頭所拿到的發(fā)票并不是一個(gè)唯一的,它同時(shí)還在你發(fā)生消費(fèi)的地點(diǎn)有一個(gè)復(fù)印件,而這個(gè)復(fù)印件就是所謂的存根。但是這個(gè)存根上并沒(méi)有很多明細(xì)的描述,只是有一個(gè)大概的金額定義。它把很多的細(xì)節(jié)費(fèi)用都忽略了。所以這個(gè)也是我們說(shuō)的存根定義。而在我們RMI的存根定義就是使用了這樣一個(gè)理解:在與遠(yuǎn)程發(fā)生通訊調(diào)用時(shí),把通訊調(diào)用的所有細(xì)節(jié)都通過(guò)對(duì)象的封裝形式給隱藏在后端。這本身就符合OOAD的意思理念。而暴露出來(lái)的就是我們的接口方式,而這種接口方式又和服務(wù)器的對(duì)象具有相同的接口(這里就和我們前面舉例說(shuō)的報(bào)銷單據(jù)聯(lián)系上了,報(bào)銷單據(jù)的存根不知道會(huì)有一個(gè)什么形式發(fā)生具體問(wèn)題,而你手執(zhí)的發(fā)票具體就需要到貴公司去報(bào)銷費(fèi)用,而這里的公司財(cái)務(wù)處就是所謂的服務(wù)器端,它才是真正干實(shí)質(zhì)性問(wèn)題的。)因此作為開(kāi)發(fā)人員只需要把精力集中在業(yè)務(wù)問(wèn)題的解決上,而不需要考慮復(fù)雜的分布式計(jì)算。所有這些問(wèn)題都交給RMI去一一處理。
2. Skeleton(一些書(shū)翻譯叫骨架,也叫結(jié)構(gòu)體):它的內(nèi)部就是真正封裝了一個(gè)類的形成調(diào)用體現(xiàn)機(jī)制。包括我們熟知的ServerSocket創(chuàng)建、接受、監(jiān)聽(tīng)、處理等。
3. Mashalling(編組):在內(nèi)存中的對(duì)象轉(zhuǎn)換成字節(jié)流,以便能夠通過(guò)網(wǎng)絡(luò)連接傳輸。
4. Unmashalling(反編組):在內(nèi)存中把字節(jié)流轉(zhuǎn)換成對(duì)象,以便本地化調(diào)用。
5. Serialization(序列化):編組中使用到的技術(shù)叫序列化。
6. Deserializationg(反序列化):反編組中使用到的技術(shù)叫反序列化。
既然我們知道stub主要是以接口的方式來(lái)暴露體現(xiàn),而stub主要 也是以代理的方式來(lái)具體實(shí)施。那在RMI中的這種接口有哪些特性呢?(Remote Interface)
1) 必須擴(kuò)展(extends)java.rmi.Remote接口,因?yàn)檫h(yuǎn)程接口并不包含任何一個(gè)方法,而是作為一個(gè)標(biāo)記出現(xiàn),它就是需要告訴JVM在RunTime的時(shí)候哪些是常規(guī)對(duì)象,哪些屬于遠(yuǎn)程對(duì)象。通過(guò)這種標(biāo)識(shí)的定義能讓JVM了解類中哪些方法需要編組,通過(guò)了編組的方式才能通過(guò)網(wǎng)絡(luò)序列化的調(diào)用;
2) 接口必須為public(公共),它的好處不言而喻的——能夠方便的讓所有人員來(lái)調(diào)用。
3) 接口方法還需要以異常拋出(例如:RemoteException),至于它的用處我們?cè)谇懊嬉蔡岬竭@里就不再?gòu)?fù)述;
4) 在調(diào)用一個(gè)遠(yuǎn)程對(duì)象期間(運(yùn)行期間),方法的參數(shù)和返回值都要必須是可序列化的。至于為什么需要這么做?這里的緣由不用多說(shuō)大家也應(yīng)該清楚了解。
既然我們知道stub所做的事情是一個(gè)簡(jiǎn)單的代理轉(zhuǎn)發(fā)動(dòng)作,那我們真正要做的對(duì)象就在服務(wù)端來(lái)做了。對(duì)于使用簡(jiǎn)單的RMI我們直接去指定,但是往往一旦使用了RMI對(duì)象就存在非常多的遠(yuǎn)程方法調(diào)用,這個(gè)時(shí)候服務(wù)器端對(duì)于這么多的調(diào)用如何來(lái)判別或者說(shuō)識(shí)別呢?這里就要說(shuō)到的是對(duì)于RMI實(shí)現(xiàn)它會(huì)創(chuàng)建一個(gè)標(biāo)識(shí)符,以便以后的stub可以調(diào)用轉(zhuǎn)發(fā)給服務(wù)器對(duì)象使用了,而這種方式我們通常叫服務(wù)器RMI的注冊(cè)機(jī)制。言外之意就是讓服務(wù)器端的對(duì)象注冊(cè)在RMI機(jī)制中,然后可以導(dǎo)出讓今后的stub按需來(lái)調(diào)用。那它又是如何做到這種方式的呢?對(duì)于RMI來(lái)說(shuō)有兩種方式可以達(dá)到這種效果:
a) 直接使用UnicastRemoteObject的靜態(tài)方法:exportObject;
b) 繼承UnicastRemoteObject類則缺省的構(gòu)造函數(shù)exportObject。
現(xiàn)在大家又會(huì)問(wèn)他們之間又有什么區(qū)別呢?我該使用哪種方式來(lái)做呢,這不是很難做抉擇嗎?從一般應(yīng)用場(chǎng)景來(lái)說(shuō)區(qū)別并不是很大,但是,這里說(shuō)了“但是”哦,呵呵。大家知道繼承的方式是把父類所具備的所有特質(zhì)都可以完好無(wú)損的繼承到子類中而對(duì)于類的總老大:Object來(lái)說(shuō)里面有:equals()、hashCode()、toString()等方法。這是個(gè)什么概念呢?意思就是說(shuō)如果對(duì)于本地化的調(diào)用,他們兩個(gè)的方法(a,b)基本區(qū)別不是很大。但是我們這里強(qiáng)調(diào)的RMI如果是一種分布式的特定場(chǎng)景,具備使用哈希表這種特性就顯得尤為重要了。
剛才說(shuō)了服務(wù)端采用什么方法行為導(dǎo)出對(duì)象的。那現(xiàn)在導(dǎo)出后的對(duì)象又對(duì)應(yīng)會(huì)發(fā)生什么情況呢?
首先被導(dǎo)出的對(duì)象被分配一個(gè)標(biāo)識(shí)符,這個(gè)標(biāo)識(shí)符被保存為:java.rmi.server.ObjID對(duì)象中并被放到一個(gè)對(duì)象列表中或者一個(gè)映射中。而這里的ID是一個(gè)關(guān)鍵字,而遠(yuǎn)程對(duì)象則是它的一個(gè)值(說(shuō)到這大家有沒(méi)有覺(jué)得它原理非常像HashMap的特質(zhì)呢?沒(méi)錯(cuò),其實(shí)就是使用了它的特性),這樣它就可以很好的和前面創(chuàng)建的stub溝通。如果調(diào)用了靜態(tài)方法UnicastRemoteObject.export(Remote …),RMI就會(huì)選擇任意一個(gè)端口號(hào),但這只是第一調(diào)用發(fā)生在隨后的exportObject每次調(diào)用都把遠(yuǎn)程對(duì)象導(dǎo)出到該遠(yuǎn)程對(duì)象第一被導(dǎo)出時(shí)使用的端口號(hào)。這樣就不會(huì)產(chǎn)生混亂,會(huì)把先前一一導(dǎo)出的對(duì)象全部放入到列表中。當(dāng)然如果采用的是指定端口的,則按照對(duì)應(yīng)顯示的調(diào)用方式使用。這里稍作強(qiáng)調(diào)的是一個(gè)端口可以導(dǎo)出任意數(shù)目的對(duì)象。
(待續(xù)……) 大家都知道對(duì)于互聯(lián)網(wǎng)的世界網(wǎng)絡(luò)通訊是其本質(zhì)特征。而對(duì)于一個(gè)分布式式計(jì)算來(lái)說(shuō)更是如此。在它的環(huán)境中使用了客戶/服務(wù)器結(jié)構(gòu)特點(diǎn),使用的一個(gè)核心技術(shù)就是網(wǎng)絡(luò)通訊層。在最早的OSI的概念基礎(chǔ)上,建立了完善具體協(xié)議層。而客戶想要能夠與位于其他物理層主機(jī)上的服務(wù)器通訊,需要能夠想服務(wù)器發(fā)送數(shù)據(jù),然后以某種方式獲得響應(yīng)。這當(dāng)中就牽涉到我們熟悉的協(xié)議層面了,在這里就不再?gòu)?fù)述這些協(xié)議概念了。對(duì)于網(wǎng)絡(luò)通訊來(lái)說(shuō)我們所要了解的是最為常用的就是兩種連接方式:無(wú)連接協(xié)議(UDP)、面向連接協(xié)議(TCP/IP)。多數(shù)網(wǎng)絡(luò)編程庫(kù)中(以JAVA為主來(lái)說(shuō)明),在JAVA平臺(tái)中一樣的提供了這些元素。而作為面向連接協(xié)議來(lái)說(shuō)使用的是套接字(Socket)進(jìn)行了更進(jìn)一步的抽象描述。一般我們?cè)?/span>JAVA的網(wǎng)絡(luò)編程中都覺(jué)得在使用套接字這塊相對(duì)方便,它不需要你去更多的了解操作系統(tǒng)的細(xì)節(jié)以及硬件的傳遞處理方式。TCP/IP的所有細(xì)節(jié)之處都得到了套接字的封裝使用,讓程序員關(guān)注到業(yè)務(wù)層面的處理。
對(duì)象是一種抽象思維物質(zhì),對(duì)于計(jì)算機(jī)來(lái)說(shuō)它只對(duì)數(shù)字電路的存儲(chǔ)方式能夠加以識(shí)別而且在網(wǎng)絡(luò)傳輸當(dāng)中也是一種信號(hào)量,而這一切只有使用字節(jié)流方式傳輸才是真正需要做到的。所以在本地主機(jī)與遠(yuǎn)程服務(wù)器的通訊傳輸就在對(duì)象與字節(jié)流之間不斷相互轉(zhuǎn)化才是我們真正需要的人性物質(zhì)與機(jī)器所需要的。(有點(diǎn)墨跡了,切入整體)總體來(lái)說(shuō)就是需要兩種方式來(lái)認(rèn)定這種傳輸行為:編組(Marshalling)與反編組(Unmarshalling)。而這一切的手段方式才是通過(guò):序列化(Serialiazable)與反序列化的方式不斷完成。如下圖所示:
圖:對(duì)象到字節(jié)再到對(duì)象的轉(zhuǎn)換
對(duì)于數(shù)據(jù)的傳輸本質(zhì)就是上圖說(shuō)明的。那我們一般是如何使用套接字來(lái)構(gòu)造我們這一行為呢?對(duì)于這里強(qiáng)調(diào)的主要是一種大致方法說(shuō)明,所以只能以部分代碼來(lái)說(shuō)明客戶端怎么來(lái)發(fā)送這個(gè)請(qǐng)求。
Socket socket=new Socket("http://www.wgh.com.cn",8888);
OutputStream out=socket.getOutputStream();
ObjectOutputStream obj=new ObjectOutputStream(out);
obj.writeObject(object);
InputStream in=socket.getInputStream();
ObjectInputStream objIn=new ObjectInputStream(in);
Object objFoo=(Object)objIn.readObject();
//todo 這里就是具體進(jìn)行操作的相關(guān)傳值參數(shù)處理了…
obj.close();
objIn.close();
socket.close();
而作為服務(wù)器的接收方則把以上數(shù)據(jù)做一個(gè)逆轉(zhuǎn)相反處理就可以。即服務(wù)器需要讀取發(fā)送過(guò)來(lái)的對(duì)象數(shù)據(jù),最終得到結(jié)果。現(xiàn)在假設(shè)還是一個(gè)甚至更多這樣的對(duì)象處理,我們又要處理和以上代碼差不多的過(guò)程。好,到這里我們可曾想到難道沒(méi)有一種辦法把這些過(guò)多的重復(fù)過(guò)程做一個(gè)通用的方式來(lái)提供嗎?我如果不想去做這些繁雜的對(duì)象處理可以嗎?比如,我想直接得到:
//其中clientObjectji就是從客戶端傳輸過(guò)來(lái)的副本;
MyObject myObject=server.getFoo(clientObject);
這樣就能讓我們把底層的那些龐雜數(shù)據(jù)轉(zhuǎn)換能夠透明封裝起來(lái)呢?既然這個(gè)問(wèn)題一經(jīng)提出,那就意味著肯定有很多類似的需求。技術(shù)永遠(yuǎn)都是在需求的提出應(yīng)運(yùn)而生的。上面提出的需求就是我們要討論的,既然我們想把一些套接字的重復(fù)處理過(guò)程來(lái)個(gè)封裝清理,那需要面對(duì)的問(wèn)題是什么呢?
1. 能夠把所有的相同處理過(guò)程全部都移入到服務(wù)端呢?
2. 對(duì)于客戶端來(lái)說(shuō)能否只預(yù)留接口行為呢?
3. 把過(guò)多的復(fù)雜處理過(guò)程完善的做個(gè)封裝?
4. 如果以上過(guò)程能夠形成,那客戶端又是如何辦到可以連接到服務(wù)器端的組件行為呢?
既然能夠把遇到的問(wèn)題提出然后總結(jié)出來(lái)也就意味著我們需要去解決它。不知道是否還
記得設(shè)計(jì)模式中有一個(gè)叫:代理模式?沒(méi)錯(cuò),就是這個(gè)代理模式開(kāi)始我們的描述。代理是一個(gè)實(shí)現(xiàn)給定接口的對(duì)象,但是不直接去執(zhí)行代碼結(jié)果,而是代表其他一些對(duì)象執(zhí)行實(shí)際計(jì)算的對(duì)象。怎么理解這個(gè)話呢?舉例說(shuō),如今很多城市都有火車票或者飛機(jī)票的代售點(diǎn),這里的代售點(diǎn)其實(shí)就是采用了一種代理機(jī)制。我們想買某天的火車或者飛機(jī)票有時(shí)候并不需要到火車站或者飛機(jī)票的總點(diǎn)去購(gòu)買票,而是找一個(gè)你最近的代售點(diǎn)去購(gòu)買。代售點(diǎn)就是起到一個(gè)中間橋梁的作用,至于買票人員無(wú)需關(guān)心他們?nèi)绾稳ビ嗁?gòu),這些具體的動(dòng)作都由他們內(nèi)部去處理,你只關(guān)心最終是否有你需要的票就行。知道這個(gè)原理接下來(lái)就好理解很多了,我們最好以類圖的方式來(lái)說(shuō)明這個(gè)代理的機(jī)制,如圖所示:
到這里如果還覺(jué)得抽象,沒(méi)關(guān)系接下來(lái)我以更加貼切的實(shí)例來(lái)結(jié)合類圖的方式給出對(duì)應(yīng)的參照說(shuō)明。假如我們把上面的proxy模式再做個(gè)深入的探討剖析(結(jié)合上面說(shuō)的客戶端發(fā)送參數(shù)作為請(qǐng)求和提出的問(wèn)題綜述)。大家都知道一個(gè)接口是能夠在安全甚至在擴(kuò)展上能夠幫助我們非常大的功能。作為客戶端最為希望的就是只關(guān)心我們需要的參數(shù)(或者變量)、返回值,而它如何而來(lái),做了哪些具體工作這些都不是客戶端關(guān)心的。Ok,現(xiàn)在結(jié)合我們說(shuō)的接口方式,確實(shí)可以解決這個(gè)問(wèn)題(接口的簡(jiǎn)單化,沒(méi)有具體實(shí)現(xiàn)),但是你可能會(huì)問(wèn):
1. 既然接口如此簡(jiǎn)單,那參數(shù)又是如何傳遞過(guò)去的呢?
2. 服務(wù)端又如何知道我要的是什么呢?
帶著問(wèn)題我們來(lái)解決這個(gè)問(wèn)題,當(dāng)然也是大家所關(guān)心的問(wèn)題了。現(xiàn)在開(kāi)始要對(duì)于上面的proxy模式做個(gè)深入剖析了。我們先來(lái)看一個(gè)proxy模式演變的過(guò)程的圖示:
圖:RMI核心結(jié)構(gòu)
我們可以從圖示看出從傳統(tǒng)的proxy模式變化到一個(gè)變化的結(jié)構(gòu)有什么不同呢?對(duì)于先前我們提出的兩個(gè)問(wèn)題就可以很好的做出解釋了:
n 既然接口如此簡(jiǎn)單,那參數(shù)又是如何傳遞過(guò)去的呢?
A:既然是對(duì)客戶端只開(kāi)接口暴露,那么我們是就需要一個(gè)后臺(tái)的socket來(lái)傳輸接口中已經(jīng)定義好的參數(shù),通過(guò)參數(shù)的編組(序列化)方式請(qǐng)求到遠(yuǎn)程服務(wù)上去響應(yīng)處理。這當(dāng)中要求定義到對(duì)方服務(wù)的服務(wù)名稱和端口號(hào)。(這里也就是我們最先提到的那段代碼了)
n 服務(wù)端又如何知道我要的是什么呢?
A:ok,既然客戶端是通過(guò)socket來(lái)發(fā)送數(shù)據(jù),那勢(shì)必一定需要ServerSocket來(lái)做這個(gè)響應(yīng)的接收處理了。問(wèn)題是傳過(guò)來(lái)的參數(shù)如何與我們的業(yè)務(wù)實(shí)現(xiàn)類關(guān)聯(lián)上呢?所以這個(gè)也就是skeleton的職責(zé)所在了,在skeleton的封裝處理中(啟動(dòng)中就把響應(yīng)實(shí)現(xiàn)類給嵌入,聚合實(shí)現(xiàn)類),然后通過(guò)類轉(zhuǎn)換處理和匹配處理來(lái)得到需要響應(yīng)的結(jié)果了。
本來(lái)說(shuō)到這想大概有個(gè)收尾,但是總覺(jué)得還沒(méi)有把一些問(wèn)題說(shuō)透徹。索性想再深入寫(xiě)寫(xiě)。
從套接字衍生到RMI代碼思路
進(jìn)程本身是一個(gè)動(dòng)態(tài)的實(shí)體,所以它本身在運(yùn)行期間也通過(guò)創(chuàng)建進(jìn)程系統(tǒng)調(diào)用,并且可以創(chuàng)建多個(gè)新進(jìn)程,對(duì)于這句話我同樣使用圖解的方式來(lái)做個(gè)簡(jiǎn)單說(shuō)明:
當(dāng)一個(gè)進(jìn)程創(chuàng)建一個(gè)新進(jìn)程時(shí),會(huì)存在兩種可能的方式執(zhí)行:
1. 父進(jìn)程(繼續(xù)執(zhí)行)和子進(jìn)程并行的執(zhí)行;
2. 父進(jìn)程等待部分或者全部子進(jìn)程終止執(zhí)行;
而新進(jìn)程的地址空間也存在兩種可能:
1. 子進(jìn)程是父進(jìn)程的一個(gè)COPY了;
2. 載入一個(gè)程序來(lái)運(yùn)行;
到這里就有點(diǎn)感覺(jué)Erlang的進(jìn)程思想端倪了(開(kāi)始我咋看感覺(jué)有點(diǎn)象,但是越深入后就覺(jué)得確實(shí)就是到這個(gè)思想才形成了Erlang程序語(yǔ)言的意義本質(zhì),個(gè)人揣度啊,哈哈)既然有那么點(diǎn)思想的感覺(jué),那我們就開(kāi)始進(jìn)入探討階段了。也正是下面即將要講到的問(wèn)題才印證一句話:技術(shù)的本質(zhì)還存留在簡(jiǎn)單事物之上(個(gè)人總結(jié),哈哈)。
進(jìn)程間通信有兩種本質(zhì)的方式:
1. 共享緩沖區(qū)提供通信;
2. 消息傳遞;
大家有沒(méi)有認(rèn)真看到上面的四個(gè)字“消息傳遞”,對(duì)沒(méi)錯(cuò)就是消息傳遞!那這里我就感覺(jué)是否就是這里和Erlang的語(yǔ)言所談到的消息傳遞呢?盡管一個(gè)處于操作系統(tǒng)級(jí)別,而另一處于語(yǔ)言級(jí)別,但是初看給我的感覺(jué)是原理是否一致呢?呵呵,那就讓我們來(lái)看看OS級(jí)別的進(jìn)程間通信本質(zhì)起了。
消息系統(tǒng)的功能是允許進(jìn)程與其他進(jìn)程之間通訊不必借助共享數(shù)據(jù),他們各自獨(dú)立。而這里要說(shuō)到一個(gè)概念,什么是IPC?
如果我們先不看它定義,而了解具體做法,看是一個(gè)什么效果。
到這里為止是不是感覺(jué)又和我們說(shuō)的Erlang非常類似呢?真的沒(méi)錯(cuò)。。。那就繼續(xù)往下看看它到底如何而做了。有以下幾種方法實(shí)現(xiàn)和Send/Receive操作的方法:
u 直接或者間接通信
u 對(duì)稱或不對(duì)稱通信
u 自動(dòng)或手動(dòng)緩沖
u 發(fā)送copy或者引用
u 定長(zhǎng)消息或者變長(zhǎng)消息
為了更好的說(shuō)明上面各自的特征是如何引入和體現(xiàn)的,使用兩個(gè)典型的進(jìn)程p,q作為兩個(gè)進(jìn)程之間的通訊來(lái)加以演示。
這里就是兩個(gè)非常赤裸的而且是非常利索的通信了:
u send(P,message) P發(fā)送一個(gè)消息給進(jìn)程Q;
u receive(Q,message) 從進(jìn)程Q中接收一個(gè)消息
特點(diǎn):
1. 每對(duì)需要通信的進(jìn)程之間自動(dòng)建立一條鏈路,進(jìn)程只需要知道彼此的進(jìn)程標(biāo)識(shí)符(Pid);
2. 一個(gè)連接就只連接到這兩個(gè)進(jìn)程;
因此這種機(jī)制在尋址上是對(duì)稱的;發(fā)送者與接收者進(jìn)程都必須要指明通信一方。不過(guò)這里要談到它的一種特例:發(fā)送者需要知道接收者,但是接收者不需要知道發(fā)送者,其原語(yǔ)定義為:
Send(P,Message) 發(fā)送一個(gè)消息給P;
Receive(id,Message)從任意進(jìn)程中接受一個(gè)消息;
由于通信是一種交互行為,所以一般情況來(lái)說(shuō)我們有發(fā)送自然希望存在一個(gè)回復(fù)的交互動(dòng)作,而像這種特例就無(wú)法知道它的這種情形,因此這種情況也是我們不希望所見(jiàn)的。
間接通信中消息發(fā)送和接收則是通過(guò)郵箱(實(shí)際中更多的是端口方式,這里為了更好理解我們比作郵箱方式)進(jìn)行的。若把郵箱看成一個(gè)對(duì)象,進(jìn)程就可以把消息郵寄(放置)在其中,顯而易見(jiàn)既然能夠放入自然也就可以從郵箱中取出了。而每一個(gè)郵箱都有一個(gè)唯一的地址(標(biāo)識(shí)符),進(jìn)程可以通過(guò)不同的郵箱和其它進(jìn)程通信了。兩個(gè)進(jìn)程只有共享一個(gè)郵箱才可以進(jìn)程通信。因此基本構(gòu)建和原語(yǔ)定義圖示如下:
Send(A,M):發(fā)送消息(Message)給郵箱A;
Receive(A,M):從郵箱A接收到消息(M);
特點(diǎn):
1. 只有在兩個(gè)進(jìn)程間有一個(gè)共享郵件箱下才能兩者建立一個(gè)連接;
2. 一條鏈路可以連接兩個(gè)或者更多的進(jìn)程;
3. 每對(duì)通信進(jìn)程之間可以同時(shí)存在多個(gè)不同的鏈路,而且每條鏈路對(duì)應(yīng)一個(gè)郵箱;
那我們來(lái)看看直接通信和間接通信最大的區(qū)別是什么?沒(méi)錯(cuò),其實(shí)間接通信存在中間一個(gè)共享的郵箱,而正是這種方式才在以后的應(yīng)用中得到廣泛利用。這里就聯(lián)想到Erlang語(yǔ)法的:Pid!M是否感覺(jué)很相似(注:M消息通知標(biāo)示符為Pid的進(jìn)程操作事件,而且具體在接受中也存在得到一個(gè)receive來(lái)獲取消化了),在我看來(lái)它就是典型使用到了這個(gè)原理機(jī)制。這里來(lái)看一道例題:假如有兩個(gè)進(jìn)程P1,P2和P3都存在共享郵箱A,而且P2與P3正是從A中接收。那么誰(shuí) 接收到P1發(fā)送來(lái)的消息呢?圖示:
這里我們就需要具體討論問(wèn)題的實(shí)質(zhì)了:
對(duì)照上面說(shuō)講到的間接通信特點(diǎn),我們知道一條鏈路最多連接兩個(gè)進(jìn)程,同時(shí)最多允許任意選擇進(jìn)程來(lái)接收消息(現(xiàn)在這個(gè)例子中只存在P2,P3),所以他們兩者只允許單獨(dú)接收消息而不是同時(shí)接收消息。至于消息會(huì)發(fā)送給誰(shuí),這就需要系統(tǒng)本身來(lái)確定接收者了。因此,一個(gè)郵箱可能為一個(gè)進(jìn)程或者操作系統(tǒng)所有,不難看出這個(gè)例子存在以下情況:
一旦擁有郵箱
u 創(chuàng)建一個(gè)新郵箱;
u 通過(guò)這個(gè)郵箱發(fā)送和接收信息;
u 刪除一個(gè)郵箱;
接下來(lái)就開(kāi)始單獨(dú)討論所謂的這個(gè)“郵箱”的單獨(dú)機(jī)制能夠引發(fā)的一些線索了。
通過(guò)消息傳送來(lái)進(jìn)程通信,這個(gè)是它本質(zhì)所在。但是消息傳送可能有阻塞或者無(wú)阻塞——同步和異步。所以這里就存在對(duì)于發(fā)送者和接收者的阻塞或無(wú)阻塞現(xiàn)象的討論了,對(duì)于他們有一下特點(diǎn):
1. 發(fā)送進(jìn)程阻塞:發(fā)送進(jìn)程被阻塞,直到接收進(jìn)程接收消息;
2. 發(fā)送進(jìn)程無(wú)阻塞:發(fā)送進(jìn)程發(fā)送消息并且立刻恢復(fù)執(zhí)行;
3. 接收進(jìn)程阻塞:接收進(jìn)程被阻塞,知道一個(gè)消息為有效;
4. 接收進(jìn)程無(wú)阻塞:接收進(jìn)程獲取一個(gè)有效或空消息;
以上的方式還可以組合形成。
既然有阻塞和無(wú)阻塞現(xiàn)象,那立刻可以聯(lián)想到我們的郵箱擴(kuò)展成一種管道方式呢?沒(méi)錯(cuò)這里就需要講解下面的定義形成。
這里只想對(duì)于三個(gè)定義了解:
u 零長(zhǎng)度:無(wú)緩沖消息系統(tǒng);
u 限定長(zhǎng)度:
自動(dòng)緩沖
u 無(wú)限長(zhǎng)度:
這里單獨(dú)把限定長(zhǎng)度和無(wú)限長(zhǎng)度提取出來(lái)定義:
限定長(zhǎng)度:消息隊(duì)列中存在N個(gè)消息,發(fā)送者在發(fā)送未滿的隊(duì)列中無(wú)阻塞。一旦隊(duì)列滿則阻塞直到出現(xiàn)空閑空間。
無(wú)線長(zhǎng)度:消息隊(duì)列有無(wú)限個(gè)消息,也不會(huì)阻塞發(fā)送者。
下面我們就要通過(guò)這些概念擴(kuò)展到程序開(kāi)發(fā)中經(jīng)常會(huì)遇到的實(shí)例。
(待續(xù)。。。。。。)
在學(xué)習(xí)Erlang程序過(guò)程中,總覺(jué)得對(duì)于進(jìn)程還是沒(méi)有很好的把握。所以自己對(duì)于進(jìn)程的再次提及讓我不得不重溫操作系統(tǒng)這門看似抽象的課程了。但是總覺(jué)得如果單一講解進(jìn)程或許略顯抽象不夠理解,自己就想把某些經(jīng)驗(yàn)和知識(shí)片段有個(gè)很好的系統(tǒng)聯(lián)系起來(lái),我想這樣可以讓自己更好加強(qiáng)記憶理解。長(zhǎng)話短說(shuō),我們進(jìn)入主題,既然在Erlang的學(xué)習(xí)中始終圍繞著進(jìn)程一詞來(lái)深入研究,我們就從進(jìn)程這個(gè)話題談起。
1. 進(jìn)程是運(yùn)行中的程序。這里我們就可以稍微延伸下以便幫助我們記憶理解了:
在這里我們只要抓住“運(yùn)動(dòng)”詞匯,就不然發(fā)現(xiàn)進(jìn)程是個(gè)動(dòng)態(tài)的實(shí)體,與之對(duì)應(yīng)的是我們常說(shuō)的程序,程序而是一個(gè)靜態(tài)實(shí)體了。(bw:這里突然想到以前對(duì)于認(rèn)識(shí)EJB2中也有一個(gè)對(duì)應(yīng)的概念就是EntityBean與SessionBean,它們與之對(duì)應(yīng)的就是一個(gè)典型的名詞和動(dòng)詞概念了,哈哈啰嗦了,轉(zhuǎn)回正題)。那我們會(huì)想是什么來(lái)體現(xiàn)我們說(shuō)的進(jìn)程為一個(gè)動(dòng)態(tài)實(shí)體呢?立刻會(huì)聯(lián)系產(chǎn)生接下來(lái)的一個(gè)特點(diǎn)了。
2. 進(jìn)程不僅僅是程序代碼,它包含了當(dāng)前狀態(tài)。而這種狀態(tài)由兩個(gè)方面來(lái)表示:
u 程序計(jì)數(shù)器(program counter)
u cpu中的寄存器(registers)
就是由于進(jìn)程中有程序計(jì)數(shù)器—指明下一條要執(zhí)行的指令而且擁有一組相關(guān)的資源。這里又要繼續(xù)反問(wèn):到底是一個(gè)什么資源呢?那就要看下面會(huì)講到的PCB的概念了。
3. 進(jìn)程還包含進(jìn)程棧(process stack)。
例如:方法參數(shù)(method parameters);返回地址與本地變量等
4. 兩個(gè)進(jìn)程可能會(huì)關(guān)聯(lián)到同樣的程序,剛才我們說(shuō)到了所謂程序是一個(gè)靜態(tài)實(shí)體。顧名思義就是兩個(gè)進(jìn)程允許使用同樣的代碼段,只是在參數(shù)不同而已。但是仍然認(rèn)為這兩個(gè)進(jìn)程是獨(dú)立執(zhí)行的序列。例如:幾個(gè)用戶可能會(huì)同事運(yùn)行主程序的不同拷貝一樣。
注:上面就是一個(gè)完整的進(jìn)程狀態(tài)圖了。這里沒(méi)有必要多說(shuō)什么了,圖表給了我們一個(gè)輪廓。
這里就是我們要講到的進(jìn)程控制塊了,對(duì)于操作系統(tǒng)都是需要通過(guò)PCB來(lái)表示進(jìn)程的。有些資料上也稱作為:任務(wù)控制塊。對(duì)于PCB的整體描述我們還是以圖表的方式來(lái)說(shuō)明(這也是本人最喜歡也覺(jué)得最直觀的一種理解方式了):
Pointer(指針) |
Process state(進(jìn)程狀態(tài)) |
Process number(進(jìn)程序列號(hào)) |
|
Program counter(程序計(jì)數(shù)器) |
|
Register(寄存器) |
|
Memory limits(主存中受限說(shuō)明) |
|
List of open files |
|
。。。(這里其實(shí)還有很多,就不再一一列舉了) |
PCB描述圖
既然是操作系統(tǒng)都需要通過(guò)進(jìn)程控制塊來(lái)調(diào)用進(jìn)程過(guò)程,那我們?cè)谶@里舉例說(shuō)明下如果有兩個(gè)進(jìn)程結(jié)合PCB是如何在CPU之中切換使用進(jìn)程的。為了更加清晰了解它們的過(guò)程,還是老規(guī)矩使用一個(gè)圖表來(lái)展示兩個(gè)進(jìn)程分別為P1,P2怎么運(yùn)行的。
(這個(gè)圖在自己的筆記本上已經(jīng)用筆畫(huà)出來(lái)了,可就是找不到一個(gè)好的工具,暫時(shí)放置在這,待續(xù)畫(huà)圖了)
由于我們目前接觸的其實(shí)多半都是以分時(shí)系統(tǒng)為主的,其目標(biāo)也是為了在進(jìn)程之間頻繁轉(zhuǎn)換cpu以便由于用戶與運(yùn)行的程序來(lái)交互。
1. 進(jìn)程進(jìn)入系統(tǒng)后,都被放在隊(duì)列中了,我們稱這個(gè)隊(duì)列為:作業(yè)隊(duì)列(也有些書(shū)上不是這么稱呼的),所有的進(jìn)程都在這個(gè)其中。
2. 處于就緒進(jìn)程都被保留在一個(gè)列表中——就緒列表
3. 一旦進(jìn)程獲得了CPU并且執(zhí)行,就可能發(fā)生一下某個(gè)事件存在:
u 進(jìn)程可能發(fā)出一個(gè)I/O請(qǐng)求,然后被放置在I/O隊(duì)列中;
u 進(jìn)程也可能創(chuàng)建一個(gè)新的子進(jìn)程并且等待它終止;
u 有時(shí)候發(fā)生一個(gè)中斷,導(dǎo)致進(jìn)程強(qiáng)行從CPU里移除并返回就緒隊(duì)列;
這里需要了解兩個(gè)主要的概念:
1. 長(zhǎng)程調(diào)度(操作系統(tǒng)調(diào)度程序):從一個(gè)池中選擇進(jìn)程并其載入內(nèi)存中。
注:咋看不是很了解,可能這里需要了解虛擬存儲(chǔ)過(guò)程對(duì)于這個(gè)概念就比較好理解。這里大致說(shuō)明下。由于過(guò)去我們所使用的內(nèi)存(主存儲(chǔ)器)空間非常有限,在搶占的進(jìn)程志愿中如果都想放入內(nèi)存中顯然是不夠科學(xué),而對(duì)于我們的后備動(dòng)力輔助存儲(chǔ)器——磁盤(這里我們說(shuō)是硬盤,當(dāng)然也有3.5英寸的小磁盤了,呵呵)來(lái)說(shuō),就可以充分考慮到使用它來(lái)做個(gè)過(guò)度動(dòng)態(tài)的存儲(chǔ)器。所以這樣一來(lái)我們就不需要把一個(gè)進(jìn)程中所有的信息都裝載到內(nèi)存中,而是在需要是再來(lái)考慮換入;而與之相反的就是不需要時(shí)就換出了(bw:這里的換入/換出如果比較頻繁也就證明我們的內(nèi)耗比較嚴(yán)重,一般稱作這個(gè)叫:抖動(dòng)現(xiàn)象。大家有時(shí)候感興趣的可以觀察我們主機(jī)的硬盤燈如果在頻繁的閃動(dòng)就表示資源在不斷換入換出了,呵呵)。而這也就是虛擬存儲(chǔ)的一個(gè)本質(zhì)過(guò)程,當(dāng)然中間需要通過(guò)邏輯轉(zhuǎn)換表來(lái)過(guò)度,在這里我們就不再具體復(fù)述了。有興趣的可以去看看相關(guān)OS方面的書(shū)籍。
2. 近程調(diào)度(CPU調(diào)度程序):從這些進(jìn)程中選擇就緒進(jìn)程并為其某個(gè)分配CPU
注:說(shuō)白了這里就是我們的cpu直接通過(guò)緩沖通道來(lái)調(diào)用就緒的程序進(jìn)入運(yùn)行。
前面我們也談到了進(jìn)程是在CPU中來(lái)回切換運(yùn)行的,既然是一種來(lái)回切換運(yùn)行那勢(shì)必需要讓CPU知道我們切換到下一個(gè)狀態(tài)執(zhí)行的地址或者說(shuō)切入點(diǎn)在哪了。這個(gè)就是為什么需要一個(gè)程序計(jì)數(shù)器的功效了。那我們把這種來(lái)回切換狀態(tài),同時(shí)需要保存當(dāng)前運(yùn)行進(jìn)程狀態(tài)信息給記錄下來(lái)以便下一次能夠定位到的方式稱作是——上下文轉(zhuǎn)換。
就上面的這樣一次轉(zhuǎn)換表述在一定程度上需要耗的硬件資源非常大(這里又要我強(qiáng)調(diào)下,更多的信息需要你還了解一些計(jì)算機(jī)組成體系結(jié)構(gòu)了。希望有時(shí)間自己也總結(jié)一篇關(guān)于一個(gè)簡(jiǎn)單程序在體系中運(yùn)行過(guò)程)。因此上下文轉(zhuǎn)換在很大程度上就取決于硬件的支持了。
接下來(lái)要講到的應(yīng)該是最核心的也是對(duì)以后我們無(wú)論是寫(xiě)程序好還是學(xué)習(xí)一門新語(yǔ)言好,都需要很好理解的部分了。在這里也盡可能表述清楚。
(待續(xù)......)
云計(jì)算應(yīng)該所具備的特質(zhì)如下:
1. 高負(fù)載
2. 正常運(yùn)轉(zhuǎn)
3. 容錯(cuò)性
4. 分布式
5. 容易伸縮
Erlang(讀音:['?:læ?]厄蘭,中文意思為:占線小時(shí)(話務(wù)負(fù)載單位))正是由于它屬于開(kāi)放的電信業(yè)務(wù)平臺(tái),也就不難理解它的意義了。幾乎完全具備以上特質(zhì),而且它也是典型的函數(shù)式語(yǔ)言。和我們OOP的思想有著截然不同的概念。在以下的學(xué)習(xí)過(guò)程中主要還是以《Erlang程序設(shè)計(jì)》這本書(shū)作為一個(gè)學(xué)習(xí)的依據(jù)。
原子
定義:在Erlang中原子用來(lái)表示不同的非數(shù)字常量值。這里說(shuō)白了其實(shí)就是一種常量的定義。Erlang中原子是全局有效的,不需要像以前c/c++那樣通過(guò)宏來(lái)定義或者包含文件。在定義原子的時(shí)候只需要注意以下一些特點(diǎn)就可以:
1. 一般情況原子是以一串以小寫(xiě)字母開(kāi)頭,后面有數(shù)字、字母、下劃線、郵件符號(hào)(@);
2. 使用單引號(hào)引用起來(lái)的字符也屬于原子,例如’Monday’;
3. 一個(gè)原子的值就是原子本身;
元組(tuple)
定義:首先它是Erlang中具有特質(zhì)的一個(gè)定義,如果說(shuō)把它和我們java中的一個(gè)JavaBean來(lái)類比可能稍顯類似,書(shū)上引用的是c語(yǔ)言數(shù)據(jù)結(jié)構(gòu)來(lái)解說(shuō)元組的結(jié)構(gòu),盡管非強(qiáng)淺顯能看懂。但是作為一個(gè)java程序員我覺(jué)得采用自己熟悉的語(yǔ)言結(jié)構(gòu)來(lái)對(duì)比,學(xué)習(xí)效果更佳吧(對(duì)于記憶有很大幫助)。
比如我們一般對(duì)于JavaBean的定義是如下結(jié)構(gòu):
public class Person {
private String name;
private int height;
private int footSize;
private String eyeColor;
// get/set...
}
那在我們引用定義的時(shí)候就可以直接:
Person person1=new Person();
person1.setName("yeshucheng");
person1.setHeight(111);
person1.setFootSize(40);
person1.setEyeColor("black");
......
與之相對(duì)應(yīng)的是我們使用Erlang來(lái)定義了,對(duì)于Erlang的定義就截然和c/c++或者java有著明顯不同,相對(duì)于更加精煉明了:(這里我直接使用書(shū)上說(shuō)的所謂二元組)
Person={person,{name,yeshucheng},{height,111},{footsize,40},{eyecolor,black}}.
沒(méi)錯(cuò),就是這么直截了當(dāng)?shù)膩?lái)定義,甚至賦值(嚴(yán)格說(shuō)Erlang不能這么說(shuō),但是為了好記憶可以這么理解)
對(duì)于以上的定義這里要說(shuō)明注意的地方:
1. 定義元組,元組中字段沒(méi)有名字,通常可以使用一個(gè)原子作為元組的第一元素來(lái)標(biāo)明(請(qǐng)注意這里花括號(hào)內(nèi)第一原子都是解釋逗號(hào)后面一個(gè)說(shuō)明),這個(gè)元組所能代表的含義就是上面列出的程序定義了。
2. 創(chuàng)建元組,在聲明元組的同時(shí)其實(shí)已經(jīng)創(chuàng)建了元組,這個(gè)也是Erlang的一大特點(diǎn)之一了。如果不再使用,也隨之銷毀。Erlang使用的垃圾搜集器去收回沒(méi)有使用的內(nèi)存。
如:F={firstName,wan}
L={lastName,andy}
P={person,F,L}//這里就應(yīng)對(duì)我們第一條說(shuō)明的一樣第一個(gè)名稱表示就是后面所有逗號(hào)的整體列舉,如果在Erlang環(huán)境中對(duì)于上面寫(xiě)完后,直接敲回車(語(yǔ)句結(jié)束后存在”.”這里稍微注意下)就會(huì)得到以下結(jié)果,正好印證我們所說(shuō)明這這個(gè)問(wèn)題了
==》{persong,{firstName,wan},{lastName,andy}}.
如果在創(chuàng)建過(guò)程中存在一個(gè)未定義的變量,則程序編譯就會(huì)產(chǎn)生錯(cuò)誤。
3. 提取元組的字段值,剛才我們?cè)诔绦蛑杏卸x一個(gè)Person的元組而且也設(shè)置值了,現(xiàn)在如果我們想得到或者說(shuō)提取我們的值,那需要如何而做呢?首先我們采用基本的元組方式來(lái)試著看看如下:
1> Point={point,10,45}.
2> {point,X,Y}=Point.
3> X.
10
4> Y.
45
注明:這里又再次強(qiáng)調(diào)下point逗號(hào)后面的都是為他而說(shuō)明的。
1>Person={person,{name,yeshucheng},{height,111},{footsize,40},{eyecolor,black}}.
2>{_,{_,Who},{_,_},{_,_},{_,_}}=Person.
3>Who.
yeshucheng
說(shuō)明下,如果上面想得到的是值,那么位置響應(yīng)對(duì)號(hào)入座然后Who換成What就成(我開(kāi)始也犯錯(cuò)誤,編譯立馬出錯(cuò),后來(lái)想想用過(guò)一個(gè)What試試,果然正確,呵呵)。
列表
定義:列表第一個(gè)元素稱為列表的頭(head),后部分稱為列表尾(tail),一般[H|T]來(lái)標(biāo)示列表了。
注:列表的頭可以是任何東西,但是列表的尾通常還是一個(gè)列表。
至于具體的細(xì)節(jié)問(wèn)題還是需要找找相關(guān)文檔看下為好,它的概念牽涉到后面的非常多的定義了。
邊緣技術(shù)人員,這里是個(gè)人的一個(gè)定義闡述而已,所有的售前售后咨詢師、維護(hù)人員、培訓(xùn)講師等都包含在這個(gè)頭銜中。咋看感覺(jué)自己對(duì)這個(gè)頭銜有失偏頗的定論,其實(shí)不然我對(duì)這個(gè)行業(yè)的人員還是挺敬佩的。為什么這么說(shuō)呢?因?yàn)樗麄儺?dāng)中多數(shù)是在和我們的客戶一線打交道,客戶的喜怒哀樂(lè),喜形于色都能第一時(shí)間映入他們的腦海,他們需要學(xué)會(huì)最大的程度“承受”,即使受到某種輕視或者詆毀的狀態(tài)都需要忍受,同時(shí)還要很快的去更好處理當(dāng)時(shí)的尷尬場(chǎng)景。某種程度來(lái)說(shuō)他們類似一些公司業(yè)務(wù)跑單人員,但是他們有更多的技術(shù)背景同時(shí)這里面也有很多的牛人。這類人員所具備的素養(yǎng)更加強(qiáng)調(diào)人性的一面,也正是由于接觸不同社會(huì)個(gè)階層人員的廣泛,相對(duì)于那些整天坐在辦公室電腦前敲代碼的程序員來(lái)說(shuō)是截然不同的天地。程序員的思維縝密這個(gè)都是毋庸置疑的,但是也正是這種思維方式讓他們?nèi)菀紫萑胍?guī)則死板的世界,甚至有些人員會(huì)鉆牛角尖(你可別不承認(rèn)哦?或許就是你自己了,哈哈)而對(duì)于這里的邊緣技術(shù)人員來(lái)說(shuō)如果遇到同樣的一件事情很有可能他處理的方式會(huì)有很大不同,他的某種圓滑處理問(wèn)題的方式或許就是你需要學(xué)習(xí)的。而作為公司的老板們也是最多和這類人員交涉的,因?yàn)樗麄兞私夤镜恼w的宗旨方案,也了解客戶的需求,他們的老練思維往往會(huì)讓老板更加樂(lè)于傾聽(tīng)。這也不難想象為什么這類人員有時(shí)候拿錢或許比你做孺子牛的自己來(lái)說(shuō)更多的緣故了,更加受到器重讓你有嫉妒之嫌。你可曾想過(guò)如果老板讓你去做,自己又能否勝任呢?呵呵。
說(shuō)到這里可能大家會(huì)覺(jué)得我講的似乎在說(shuō)一名老練的銷售業(yè)務(wù)人員嗎?沒(méi)錯(cuò),如果你想做一個(gè)高端的邊緣技術(shù)人員(說(shuō)到這自己都感覺(jué)有點(diǎn)不大確切了,呵呵)上面談到的那種圓滑是你必修課程,但是有這些個(gè)人認(rèn)為還遠(yuǎn)遠(yuǎn)不夠!為什么這么說(shuō)呢?在我看來(lái),過(guò)去一些年確實(shí)很多做銷售的人員比做純技術(shù)的人員賺錢多這個(gè)也是不爭(zhēng)的事實(shí)。在未來(lái)如果你想在這個(gè)職位闖蕩,需要的素養(yǎng)再也不是靠過(guò)去的“牛皮嘴”了更多的是需要一個(gè)務(wù)實(shí)的干練大氣者。你需要知道在什么場(chǎng)合說(shuō)話到位的分寸;你需要知道如何行云流水般的寫(xiě)一份好材料;你需要有細(xì)心的觀察和不失吝嗇的豪邁口才;更甚你還不能缺少酒桌文化。。。。。。所有的這些或許你不具備,每個(gè)人都不是天生賦予有這些能力,但是你只要還年輕懂得如何去“學(xué)”就是你最大的資本。當(dāng)然這些前提都是需要你性格已經(jīng)具備它的潛質(zhì)所在,不然勸你另?yè)竦缆坊蛟S也是你的一片天地呢?
寫(xiě)到這回過(guò)頭看看,仿佛這個(gè)并不是自己的所謂“總結(jié)”了,連我自己都覺(jué)得自己都在天馬行空,哈哈。因?yàn)槲覀兟?tīng)過(guò)太多的領(lǐng)導(dǎo)的年終評(píng)述,八股文的段落著實(shí)讓自己不想再陳詞濫調(diào)一番“在這辭舊迎新的新春,借著黨的春風(fēng)我們回顧過(guò)去,展望未來(lái)在接下來(lái)的09年。。。”
既然09年馬上要到來(lái),我也簡(jiǎn)述下吧,俗是俗了點(diǎn)但是形式上還是要走一下的,呵呵。對(duì)于個(gè)人發(fā)展來(lái)說(shuō),09年自己還是想有個(gè)新的環(huán)境。人老在一個(gè)地方呆容易把自己給“停滯”成為慣性的“懶惰”。盡管自己有很多想法,但是有想法確實(shí)是不夠的,需要著實(shí)的執(zhí)行一番。在09年開(kāi)始有空就寫(xiě)blog了,做看官N年之久。把自己的一些心得體會(huì)寫(xiě)出來(lái)。若干年之后自己回頭看看或許是一種美妙的回憶呢?呵呵。在09年繼續(xù)鞏固自己的技術(shù)基石,同時(shí)也開(kāi)始學(xué)習(xí)一門新語(yǔ)言:Erlang。在它的邁進(jìn)同時(shí)還是不忘JAVA給我?guī)?lái)無(wú)窮樂(lè)資。最后就是希望上天多給我一些機(jī)會(huì),我時(shí)刻準(zhǔn)備著,哈哈。相信自己一定行!
(唧唧歪歪這么多寫(xiě)到這算都結(jié)束了!不知所云,哈哈)
PS:“有想法是不夠的,執(zhí)行力度還很差”---崔,我非常謝謝有你這個(gè)朋友,你的直率和指點(diǎn)讓我知道太多的無(wú)知,也讓我知道人的奮斗目標(biāo)是什么;盡管有時(shí)候你喜歡給我吃“棒棒糖”,內(nèi)心甜滋滋的,但正是你的這些語(yǔ)言從某些側(cè)面刺激了我的思維,很是感謝你!真的。我希望我們09年我們都共勉。