近日由于老師的要求及學(xué)習的需要谅年,要使用安卓搭建HTTP Server,思路上和平常搭建HTTP Server沒什么區(qū)別肮韧,只不過現(xiàn)在的載體是手機融蹂。存在一個較大的問題,就是以前沒有接觸過HTTP Server弄企,雖然之前的編程中對HTTP協(xié)議有過一定的了解超燃,但是對自己搭建一個HTTP Server而言還遠遠不足。
搭建這樣一個HTTP Server拘领,首要解決的問題就是如何開始意乓。如何邁出第一步,開始時我是有些糾結(jié)的约素,而google官方是有一個例子的届良,叫做SimpleWebServer,顯而易見圣猎,這個例子就搭建了一個簡單的服務(wù)器士葫,從例子中可以看到,這個例子采用了java中的ServerSocket和Socket來建立連接送悔,而且這個例子只能允許一個客戶端連接慢显,返回簡單的信息。這就給了我一個初步的思路了欠啤,要想建立自己的http server荚藻,我的想法就是模仿SimpleWebServer來建立,使用ServerSocket來連接洁段,不過要實現(xiàn)多線程鞋喇,這樣才能允許多客戶端連接。
原先的思路有些錯誤了眉撵,原先的思路里面,總覺得客戶端與服務(wù)器的交互是類似于人這樣的落塑,當客戶端請求數(shù)據(jù)時要對客戶端進行標識纽疟,否則不同的客戶端之間容易發(fā)生沖突。后來發(fā)現(xiàn)其實都是定義好的憾赁,客戶端可以執(zhí)行的操作都是由服務(wù)器定義好的污朽,服務(wù)器對自己定義的操作進行了識別,并且返回相應(yīng)的處理龙考,對其他不能識別的操作則返回錯誤蟆肆。這樣的思路處理起來就簡單了矾睦,客戶端執(zhí)行操作,服務(wù)器在接收到客戶端的請求時就“直接”進行處理炎功,并不保存客戶端的任何信息枚冗,在http 1.1中雖然可以保持客戶端的長連接,但是不過是保持連接不被關(guān)閉蛇损,減少建立連接的資源赁温,并不代表服務(wù)端應(yīng)用層及應(yīng)用要保存客戶端的信息,應(yīng)用層及應(yīng)用在接收到客戶端的請求時對相應(yīng)的請求進行處理及反饋淤齐,反饋結(jié)果送入運輸層股囊,此時就不再于服務(wù)端的應(yīng)用有關(guān),而由TCP/IP協(xié)議向客戶端發(fā)送反饋更啄。
接下來一個問題就是http server返回信息的格式的處理稚疹,返回信息要符合http協(xié)議中的響應(yīng)頭格式,我們可以在服務(wù)器中每個相應(yīng)的處理里面寫響應(yīng)頭的格式祭务,顯然這樣會顯得冗余内狗,代碼上重復(fù)的部分太多,一開始對服務(wù)器進行測試時還可這樣簡單的寫一寫待牵,后面要將響應(yīng)頭這里封裝到Response類中其屏,讓這個類負責對返回信息進行處理,服務(wù)器向這個類傳遞需要發(fā)送的數(shù)據(jù)缨该,為這個類設(shè)定發(fā)送的狀態(tài)及一些必要的格式偎行,這個類則返回給服務(wù)器封裝的發(fā)送的數(shù)據(jù),其后將數(shù)據(jù)發(fā)送給客戶端贰拿。
建立HTTP Server存在的一個難點蛤袒,也是重點,就是面對的客戶端是多種多樣的膨更,而不是確定的某一樣客戶端妙真,為了適配更多的客戶端,獲得更好的兼容性荚守,就要看對HTTP協(xié)議的理解了珍德,也就是上面所說的返回信息的格式的處理。HTTP協(xié)議的請求響應(yīng)等內(nèi)容反復(fù)看了多次矗漾,加上對一些網(wǎng)絡(luò)上其他人的代碼的理解锈候,建議是最好能閱讀RFC文檔,第一手資料敞贡,詳細準確泵琳。
在我的建立過程中,參考了nanohttpd,這里網(wǎng)絡(luò)上的一個開源的java庫获列,實現(xiàn)了http server的一些功能谷市,使用這個nanohttpd,在android手機上完成了一個http的服務(wù)器击孩,實現(xiàn)了下載文件的功能迫悠,即android手機作為http服務(wù)端,可以從手機中選取文件分享溯壶,電腦則可以通過瀏覽器從android手機中下載手機中分享的文件及皂。
完成了文件分享下載的功能后,接下來的一步就是文件的上傳了且改,如何將文件上傳验烧,這又是另外一個問題。這里有個地方要特別提醒下又跛,在安卓手機上完成HTTP Server碍拆,要注意權(quán)限的問題,權(quán)限一定要設(shè)置好慨蓝,否則又無法實現(xiàn)功能感混,又難以定位錯誤。文件上傳礼烈,一開始使用的是post弧满,后來經(jīng)過多方資料的查找,使用put是更好的方式此熬。簡單在代碼中添加了H5的表單庭呜,暫時沒有測試,完成后會在后文說明犀忱。
使用nanohttpd完成了文件的下載后募谎,自然而然的想通過nanohttpd來完成文件的上傳功能,nanohttpd是一個優(yōu)秀的開源庫阴汇,可惜我在測試時忘記在添加寫權(quán)限数冬,導(dǎo)致功能無法完成,過了好久才發(fā)現(xiàn)錯誤搀庶,只能說要特別注意特別小心拐纱。因為在此處無法正常上傳文件,自己也不知道為什么哥倔,懷疑是對nanohttpd的源碼理解不夠戳玫,所以打算重新寫,而且在使用nanohttpd開發(fā)的過程中未斑,自身也對HTTP協(xié)議理解的更加深刻了,如使用java代碼完成HTTP Server的開發(fā),會比使用他人的開源庫更得心應(yīng)手蜡秽。于是打算自己完成整個HTTP Server的內(nèi)容了府阀。
一開始對java nio中的內(nèi)容有些一知半解,對ServerSocketChannel及SocketChannel的內(nèi)容不是很明白芽突,就憑借著一知半解打算使用這兩個類來建立httpserver试浙,代碼寫的很開心,參照了一些網(wǎng)路上的資料寞蚌,運行卻總是不成功田巴。打個Log發(fā)現(xiàn),一直處于死循環(huán)的狀態(tài)挟秤,本來在收到來自客戶端的請求以后壹哺,就應(yīng)該進入某個for循環(huán)中,卻不知為什么始終無法進去艘刚,抓包也覺得沒有問題管宵,打了log也覺得沒有問題,沒有問題就是最大的問題吧攀甚,一直不成功箩朴,于是就放棄。改用傳統(tǒng)的多線程來實現(xiàn)秋度。
傳統(tǒng)的多線程實現(xiàn)炸庞,使用了一個線程池,采用這種方式建立荚斯,即使用serversocket 和socket來建立埠居。serversocket接收一個連接請求,返回一個socket鲸拥,這個socket建立一個線程拐格,線程中對socket的請求進行處理,將線程交給線程池刑赶,serversocket 繼續(xù)監(jiān)聽端口捏浊,等待后面的連接。下面講講整個操作的過程撞叨。
監(jiān)聽并獲取到socket后金踪,交由單獨的客戶線程處理,客戶線程從socket中獲取inputStream和outputStream牵敷,從inputStream中讀取byte流胡岔,將byte流分析得到http的首部及內(nèi)容,即可進行操作枷餐。
這里的HTTP Server做的簡單靶瘸,只支持get和post兩個方法,get方法用于向HTTP Server請求資源,即數(shù)據(jù)下載怨咪,這里倒是簡單些屋剑,有些問題的地方是安卓的文件選擇器問題,文件選擇器選擇的文件路徑容易有問題诗眨,得到的路徑不是絕對路徑唉匾,需要專門做些處理。同樣也要注意權(quán)限的問題匠楚。
get方法的處理較為簡單些巍膘,從客戶端的socket 中讀取到客戶端請求的數(shù)據(jù),而后使用fileinputstream讀取文件芋簿,使用outputstream向客戶端發(fā)送數(shù)據(jù)峡懈。發(fā)送完畢后將fileinputstream和outputstream關(guān)閉,即完成一次傳輸益咬。需要注意的是逮诲,客戶端瀏覽器可以通過服務(wù)器返回的html中包含的文件信息選擇下載,而客戶端是不確定的幽告,如果不管客戶端請求什么都向客戶端發(fā)送梅鹦,顯然安全性是不夠好的,于是添加判斷冗锁,只有分享的文件才可以被訪問齐唆,其他文件不可。
post方法的處理較為復(fù)雜冻河,因為這是向HTTP Server發(fā)送文件箍邮,HTTP Server上要接收文件,并且將文件保存到本地叨叙,操作起來復(fù)雜度較高锭弊。由于HTTP協(xié)議特點,要先從http協(xié)議的首部獲取boundary字段值擂错,boundary字段值是文件分隔符味滞,也是文件部分開始的符號,結(jié)束符號是在boundary字段值后面添加“--”钮呀。第一次使用了Scanner來讀取數(shù)據(jù)剑鞍,但是Scanner不會讀入換行符,在沒有讀到換行符或者結(jié)束之前會阻塞爽醋,這就是個比較嚴重的問題了蚁署。文件因為缺少幾個字節(jié),導(dǎo)致上傳一直不成功蚂四。后來使用BufferedReader 或者BufferedInputStream都有相似的問題光戈。最后決定直接使用InputStream來讀取文件哪痰。因為是流的處理,多一個字節(jié)少一個字節(jié)都要特別小心久妆,不能出錯妒御。否則整個讀取的過程就會失敗。使用byte數(shù)組讀取镇饺,寫入文件時要特別小心,從inputStream中讀取了多少byte送讲,就向文件中寫入多少byte奸笤,否則會出錯,當遇到文件結(jié)束符時退出哼鬓,不退出就會阻塞监右,導(dǎo)致失敗。
完成了這些基本功能后异希,HTTP Server的基礎(chǔ)算是完成了健盒,接下來要解決的就是一些其他的問題了,例如解決下載續(xù)傳的問題称簿,這些地方就見仁見智了扣癣,不同的人有不同的想法,能做的也不一樣憨降。就沒什么可以多說了父虑。實話說來,在手機端完成一個HTTP Server不難也不簡單授药,看個人想法吧士嚎。
HTTP Server 漫談
最后編輯于 :
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
- 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來岔激,“玉大人勒极,你說我怎么就攤上這事÷嵌Γ” “怎么了辱匿?”我有些...
- 文/不壞的土叔 我叫張陵键痛,是天一觀的道長。 經(jīng)常有香客問我匾七,道長絮短,這世上最難降的妖魔是什么? 我笑而不...
- 正文 為了忘掉前任昨忆,我火速辦了婚禮丁频,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘邑贴。我一直安慰自己席里,他們只是感情好,可當我...
- 文/花漫 我一把揭開白布拢驾。 她就那樣靜靜地躺著奖磁,像睡著了一般。 火紅的嫁衣襯著肌膚如雪繁疤。 梳的紋絲不亂的頭發(fā)上咖为,一...
- 文/蒼蘭香墨 我猛地睜開眼鳖昌,長吁一口氣:“原來是場噩夢啊……” “哼备畦!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起许昨,我...
- 正文 年R本政府宣布汽久,位于F島的核電站,受9級特大地震影響踊餐,放射性物質(zhì)發(fā)生泄漏景醇。R本人自食惡果不足惜,卻給世界環(huán)境...
- 文/蒙蒙 一吝岭、第九天 我趴在偏房一處隱蔽的房頂上張望三痰。 院中可真熱鬧,春花似錦窜管、人聲如沸酒觅。這莊子的主人今日做“春日...
- 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至抒钱,卻和暖如春蜓肆,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背谋币。 一陣腳步聲響...
推薦閱讀更多精彩內(nèi)容
- Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)调炬,斷路器语盈,智...
- 一、概念(載錄于:http://www.cnblogs.com/EricaMIN1987_IT/p/3837436...
- Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
- 優(yōu)秀文章推薦 給 Android 開發(fā)者的 RxJava 詳解http://gank.io/post/560e15...