|
1、下載log4j下載1.2以后的版本
下載地址:http://logging.apache.org/log4j/1.2/download.html
2、下載tomcat-juli.jar,tomcat-juli-adapters.jar
使用LOG4J來接管tomcat6.0.18的日志文件必須要下載兩個文件:tomcat-juli.jar,tomcat-juli-adapters.jar。
下載地址為:http://www.apache.org/dist/tomcat/tomcat-6/v6.0.18/bin/extras/ (如果tomcat為其他版本,請下載對應版本的類包)
1、修改${catalina.home}/conf/context.xml
修改:<Context >為<Context swallowOutput="true" >只有這樣才能完全的把tomcat的stdout給接管過來。這一步很關鍵 在官網及網上找了許多資料都沒有提及。
2、復制log4j.jar到${catalina.home}/lib下
3、復制tomcat-juli-adapters.jar到${catalina.home}/lib下
4、復制tomcat-juli.jar到${catalina.home}/bin下,在該目錄會存在該文件,覆蓋 即可
5、建立log4j.properties,并把其放到${catalina.home}/lib下
在維護服務器時常常需要用到linux Shell命令,將常用的寫在這里備查:
telnet 10.10.50.122 7070
nslookup 查看域名解析
netstat -anp 顯示系統端口使用情況 a表示全部socket n不解析名稱 p顯示PID
lsof -i :端口 顯示占用該端口的進程情況
last
history
scp root@10.10.10.11:/home/asd/we.zip /home/we/ scp文件傳輸
w 當前登錄用戶
ps -ef|grep java 不解釋!
查看機器吞吐量(throughput)
sudo ifconfig eth0
iftop 監視網卡即時吞吐量
iptraf 監視網卡即時吞吐量
iostat 磁盤吞吐量查看
iostat 結果解釋 * rrqm/s: 每秒進行 merge 的讀操作數目。即 delta(rmerge)/s * wrqm/s: 每秒進行 merge 的寫操作數目。即 delta(wmerge)/s * r/s: 每秒完成的讀 I/O 設備次數。即 delta(rio)/s * w/s: 每秒完成的寫 I/O 設備次數。即 delta(wio)/s * rsec/s: 每秒讀扇區數。即 delta(rsect)/s * wsec/s: 每秒寫扇區數。即 delta(wsect)/s * rkB/s: 每秒讀K字節數。是 rsect/s 的一半,因為每扇區大小為512字節。(需要計算) * wkB/s: 每秒寫K字節數。是 wsect/s 的一半。(需要計算) * avgrq-sz: 平均每次設備I/O操作的數據大小 (扇區)。delta(rsect+wsect)/delta(rio+wio) * avgqu-sz: 平均I/O隊列長度。即 delta(aveq)/s/1000 (因為aveq的單位為毫秒)。 * await: 平均每次設備I/O操作的等待時間 (毫秒)。即 delta(ruse+wuse)/delta(rio+wio) * svctm: 平均每次設備I/O操作的服務時間 (毫秒)。即 delta(use)/delta(rio+wio) * %util: 一秒中有百分之多少的時間用于 I/O 操作,或者說一秒中有多少時間 I/O 隊列是非空的。即 delta(use)/s/1000 (因為use的單位為毫秒)
df -m 硬盤使用情況
free -m 內存使用情況
top 查看CPU使用情況
關于 load average 一般來說只要每個CPU的當前活動進程數不大于3那么系統的性能就是良好的,如果每個CPU的任務數大于5,那么就表示這臺機器的性能有嚴重問題。 對于上面的例子來說,假設系統有兩個CPU,那么其每個CPU的當前任務數為:8.13/2=4.065。這表示該系統的性能是可以接受的。
查看機器硬件信息
測試機器的硬件信息: 查看CPU信息(型號) # cat /proc/cpuinfo | grep name | cut -f2 -d: | uniq -c 8 Intel(R) Xeon(R) CPU E5410 @ 2.33GHz (看到有8個邏輯CPU, 也知道了CPU型號) # cat /proc/cpuinfo | grep physical | uniq -c 4 physical id : 0 4 physical id : 1 (說明實際上是兩顆4核的CPU) # getconf LONG_BIT 32 (說明當前CPU運行在32bit模式下, 但不代表CPU不支持64bit) # cat /proc/cpuinfo | grep flags | grep ' lm ' | wc -l 8 (結果大于0, 說明支持64bit計算. lm指long mode, 支持lm則是64bit) 再完整看cpu詳細信息, 不過大部分我們都不關心而已. # dmidecode | grep 'Processor Information' 查看內 存信息 # cat /proc/meminfo # uname -a Linux euis1 2.6.9-55.ELsmp #1 SMP Fri Apr 20 17:03:35 EDT 2007 i686 i686 i386 GNU/Linux (查看當前操作系統內核信息) # cat /etc/issue | grep Linux Red Hat Enterprise Linux AS release 4 (Nahant Update 5) (查看當前操作系統發行版信息) 查看機器型號 # dmidecode | grep "Product Name" 查看網卡信息 # dmesg | grep -i eth
du -ms /usr/local/jdk 查看文件夾使用的空間大小
du -sm * | sort -n 當前路徑下各文件夾大小,并排序顯示
Ubuntu Linux系統環境變量配置文件介紹在Ubuntu中有如下幾個文件可以設置環境變量
/etc/profile:在登錄時,操作系統定制用戶環境時使用的第一個文件,此文件為系統的每個用戶設置環境信息,當用戶第一次登錄時,該文件被執行。
/etc/environment:在登錄時操作系統使用的第二個文件,系統在讀取你自己的 profile前,設置環境文件的環境變量。
~/.profile:在登錄時用到的第三個文件是.profile文件,每個用戶都可使用該文件輸入專用于自己使用的shell信息,當用戶登錄時,該文件僅僅執行一次!默認情況下,他設置一些環境變量,執行用戶的.bashrc文件。
/etc/bashrc:為每一個運行bash shell的用戶執行此文件.當bash shell被打開時,該文件被讀取.
~/.bashrc:該文件包含專用于你的bash shell的bash信息,當登錄時以及每次打開新的shell時,該該文件被讀取。
使用source命令刷新環境變量
原文地址: http://ifelseif.blog.sohu.com/145381162.html首先下載libSVM的最新版本,他們的主頁在此http://www.csie.ntu.edu.tw/~cjlin/libsvm/index.html。源碼和手冊都有,真是好人啊!手冊寫的清晰明了通俗易懂,盡管是英文的。想快速上手看具體操作步驟的直接翻到appendix吧。
在linux下部署libSVM是簡單到不能再簡單了,make一下就完事兒了。什么!你沒有gcc,沒有python,沒有gnuplot?自己apt-get去吧。
用windows的童鞋,首先你們要安裝python和gnuplot。python的主頁為http://www.python.org/,安裝程序可以在這里下載。gnuplot的主頁為http://www.gnuplot.info/download.html,安裝程序在這里。python是需要安裝的,gnuplot是綠色軟件找個地方解壓就行。如果你網速快的話強烈推薦pythonxy這個東西,python科學計算相關的軟件包基本都包括了,有功夫好好學吧開源的哦。
需要手工添加環境變量,保證python根目錄,gnuplot的bin目錄,libsvm的windows目錄都在path里面,我的電腦上是c:\python26,C:\Python26\gnuplot\bin,c:\Users\gongwei\program\libsvm-2.9\windows\。然后還要改libSVM\tools目錄下的easy.py和grid.py文件,把gnuplot路徑那一項改成gnuplot_exe = r"C:\Python26\gnuplot\bin\pgnuplot.exe"。gnuplot有三個exe,這里只能用這個因為它可以通過管道輸入數據,另外兩個都不行。都弄完之后,嘗試運行一下吧:
python easy.py train.1 test.1
其中train.1和test.1都是作者提供的測試數據。可以在這里下載guide里面的數據,這里還有更多。
好啦下面就等著彈窗吧,會彈出一個gnuplot的窗口,里面的圖像會隨著網絡的訓練逐步更新。大功告成!
libSVM的使用很簡單,會用python的可以參考easy.py和grid.py寫自己的script。libSVM使用c++編寫,提供java的源碼,還支持R (also Splus), MATLAB, Perl, Ruby, Weka, Common LISP, CLISP, Haskell, LabVIEW的調用。想用的話基本都有自己適合的環境。
最后還是要感謝libSVM的幾位作者們,寫出這么好的軟件。向臺灣同胞致敬!
系統之前一直用的是maven-artifact-ant-2.0.4-dep.jar,但最近對一些jar包支持不好,運行ant腳本出現以下問題:
[artifact:dependencies] [WARNING] POM for 'ch.qos.logback:logback-classic:pom:0.9.9' is invalid. It will be ignored for artifact resolution. Reason: The POM expression: ${parent.version} could not be evaluated. Reason: ch.qos.logback:logback-classic:jar:${parent.version} references itself.這兩天調試一個asp.net程序,用戶在首頁登錄成功后,系統會在客戶端添加一個Cookie,然后重定向到首頁,首頁檢測到這個Cookie后就屏蔽掉登錄。我在本機調試的時候本能的用localhost,結果每次都不成功,Cookie不起作用。后來在hosts文件中將127.0.0.1 隨便映射成一個域名,一試就好了。到現在也不明白這是為什么,莫非是微軟覺得localhost的程序給自己添加Cookie是多此一舉?
這兩天開始研究一個韓國人寫的asp.net(C#)程序,好多年沒玩.net了,發現很生疏。首先要把源代碼在本機跑起來,安裝VS2005。然后打開網站把項目到進去后,啟動debug(F5)后出現問題, <add assembly="System.Web.DataVisualization, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />這一行報錯,google了一下發現必須要安裝.net framework 3.5 sp1 ,如果還不行還要安裝MS Chart.exe,看來這個是圖形報表需要的東西。
安裝完成后點擊自動調試模式,還是報錯,這次提示web.config里的全局路徑出問題,后來仔細琢磨了一下發現VS默認啟動的Development Server自作聰明的在啟動的URL后面加了一個項目名稱作為子路徑,這個導致了很多問題,項目里定義的相對路徑找不到,導致圖片、JS、CSS等無法顯示。好多人在罵微軟的這個stupid。
google了一下解決方案,如下:點擊VS上面的“工具”--->“外部工具”,然后添加一個Development Server,自己定義名稱、端口號、虛擬路徑、物理路徑等。我的位置如下:
標題:Web Server Port:8080
命令:C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\WebDev.WebServer.EXE
參數:/port:8080 /path:D:\vs_workspace\ibt 這里沒有定義虛擬路徑,即為/
然后勾選“使用輸出窗口”,這樣就有打印信息了。
完成后你會發現“工具”里多了一個你定義的“Web Server Port:8080”,點擊一下就啟動了。
好多國內的帖子到這里后就完事了,其實不然。因為這樣的話是解決了端口號和虛擬路徑的問題,但我發現這時候不能debug程序了,斷點沒用。
國外的帖子找到了解決辦法,原來還差一步,就是替換VS給項目設置的默認Development Server。在“解決方案資源管理區(solution explore)”里點擊項目工程(project),右鍵點擊并選擇“屬性頁”,選擇左邊的“啟動選項”,在“服務器”里選擇“使用自定義服務器”,在基URL里填寫“http://localhost:8080/”,這樣就OK了。但跟默認有區別的是,這次VS不管自動啟動Development Server,需要手動啟動,然后才能點擊“啟動調試(F5)”按鈕
由于項目中的小文件太多,都是幾K的小文件,有100多G,所以必須要提升靜態文件的訪問速度。一開始用Nginx 與 Tomcat做集群,Nginx負責靜態資源的響應。Nginx在Linux下跑的很爽,到Windows下就不太好了。Nginx前段時間推出了Windows版,拿來一試,感覺不太穩定。在一個刀片機下作測試很好,但弄到正式環境下就不行了,ext tree顯示不出來,而且要等很久,最后頁面提示:ext無法顯示。最后跟同事商量,覺得還是apache+tomcat在windows下比較穩定,轉手弄apache+tomcat。
apache官方沒有提供win64版本,就找了一個外國哥們在Vistual Studio 2005 下自己編譯的win64 apache,在測試機上安裝很輕松,然后布了2個tomcat,又在apache的mem cache中設置了3G的內存做緩存,測試一切OK。接著弄正式服務器,第一臺正式服務器很順利,幾分鐘就搞定了。第二臺服務器就出了問題,apache無法啟動,提示:“由于應用程序配置不正確 應用程序未能啟動。重新安裝應用程序可能會糾正這個問題”。然后查看這兩臺服務器有何差異,最后發現第一臺上有.net framework 2,3,3.5,第二臺上一個.net framework 都沒有。接著裝.net framework 2.0 service,還是不行。有文章說要安裝 vc redistribute 包,到微軟官方下載安裝,還是不行,郁悶。最后沒辦法,又下載安裝.ner framework 3.0,還是不行,靠!這時候我都不報希望了,又下載安裝.net framework 3.5,然后發現apache 可以了!最后一分鐘搞定第二臺服務器的apache+tomcat。
我的apache+tomcat用的是ajp proxy通信方式,設置session sticky。
好了,接下來觀察幾天看看效果如何
SkillSoft的Business Skills課程的Objectives數據封裝方式與PagePlayer.properties的LMS_AICC_VERSION,LMS_AICC_V2_POST這兩項屬性值有關。
LMS_AICC_VERSION值為2.2 or 3.5,默認是3.5。當LMS_AICC_VERSION=3.5時,Objectives的Score的值以分號割開,如下:
由于項目中用到,特在此做一筆記:
1.Tomcat為6.0.14,解壓版。首先說明一點:Tomcat本身是32位的,所以64位操作系統的話要覆蓋兩個文件。
到http://svn.apache.org/viewvc/tomcat/tc6.0.x/tags/TOMCAT_6_0_14/res/procrun/amd64/ 下載tomcat6.exe和tomcat6w.exe兩個文件。
2.將上面下載的兩個文件覆蓋$TOMCAT_HOME/bin下對應的文件。
3.命令行到$TOMCAT_HOME/bin下,運行service install命令。
4.修改服務為自啟動,OK。
PS:
這里有點小問題,系統中用的Java為Oracle jrockit,所以安裝后的路徑同SUN的Java有所不同。而$TOMCAT_HOME/bin下的service.bat顯然是為SUN的Java準備的,如下:
1.安裝AS4
這個不多說,安裝過程沒什么難度。
2.安裝Oracle10g
AS4下安裝Oracle10g的文章一搜一堆,都是那幾個步驟:
1、檢查oracle所需的RPM包是否齊全:
版本問題不大,大于等于都可以,沒有的在安裝盤或者Down下來裝上。
2、建立oracle用戶及oinstall,dba用戶組:
3、修改oracle用戶的.bash_profile文件,將oracle相關的環境變量加進去:
4、修改系統屬性,在/etc/sysctl.conf文件中加入kernel相關的屬性配置:
這里重要的是kernel.shmmax,這里設置的值為2G,這個值跟oracle的SGA有很大關系,很容易出錯。有的文章說這個值應該設置成內存的一半。另一個是kernel.shmall,有文章說這個值應該是kernel.shmmax除以系統的PAGE_SIDE得到的商。
5、根據步驟3里的設置創建相關目錄。
6、修改redhat發行標識:
由于oracle10g具有系統安裝監測,當檢測到的系統不符合安裝配置規定的要求時,安裝不能正常進行,故要更改操作系統的版本標識,這一操作不會影響任何系統問題,可以在安裝結束后恢復為正常狀態。
操作如下:
備份/etc/redhat-release文件為/etc/redhat-release.bak
以root權限修改/etc/redhat-release文件
將文件的內容Red Hat Enterprise Linux AS release 4 (Nahant)
修改為Red Hat Enterprise Linux AS release 3 (Taroon)
用于滿足 Disk1/install/oraparam.ini的檢查要求
7、開始安裝
這里可能會遇到一些問題,比如X-Windows啟動不起來,這時候需要運行命令:xhost+。如果IP是DHCP的話可能還需要修改local.localdomian的值。
運行oracle安裝盤里的runInstaller會出現安裝頁面,如果是亂碼的話還要設置系統的字符集。
需要運行orainstRoot.sh命令。
接下來oracle要驗證安裝需要的RPM包是否齊全,有的高級版本可能檢驗不出來。
安裝最后還要執行root.sh命令。
8、DBCA建庫問題
這個問題因機器而異,在我的機器上出了問題,害我折騰了兩三天。在建表的時候,最后一步有SGA的設置,默認選的是內存的40%。我的機器的內存是8G,40%是3G多,這樣就出問題了,開始建表操作后2%進度的時候報ORA-27123錯誤,說是sharedmomery問題,一開始弄的我一頭霧水,找不到北。有的文章提到32位的操作系統及Oracle,SGA應該不高于1.7G,這是32位系統的上限。后來我把SGA調到小于1.7G就OK了。后來我試著更改kernel.shmmax的值,當改為4G后再運行DBCA建庫,會報ORA-27101(可能是這個號),out of memory的問題,內存溢出。有文章說到應該改limits.conf設置,去掉限制。但對此我還沒有進行嘗試。
9、Oracle的自啟動
在這個問題上我花費了不少時間,一開始在/etc/init.d/目錄下建dbora啟動腳本的時候有問題,系統重啟的時候一會執行一會不執行。后來根據別的文章采用令一種辦法:
這時你可以試試手動啟動及關閉oracle服務:
service dbora start
service dbora stop
總結:
現在的服務器配置越來越高,我的這臺機器是dell2950,4核CPU×2,8G內存,64位。因為沒有64位的redhat系統盤,只好操作系統及oracle都裝的32位的,這點很不爽。所以64位的硬件最好還是裝64位的系統及軟件,否則硬件上會有限制,不能充分利用。
Oracle Server - Enterprise Edition - Version: 9.2.0.1 to 10.2.0.3
Linux x86
ORA-27102, Out of memory error
For 32 bit system running smp kernel, we cannot have SGA > 1.7 GB directly. This is because of
limitation of 32 bit systems of not being able to address memory > 4GB directly by a user process.
If SGA is kept higher than 1.7 GB, it will results in ORA 27102 errors.
While invoking dbca or creating starter database, by default it takes 40% of memory for SGA.
Hence the size can accidentally exceed 1.7 GB
The workaround is to create a new database, and specify the size of SGA approximate to be 1.5 to
1.7 GB.
Note 260152.1 - Summary About the Large SGA & Address Space on RH Linux
ORA-27102 out of memory
http://hmily.blueidea.com/archives/2007/4508.shtml
目錄:
一、術語session
二、HTTP協議與狀態保持
三、理解cookie機制
四、理解session機制
五、理解javax.servlet.http.HttpSession
六、HttpSession常見問題
七、跨應用程序的session共享
八、總結
參考文檔
一、術語session
在我的經驗里,session這個詞被濫用的程度大概僅次于transaction,更加有趣的是transaction與session在某些語境下的含義是相同的。
session,中文經常翻譯為會話,其本來的含義是指有始有終的一系列動作/消息,比如打電話時從拿起電話撥號到掛斷電話這中間的一系列過程可以稱之為一個 session。有時候我們可以看到這樣的話“在一個瀏覽器會話期間,...”,這里的會話一詞用的就是其本義,是指從一個瀏覽器窗口打開到關閉這個期間 ①。最混亂的是“用戶(客戶端)在一次會話期間”這樣一句話,它可能指用戶的一系列動作(一般情況下是同某個具體目的相關的一系列動作,比如從登錄到選購商品到結賬登出這樣一個網上購物的過程,有時候也被稱為一個transaction),然而有時候也可能僅僅是指一次連接,也有可能是指含義①,其中的差別只能靠上下文來推斷②。
然而當session一詞與網絡協議相關聯時,它又往往隱含了“面向連接”和/或“保持狀態”這樣兩個含義, “面向連接”指的是在通信雙方在通信之前要先建立一個通信的渠道,比如打電話,直到對方接了電話通信才能開始,與此相對的是寫信,在你把信發出去的時候你并不能確認對方的地址是否正確,通信渠道不一定能建立,但對發信人來說,通信已經開始了。“保持狀態”則是指通信的一方能夠把一系列的消息關聯起來,使得消息之間可以互相依賴,比如一個服務員能夠認出再次光臨的老顧客并且記得上次這個顧客還欠店里一塊錢。這一類的例子有“一個TCP session”或者 “一個POP3 session”③。
而到了web服務器蓬勃發展的時代,session在web開發語境下的語義又有了新的擴展,它的含義是指一類用來在客戶端與服務器之間保持狀態的解決方案④。有時候session也用來指這種解決方案的存儲結構,如“把xxx保存在session 里”⑤。由于各種用于web開發的語言在一定程度上都提供了對這種解決方案的支持,所以在某種特定語言的語境下,session也被用來指代該語言的解決方案,比如經常把Java里提供的javax.servlet.http.HttpSession簡稱為session⑥。
鑒于這種混亂已不可改變,本文中session一詞的運用也會根據上下文有不同的含義,請大家注意分辨。
在本文中,使用中文“瀏覽器會話期間”來表達含義①,使用“session機制”來表達含義④,使用“session”表達含義⑤,使用具體的“HttpSession”來表達含義⑥
二、HTTP協議與狀態保持
HTTP 協議本身是無狀態的,這與HTTP協議本來的目的是相符的,客戶端只需要簡單的向服務器請求下載某些文件,無論是客戶端還是服務器都沒有必要紀錄彼此過去的行為,每一次請求之間都是獨立的,好比一個顧客和一個自動售貨機或者一個普通的(非會員制)大賣場之間的關系一樣。
然而聰明(或者貪心?)的人們很快發現如果能夠提供一些按需生成的動態信息會使web變得更加有用,就像給有線電視加上點播功能一樣。這種需求一方面迫使HTML逐步添加了表單、腳本、DOM等客戶端行為,另一方面在服務器端則出現了CGI規范以響應客戶端的動態請求,作為傳輸載體的HTTP協議也添加了文件上載、 cookie這些特性。其中cookie的作用就是為了解決HTTP協議無狀態的缺陷所作出的努力。至于后來出現的session機制則是又一種在客戶端與服務器之間保持狀態的解決方案。
讓我們用幾個例子來描述一下cookie和session機制之間的區別與聯系。筆者曾經常去的一家咖啡店有喝5杯咖啡免費贈一杯咖啡的優惠,然而一次性消費5杯咖啡的機會微乎其微,這時就需要某種方式來紀錄某位顧客的消費數量。想象一下其實也無外乎下面的幾種方案:
1、該店的店員很厲害,能記住每位顧客的消費數量,只要顧客一走進咖啡店,店員就知道該怎么對待了。這種做法就是協議本身支持狀態。
2、發給顧客一張卡片,上面記錄著消費的數量,一般還有個有效期限。每次消費時,如果顧客出示這張卡片,則此次消費就會與以前或以后的消費相聯系起來。這種做法就是在客戶端保持狀態。
3、發給顧客一張會員卡,除了卡號之外什么信息也不紀錄,每次消費時,如果顧客出示該卡片,則店員在店里的紀錄本上找到這個卡號對應的紀錄添加一些消費信息。這種做法就是在服務器端保持狀態。
由于HTTP協議是無狀態的,而出于種種考慮也不希望使之成為有狀態的,因此,后面兩種方案就成為現實的選擇。具體來說cookie機制采用的是在客戶端保持狀態的方案,而session機制采用的是在服務器端保持狀態的方案。同時我們也看到,由于采用服務器端保持狀態的方案在客戶端也需要保存一個標識,所以session機制可能需要借助于cookie機制來達到保存標識的目的,但實際上它還有其他選擇。
三、理解cookie機制
cookie機制的基本原理就如上面的例子一樣簡單,但是還有幾個問題需要解決:“會員卡”如何分發;“會員卡”的內容;以及客戶如何使用“會員卡”。
正統的cookie分發是通過擴展HTTP協議來實現的,服務器通過在HTTP的響應頭中加上一行特殊的指示以提示瀏覽器按照指示生成相應的cookie。然而純粹的客戶端腳本如JavaScript或者VBScript也可以生成cookie。
而cookie 的使用是由瀏覽器按照一定的原則在后臺自動發送給服務器的。瀏覽器檢查所有存儲的cookie,如果某個cookie所聲明的作用范圍大于等于將要請求的資源所在的位置,則把該cookie附在請求資源的HTTP請求頭上發送給服務器。意思是麥當勞的會員卡只能在麥當勞的店里出示,如果某家分店還發行了自己的會員卡,那么進這家店的時候除了要出示麥當勞的會員卡,還要出示這家店的會員卡。
cookie的內容主要包括:名字,值,過期時間,路徑和域。
其中域可以指定某一個域比如.google.com,相當于總店招牌,比如寶潔公司,也可以指定一個域下的具體某臺機器比如www.google.com或者froogle.google.com,可以用飄柔來做比。
路徑就是跟在域名后面的URL路徑,比如/或者/foo等等,可以用某飄柔專柜做比。
路徑與域合在一起就構成了cookie的作用范圍。
如果不設置過期時間,則表示這個cookie的生命期為瀏覽器會話期間,只要關閉瀏覽器窗口,cookie就消失了。這種生命期為瀏覽器會話期的 cookie被稱為會話cookie。會話cookie一般不存儲在硬盤上而是保存在內存里,當然這種行為并不是規范規定的。如果設置了過期時間,瀏覽器就會把cookie保存到硬盤上,關閉后再次打開瀏覽器,這些cookie仍然有效直到超過設定的過期時間。
存儲在硬盤上的cookie 可以在不同的瀏覽器進程間共享,比如兩個IE窗口。而對于保存在內存里的cookie,不同的瀏覽器有不同的處理方式。對于IE,在一個打開的窗口上按 Ctrl-N(或者從文件菜單)打開的窗口可以與原窗口共享,而使用其他方式新開的IE進程則不能共享已經打開的窗口的內存cookie;對于 Mozilla Firefox0.8,所有的進程和標簽頁都可以共享同樣的cookie。一般來說是用javascript的window.open打開的窗口會與原窗口共享內存cookie。瀏覽器對于會話cookie的這種只認cookie不認人的處理方式經常給采用session機制的web應用程序開發者造成很大的困擾。
下面就是一個goolge設置cookie的響應頭的例子
HTTP/1.1 302 Found
Location: http://www.google.com/intl/zh-CN/
Set-Cookie: PREF=ID=0565f77e132de138:NW=1:TM=1098082649:LM=1098082649:S=KaeaCFPo49RiA_d8; expires=Sun, 17-Jan-2038 19:14:07 GMT; path=/; domain=.google.com
Content-Type: text/html
這是使用HTTPLook這個HTTP Sniffer軟件來俘獲的HTTP通訊紀錄的一部分
瀏覽器在再次訪問goolge的資源時自動向外發送cookie
使用Firefox可以很容易的觀察現有的cookie的值
使用HTTPLook配合Firefox可以很容易的理解cookie的工作原理。
IE也可以設置在接受cookie前詢問
這是一個詢問接受cookie的對話框。
四、理解session機制
session機制是一種服務器端的機制,服務器使用一種類似于散列表的結構(也可能就是使用散列表)來保存信息。
當程序需要為某個客戶端的請求創建一個session的時候,服務器首先檢查這個客戶端的請求里是否已包含了一個session標識 - 稱為 session id,如果已包含一個session id則說明以前已經為此客戶端創建過session,服務器就按照session id把這個 session檢索出來使用(如果檢索不到,可能會新建一個),如果客戶端請求不包含session id,則為此客戶端創建一個session并且生成一個與此session相關聯的session id,session id的值應該是一個既不會重復,又不容易被找到規律以仿造的字符串,這個 session id將被在本次響應中返回給客戶端保存。
保存這個session id的方式可以采用cookie,這樣在交互過程中瀏覽器可以自動的按照規則把這個標識發揮給服務器。一般這個cookie的名字都是類似于SEEESIONID,而。比如weblogic對于web應用程序生成的cookie,JSESSIONID= ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764,它的名字就是 JSESSIONID。
由于cookie可以被人為的禁止,必須有其他機制以便在cookie被禁止時仍然能夠把session id傳遞回服務器。經常被使用的一種技術叫做URL重寫,就是把session id直接附加在URL路徑的后面,附加方式也有兩種,一種是作為URL路徑的附加信息,表現形式為http://...../xxx;jsessionid= ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764
另一種是作為查詢字符串附加在URL后面,表現形式為http://...../xxx?jsessionid=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764
這兩種方式對于用戶來說是沒有區別的,只是服務器在解析的時候處理的方式不同,采用第一種方式也有利于把session id的信息和正常程序參數區分開來。
為了在整個交互過程中始終保持狀態,就必須在每個客戶端可能請求的路徑后面都包含這個session id。
另一種技術叫做表單隱藏字段。就是服務器會自動修改表單,添加一個隱藏字段,以便在表單提交時能夠把session id傳遞回服務器。比如下面的表單
<form name="testform" action="/xxx">
<input type="text">
</form>
在被傳遞給客戶端之前將被改寫成
<form name="testform" action="/xxx">
<input type="hidden" name="jsessionid" value="ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764">
<input type="text">
</form>
這種技術現在已較少應用,筆者接觸過的很古老的iPlanet6(SunONE應用服務器的前身)就使用了這種技術。
實際上這種技術可以簡單的用對action應用URL重寫來代替。
在談論session機制的時候,常常聽到這樣一種誤解“只要關閉瀏覽器,session就消失了”。其實可以想象一下會員卡的例子,除非顧客主動對店家提出銷卡,否則店家絕對不會輕易刪除顧客的資料。對session來說也是一樣的,除非程序通知服務器刪除一個session,否則服務器會一直保留,程序一般都是在用戶做log off的時候發個指令去刪除session。然而瀏覽器從來不會主動在關閉之前通知服務器它將要關閉,因此服務器根本不會有機會知道瀏覽器已經關閉,之所以會有這種錯覺,是大部分session機制都使用會話cookie來保存session id,而關閉瀏覽器后這個 session id就消失了,再次連接服務器時也就無法找到原來的session。如果服務器設置的cookie被保存到硬盤上,或者使用某種手段改寫瀏覽器發出的HTTP請求頭,把原來的session id發送給服務器,則再次打開瀏覽器仍然能夠找到原來的session。
恰恰是由于關閉瀏覽器不會導致session被刪除,迫使服務器為seesion設置了一個失效時間,當距離客戶端上一次使用session的時間超過這個失效時間時,服務器就可以認為客戶端已經停止了活動,才會把session刪除以節省存儲空間。
五、理解javax.servlet.http.HttpSession
HttpSession是Java平臺對session機制的實現規范,因為它僅僅是個接口,具體到每個web應用服務器的提供商,除了對規范支持之外,仍然會有一些規范里沒有規定的細微差異。這里我們以BEA的Weblogic Server8.1作為例子來演示。
首先,Weblogic Server提供了一系列的參數來控制它的HttpSession的實現,包括使用cookie的開關選項,使用URL重寫的開關選項,session持久化的設置,session失效時間的設置,以及針對cookie的各種設置,比如設置cookie的名字、路徑、域, cookie的生存時間等。
一般情況下,session都是存儲在內存里,當服務器進程被停止或者重啟的時候,內存里的session也會被清空,如果設置了session的持久化特性,服務器就會把session保存到硬盤上,當服務器進程重新啟動或這些信息將能夠被再次使用, Weblogic Server支持的持久性方式包括文件、數據庫、客戶端cookie保存和復制。
復制嚴格說來不算持久化保存,因為session實際上還是保存在內存里,不過同樣的信息被復制到各個cluster內的服務器進程中,這樣即使某個服務器進程停止工作也仍然可以從其他進程中取得session。
cookie生存時間的設置則會影響瀏覽器生成的cookie是否是一個會話cookie。默認是使用會話cookie。有興趣的可以用它來試驗我們在第四節里提到的那個誤解。
cookie的路徑對于web應用程序來說是一個非常重要的選項,Weblogic Server對這個選項的默認處理方式使得它與其他服務器有明顯的區別。后面我們會專題討論。
關于session的設置參考[5] http://e-docs.bea.com/wls/docs70/webapp/weblogic_xml.html#1036869
六、HttpSession常見問題
(在本小節中session的含義為⑤和⑥的混合)
1、session在何時被創建
一個常見的誤解是以為session在有客戶端訪問時就被創建,然而事實是直到某server端程序調用 HttpServletRequest.getSession(true)這樣的語句時才被創建,注意如果JSP沒有顯示的使用 <% @page session="false"%> 關閉session,則JSP文件在編譯成Servlet時將會自動加上這樣一條語句 HttpSession session = HttpServletRequest.getSession(true);這也是JSP中隱含的 session對象的來歷。
由于session會消耗內存資源,因此,如果不打算使用session,應該在所有的JSP中關閉它。
2、session何時被刪除
綜合前面的討論,session在下列情況下被刪除a.程序調用HttpSession.invalidate();或b.距離上一次收到客戶端發送的session id時間間隔超過了session的超時設置;或c.服務器進程被停止(非持久session)
3、如何做到在瀏覽器關閉時刪除session
嚴格的講,做不到這一點。可以做一點努力的辦法是在所有的客戶端頁面里使用javascript代碼window.oncolose來監視瀏覽器的關閉動作,然后向服務器發送一個請求來刪除session。但是對于瀏覽器崩潰或者強行殺死進程這些非常規手段仍然無能為力。
4、有個HttpSessionListener是怎么回事
你可以創建這樣的listener去監控session的創建和銷毀事件,使得在發生這樣的事件時你可以做一些相應的工作。注意是session的創建和銷毀動作觸發listener,而不是相反。類似的與HttpSession有關的listener還有 HttpSessionBindingListener,HttpSessionActivationListener和 HttpSessionAttributeListener。
5、存放在session中的對象必須是可序列化的嗎
不是必需的。要求對象可序列化只是為了session能夠在集群中被復制或者能夠持久保存或者在必要時server能夠暫時把session交換出內存。在 Weblogic Server的session中放置一個不可序列化的對象在控制臺上會收到一個警告。我所用過的某個iPlanet版本如果 session中有不可序列化的對象,在session銷毀時會有一個Exception,很奇怪。
6、如何才能正確的應付客戶端禁止cookie的可能性
對所有的URL使用URL重寫,包括超鏈接,form的action,和重定向的URL,具體做法參見[6]
http://e-docs.bea.com/wls/docs70/webapp/sessions.html#100770
7、開兩個瀏覽器窗口訪問應用程序會使用同一個session還是不同的session
參見第三小節對cookie的討論,對session來說是只認id不認人,因此不同的瀏覽器,不同的窗口打開方式以及不同的cookie存儲方式都會對這個問題的答案有影響。
8、如何防止用戶打開兩個瀏覽器窗口操作導致的session混亂
這個問題與防止表單多次提交是類似的,可以通過設置客戶端的令牌來解決。就是在服務器每次生成一個不同的id返回給客戶端,同時保存在session里,客戶端提交表單時必須把這個id也返回服務器,程序首先比較返回的id與保存在session里的值是否一致,如果不一致則說明本次操作已經被提交過了。可以參看《J2EE核心模式》關于表示層模式的部分。需要注意的是對于使用javascript window.open打開的窗口,一般不設置這個id,或者使用單獨的id,以防主窗口無法操作,建議不要再window.open打開的窗口里做修改操作,這樣就可以不用設置。
9、為什么在Weblogic Server中改變session的值后要重新調用一次session.setValue
做這個動作主要是為了在集群環境中提示Weblogic Server session中的值發生了改變,需要向其他服務器進程復制新的session值。
10、為什么session不見了
排除session正常失效的因素之外,服務器本身的可能性應該是微乎其微的,雖然筆者在iPlanet6SP1加若干補丁的Solaris版本上倒也遇到過;瀏覽器插件的可能性次之,筆者也遇到過3721插件造成的問題;理論上防火墻或者代理服務器在cookie處理上也有可能會出現問題。
出現這一問題的大部分原因都是程序的錯誤,最常見的就是在一個應用程序中去訪問另外一個應用程序。我們在下一節討論這個問題。
七、跨應用程序的session共享
常常有這樣的情況,一個大項目被分割成若干小項目開發,為了能夠互不干擾,要求每個小項目作為一個單獨的web應用程序開發,可是到了最后突然發現某幾個小項目之間需要共享一些信息,或者想使用session來實現SSO(single sign on),在session中保存login的用戶信息,最自然的要求是應用程序間能夠訪問彼此的session。
然而按照Servlet規范,session的作用范圍應該僅僅限于當前應用程序下,不同的應用程序之間是不能夠互相訪問對方的session的。各個應用服務器從實際效果上都遵守了這一規范,但是實現的細節卻可能各有不同,因此解決跨應用程序session共享的方法也各不相同。
首先來看一下Tomcat是如何實現web應用程序之間session的隔離的,從 Tomcat設置的cookie路徑來看,它對不同的應用程序設置的cookie路徑是不同的,這樣不同的應用程序所用的session id是不同的,因此即使在同一個瀏覽器窗口里訪問不同的應用程序,發送給服務器的session id也可以是不同的。
根據這個特性,我們可以推測Tomcat中session的內存結構大致如下。
筆者以前用過的iPlanet也采用的是同樣的方式,估計SunONE與iPlanet之間不會有太大的差別。對于這種方式的服務器,解決的思路很簡單,實際實行起來也不難。要么讓所有的應用程序共享一個session id,要么讓應用程序能夠獲得其他應用程序的session id。
iPlanet中有一種很簡單的方法來實現共享一個session id,那就是把各個應用程序的cookie路徑都設為/(實際上應該是/NASApp,對于應用程序來講它的作用相當于根)。
<session-info>
<path>/NASApp</path>
</session-info>
需要注意的是,操作共享的session應該遵循一些編程約定,比如在session attribute名字的前面加上應用程序的前綴,使得 setAttribute("name", "neo")變成setAttribute("app1.name", "neo"),以防止命名空間沖突,導致互相覆蓋。
在Tomcat中則沒有這么方便的選擇。在Tomcat版本3上,我們還可以有一些手段來共享session。對于版本4以上的Tomcat,目前筆者尚未發現簡單的辦法。只能借助于第三方的力量,比如使用文件、數據庫、JMS或者客戶端cookie,URL參數或者隱藏字段等手段。
我們再看一下Weblogic Server是如何處理session的。
從截屏畫面上可以看到Weblogic Server對所有的應用程序設置的cookie的路徑都是/,這是不是意味著在Weblogic Server中默認的就可以共享session了呢?然而一個小實驗即可證明即使不同的應用程序使用的是同一個session,各個應用程序仍然只能訪問自己所設置的那些屬性。這說明Weblogic Server中的session的內存結構可能如下
對于這樣一種結構,在 session機制本身上來解決session共享的問題應該是不可能的了。除了借助于第三方的力量,比如使用文件、數據庫、JMS或者客戶端 cookie,URL參數或者隱藏字段等手段,還有一種較為方便的做法,就是把一個應用程序的session放到ServletContext中,這樣另外一個應用程序就可以從ServletContext中取得前一個應用程序的引用。示例代碼如下,
應用程序A
context.setAttribute("appA", session);
應用程序B
contextA = context.getContext("/appA");
HttpSession sessionA = (HttpSession)contextA.getAttribute("appA");
值得注意的是這種用法不可移植,因為根據ServletContext的JavaDoc,應用服務器可以處于安全的原因對于context.getContext("/appA");返回空值,以上做法在Weblogic Server 8.1中通過。
那么Weblogic Server為什么要把所有的應用程序的cookie路徑都設為/呢?原來是為了SSO,凡是共享這個session的應用程序都可以共享認證的信息。一個簡單的實驗就可以證明這一點,修改首先登錄的那個應用程序的描述符weblogic.xml,把cookie路徑修改為/appA 訪問另外一個應用程序會重新要求登錄,即使是反過來,先訪問cookie路徑為/的應用程序,再訪問修改過路徑的這個,雖然不再提示登錄,但是登錄的用戶信息也會丟失。注意做這個實驗時認證方式應該使用FORM,因為瀏覽器和web服務器對basic認證方式有其他的處理方式,第二次請求的認證不是通過 session來實現的。具體請參看[7] secion 14.8 Authorization,你可以修改所附的示例程序來做這些試驗。
八、總結
session機制本身并不復雜,然而其實現和配置上的靈活性卻使得具體情況復雜多變。這也要求我們不能把僅僅某一次的經驗或者某一個瀏覽器,服務器的經驗當作普遍適用的經驗,而是始終需要具體情況具體分析。
摘要:雖然session機制在web應用程序中被采用已經很長時間了,但是仍然有很多人不清楚session機制的本質,以至不能正確的應用這一技術。本文將詳細討論session的工作機制并且對在Java web application中應用session機制時常見的問題作出解答。