很多小伙伴跟我说,学习网络太难了,怎么办?其实很多技术都是相通的,只要你理解了技术的本质,你自己都可以实现它。这不,冰河就趁着周末,只用了几个<em>Java</em>类就简单的实现了Http协议,爽!!小伙伴们点赞,收藏,评论,走起呀~~HTT..
2021-05-24 09:30:28
大家好,我是冰河~~
很多小夥伴跟我說,學習網路太難了,怎麼辦?其實很多技術都是相通的,只要你理解了技術的本質,你自己都可以實現它。這不,冰河就趁著週末,只用了幾個Java類就簡單的實現了Http協議,爽!!小夥伴們點贊,收藏,評論,走起呀~~
HTTP協議屬於應用層協議,它構建於TCP和IP協議之上,處於TCP/IP協議架構層的頂端,所以,它不用處理下層協議間諸如丟包補發、握手及資料的分段及重新組裝等繁瑣的細節,使開發人員可以專注於應用業務。
協議是通訊的規範,為了更好的理解HTTP協議,我們可以基於Java的Socket API介面,通過設計一個簡單的應用層通訊協議,來簡單分析下協議實現的過程和細節。
在我們今天的示例程式中,客戶端會向服務端傳送一條命令,服務端在接收到命令後,會判斷命令是否是「HELLO」,如果是「HELLO」, 則服務端返回給客戶端的響應為「hello」,否則,服務端返回給客戶端的響應為「bye bye」。
我們接下來用Java實現這個簡單的應用層通訊協議,說幹就幹,走起~~
協議請求的定義
協議的請求主要包括:編碼、命令和命令長度三個欄位。
package com.binghe.params;/** * 協議請求的定義 * @author binghe * */publicclassRequest{ /** * 協議編碼 */privatebyte encode;/** * 命令 */private String command;/** * 命令長度 */privateint commandLength;publicRequest(){ super();}publicRequest(byte encode, String command,int commandLength){ super();this.encode = encode;this.command = command;this.commandLength = commandLength;}publicbytegetEncode(){ return encode;}publicvoidsetEncode(byte encode){ this.encode = encode;}public String getCommand(){ return command;}publicvoidsetCommand(String command){ this.command = command;}publicintgetCommandLength(){ return commandLength;}publicvoidsetCommandLength(int commandLength){ this.commandLength = commandLength;}@Overridepublic String toString(){ return"Request [encode="+ encode +", command="+ command +", commandLength="+ commandLength +"]";}}
響應協議的定義
協議的響應主要包括:編碼、響應內容和響應長度三個欄位。
package com.binghe.params;/** * 協議響應的定義 * @author binghe * */publicclassResponse{ /** * 編碼 */privatebyte encode;/** * 響應內容 */private String response;/** * 響應長度 */privateint responseLength;publicResponse(){ super();}publicResponse(byte encode, String response,int responseLength){ super();this.encode = encode;this.response = response;this.responseLength = responseLength;}publicbytegetEncode(){ return encode;}publicvoidsetEncode(byte encode){ this.encode = encode;}public String getResponse(){ return response;}publicvoidsetResponse(String response){ this.response = response;}publicintgetResponseLength(){ return responseLength;}publicvoidsetResponseLength(int responseLength){ this.responseLength = responseLength;}@Overridepublic String toString(){ return"Response [encode="+ encode +", response="+ response +", responseLength="+ responseLength +"]";}}
編碼常量定義
編碼常量的定義主要包括UTF-8和GBK兩種編碼。
package com.binghe.constant;/** * 常量類 * @author binghe * */publicfinalclassEncode{ //UTF-8編碼publicstaticfinalbyte UTF8 =1;//GBK編碼publicstaticfinalbyte GBK =2;}
客戶端的實現
客戶端先構造一個request請求,通過Socket介面將其傳送到遠端,並接收遠端的響應資訊,並構造成一個Response物件。
package com.binghe.protocol.client;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.net.Socket;import com.binghe.constant.Encode;import com.binghe.params.Request;import com.binghe.params.Response;import com.binghe.utils.ProtocolUtils;/** * 客戶端程式碼 * @author binghe * */publicfinalclassClient{ publicstaticvoidmain(String[] args)throws IOException{ //請求 Request request =newRequest(); request.setCommand("HELLO"); request.setCommandLength(request.getCommand().length()); request.setEncode(Encode.UTF8); Socket client =newSocket("127.0.0.1",4567); OutputStream out = client.getOutputStream();//傳送請求 ProtocolUtils.writeRequest(out, request);//讀取響應資料 InputStream in = client.getInputStream(); Response response = ProtocolUtils.readResponse(in); System.out.println("獲取的響應結果資訊為: "+ response.toString());}}
服務端的實現
服務端接收客戶端的請求,根據接收命令的不同,響應不同的訊息資訊,如果是「HELLO」命令,則響應「hello」資訊,否則響應「bye bye」資訊。
package com.binghe.protocol.server;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.net.ServerSocket;import java.net.Socket;import com.binghe.constant.Encode;import com.binghe.params.Request;import com.binghe.params.Response;import com.binghe.utils.ProtocolUtils;/** * Server端程式碼 * @author binghe * */publicfinalclassServer{ publicstaticvoidmain(String[] args)throws IOException{ ServerSocket server =newServerSocket(4567);while(true){ Socket client = server.accept();//讀取請求資料 InputStream input = client.getInputStream(); Request request = ProtocolUtils.readRequest(input); System.out.println("收到的請求參數為: "+ request.toString()); OutputStream out = client.getOutputStream();//組裝響應資料 Response response =newResponse(); response.setEncode(Encode.UTF8);if("HELLO".equals(request.getCommand())){ response.setResponse("hello");}else{ response.setResponse("bye bye");} response.setResponseLength(response.getResponse().length()); ProtocolUtils.writeResponse(out, response);}}}
ProtocolUtils工具類的實現
ProtocolUtils的readRequest方法將從傳遞進來的輸入流中讀取請求的encode、command和commandLength三個參數,進行相應的編碼轉化,構造成Request物件返回。而writeResponse方法則是將response物件的欄位根據對應的編碼寫入到響應的輸出流中。
有一個細節需要重點注意:OutputStream中直接寫入一個int類型,會擷取其低8位,丟棄其高24位,所以,在傳遞和接收資料時,需要進行相應的轉化操作。
package com.binghe.utils;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import com.binghe.constant.Encode;import com.binghe.params.Request;import com.binghe.params.Response;/** * 協議工具類 * @author binghe * */publicfinalclassProtocolUtils{ /** * 從輸入流中反序列化Request物件 * @param input * @return * @throws IOException */publicstatic Request readRequest(InputStream input)throws IOException{ //讀取編碼byte[] encodeByte =newbyte[1]; input.read(encodeByte);byte encode = encodeByte[];//讀取命令長度byte[] commandLengthBytes =newbyte[4]; input.read(commandLengthBytes);int commandLength = ByteUtils.byte2Int(commandLengthBytes);//讀取命令byte[] commandBytes =newbyte[commandLength]; input.read(commandBytes); String command ="";if(Encode.UTF8 == encode){ command =newString(commandBytes,"UTF-8");}elseif(Encode.GBK == encode){ command =newString(commandBytes,"GBK");}//組裝請求返回 Request request =newRequest(encode, command, commandLength);return request;}/** * 從輸入流中反序列化Response物件 * @param input * @return * @throws IOException */publicstatic Response readResponse(InputStream input)throws IOException{ //讀取編碼byte[] encodeByte =newbyte[1]; input.read(encodeByte);byte encode = encodeByte[];//讀取響應長度byte[] responseLengthBytes =newbyte[4]; input.read(responseLengthBytes);int responseLength = ByteUtils.byte2Int(responseLengthBytes);//讀取命令byte[] responseBytes =newbyte[responseLength]; input.read(responseBytes); String response ="";if(Encode.UTF8 == encode){ response =newString(responseBytes,"UTF-8");}elseif(Encode.GBK == encode){ response =newString(responseBytes,"GBK");}//組裝請求返回 Response resp =newResponse(encode, response, responseLength);return resp;}/** * 序列化請求資訊 * @param output * @param response */publicstaticvoidwriteRequest(OutputStream output, Request request)throws IOException{ //將response響應返回給客戶端 output.write(request.getEncode());//output.write(response.getResponseLength());直接write一個int類型會擷取低8位傳輸丟棄高24位 output.write(ByteUtils.int2ByteArray(request.getCommandLength()));if(Encode.UTF8 == request.getEncode()){ output.write(request.getCommand().getBytes("UTF-8"));}elseif(Encode.GBK == request.getEncode()){ output.write(request.getCommand().getBytes("GBK"));} output.flush();}/** * 序列化響應資訊 * @param output * @param response */publicstaticvoidwriteResponse(OutputStream output, Response response)throws IOException{ //將response響應返回給客戶端 output.write(response.getEncode());//output.write(response.getResponseLength());直接write一個int類型會擷取低8位傳輸丟棄高24位 output.write(ByteUtils.int2ByteArray(response.getResponseLength()));if(Encode.UTF8 == response.getEncode()){ output.write(response.getResponse().getBytes("UTF-8"));}elseif(Encode.GBK == response.getEncode()){ output.write(response.getResponse().getBytes("GBK"));} output.flush();}}
ByteUtils類的實現
package com.binghe.utils;/** * 位元組轉化工具類 * @author binghe * */publicfinalclassByteUtils{ /** * 將byte陣列轉化為int數字 * @param bytes * @return */publicstaticintbyte2Int(byte[] bytes){ int num = bytes[3]&0xFF; num |=((bytes[2]<<8)&0xFF00); num |=((bytes[1]<<16)&0xFF0000); num |=((bytes[]<<24)&0xFF000000);return num;}/** * 將int類型數字轉化為byte陣列 * @param num * @return */publicstaticbyte[]int2ByteArray(int i){ byte[] result =newbyte[4]; result[]=(byte)(( i >>24)&0xFF); result[1]=(byte)(( i >>16)&0xFF); result[2]=(byte)(( i >>8)&0xFF); result[3]=(byte)(i &0xFF);return result;}}
至此,我們這個應用層通訊協議示例程式碼開發完成,怎麼樣,小夥伴們,是不是很簡單呢?趕緊開啟你的環境,手擼個Http協議吧!!
寫在最後
如果你想進大廠,想升職加薪,或者對自己現有的工作比較迷茫,都可以私信我交流,希望我的一些經歷能夠幫助到大家~~
推薦閱讀:
《奉勸那些剛參加工作的學弟學妹們:要想進大廠,這些核心技能是你必須要掌握的!完整學習路線!!(建議收藏)》《奉勸那些剛參加工作的學弟學妹們:這些計算機與作業系統基礎知識越早知道越好!萬字長文太頂了!!(建議收藏)》《我用三天時間開發了一款老少皆宜的國民級遊戲,支援播放音樂,現開放完整原始碼和註釋(建議收藏)!!》《我是全網最硬核的高併發程式設計作者,CSDN最值得關注的博主,大家同意嗎?(建議收藏)》《畢業五年,從月薪3000到年薪百萬,我掌握了哪些核心技能?(建議收藏)》《我入侵了隔壁妹子的Wifi,發現。。。(全程實戰乾貨,建議收藏)》《千萬不要輕易嘗試「熊貓燒香」,這不,我後悔了!》《清明節偷偷訓練「熊貓燒香」,結果我的電腦為熊貓「獻身了」!》《7.3萬字肝爆Java8新特性,我不信你能看完!(建議收藏)》《在業務高峰期拔掉伺服器電源是一種怎樣的體驗?》
好了,今天就到這兒吧,小夥伴們點贊、收藏、評論,一鍵三連走起呀,我是冰河,我們下期見~~
,https://blog.csdn.net/l1028386804/article/details/117154518
相關文章
很多小伙伴跟我说,学习网络太难了,怎么办?其实很多技术都是相通的,只要你理解了技术的本质,你自己都可以实现它。这不,冰河就趁着周末,只用了几个<em>Java</em>类就简单的实现了Http协议,爽!!小伙伴们点赞,收藏,评论,走起呀~~HTT..
2021-05-24 09:30:28
相信大家对Apple这个品牌是不陌生的,甚至生活中有一部分人是“苹果控”,任何品类的都想要入手一件,当然它的品质也是有目共睹的,在去年9月份发布会上隆重上线的 <em>iPad</em> Air 4,可谓是改头换面的佳作,让一众看客眼前一
2021-05-24 09:30:14
芯片研究在国际固态电路会议发表论文数量名列全球第二,仅次于<em>英特尔</em>(<em>Intel</em>)。中药研究是澳大极具特色的研究领域,致力中医药质量及国际标准研究,成果获国家科技进步奖二等奖、创新中药产品获国际发明金
2021-05-24 09:00:48
在日前视频展示了<em>英特尔</em> 11 代酷睿 i5-11400 芯片的无风扇运行状况之后,近日知名爆料人士 Fritzchens Fritz 分享了该芯片的高清内核裸图(Die Photoshoot)。<em>英特尔</em>酷睿 i5-11400 装备了 6 个核心和 12
2021-05-24 09:00:25
当时的散热器用的是<em>Intel</em>的原装散热器,本来是没啥问题,但是随着吃鸡的风靡, 我也成为了万千游戏党的一员,这就导致了CPU动不动就会100%占用率,久而久之,原装的散热器就有点遭不住了,于是我将目光瞄上了新晋的百元散
2021-05-24 08:00:23
宽松直筒衬衫裤棉麻材质的风格,加上雪纺材质的面料,下身可以搭配一条长裤,让宽松的衬衫裤看起来更加优雅。那么怎么搭配这样的连衣裙呢?讲了那么多,那么你是不是觉得我们公号的知识已经全部都学到了呢?。翻开UC<em>浏览器</
2021-05-24 07:30:20