摘要:如端口號(hào)分為標(biāo)準(zhǔn)既定的端口號(hào)其中知名端口號(hào)由組成。協(xié)議中,使用數(shù)據(jù)報(bào)為傳輸單位。用于直播等網(wǎng)速要求較高的應(yīng)用端到端的通信類本機(jī)地址隨機(jī)指定發(fā)送與接收數(shù)據(jù)報(bào)為和等網(wǎng)絡(luò)層以上的包的單位。
前言
最近在做一個(gè)項(xiàng)目的時(shí)候,因?yàn)轫?xiàng)目要求跨域連接。所以,使用了Okhttp框架。其內(nèi)部原理是基于 socket 網(wǎng)絡(luò)編程的。因?yàn)樽约涸谶@方面比較薄弱,所以寫(xiě)這一篇文章進(jìn)行相關(guān)的總結(jié)。
基礎(chǔ)知識(shí)(參考 圖解TCP/IP 與 深入理解計(jì)算機(jī)系統(tǒng))1、TCP/IP 參考模型
這位大佬寫(xiě)的很詳細(xì)---點(diǎn)擊即看
2、socket 套接字
每個(gè)套接字都是連接的一個(gè)端點(diǎn),有相應(yīng)的套接字地址。由一個(gè)IP地址與16位的整數(shù)端口組成.一個(gè)連接由兩端的套接字地址唯一確定。叫套接字對(duì)。
如:(cliaddr:cliport, servaddr:servport)
端口號(hào)分為:
標(biāo)準(zhǔn)既定的端口號(hào): 0~49151. 其中知名端口號(hào)由 0~1023 ** 組成。FTP 一般使用 21號(hào)端口號(hào),HTTP 通信一般使用 80 號(hào)端口號(hào)。
動(dòng)態(tài)分配的端口號(hào): 49152~65535. 操作系統(tǒng)為之分配不同的端口號(hào)。然后應(yīng)用程序使用時(shí),由操作系統(tǒng)將連接建立。
3、java 中的網(wǎng)絡(luò)編程類
InetAddress:用于標(biāo)識(shí)網(wǎng)絡(luò)上的硬件資源,主要是IP地址 URL:統(tǒng)一資源定位符,通過(guò)URL可以直接讀取或?qū)懭刖W(wǎng)絡(luò)上的數(shù)據(jù) Sockets:使用TCP協(xié)議實(shí)現(xiàn)的網(wǎng)絡(luò)通信Socket相關(guān)的類 Datagram:使用UDP協(xié)議,將數(shù)據(jù)保存在用戶數(shù)據(jù)報(bào)中,通過(guò)網(wǎng)絡(luò)進(jìn)行通信。UDP協(xié)議中,使用 數(shù)據(jù)報(bào) 為傳輸單位。java 網(wǎng)絡(luò)編程類介紹 1. InetAddress
InetAddress類用于標(biāo)識(shí)網(wǎng)絡(luò)上的硬件資源,標(biāo)識(shí)互聯(lián)網(wǎng)協(xié)議(IP)地址。
//獲取本機(jī)的InetAddress實(shí)例 InetAddress address =InetAddress.getLocalHost(); //獲取計(jì)算機(jī)名 address.getHostName(); //獲取IP地址 address.getHostAddress(); //獲取字節(jié)數(shù)組形式的IP地址,以點(diǎn)分隔的四部分 byte[] bytes = address.getAddress(); //獲取其他主機(jī)的InetAddress實(shí)例 InetAddress address2 =InetAddress.getByName("其他主機(jī)名"); InetAddress address3 =InetAddress.getByName("IP地址");2. URL
URL(Uniform Resource Locator)統(tǒng)一資源定位符,表示Internet上某一資源的地址,協(xié)議名:資源名稱
基礎(chǔ)使用
//創(chuàng)建一個(gè)URL的實(shí)例 URL myBlog =new URL("https://3dot141.cn"); URL url =new URL(myBlog,"/blogs/33521.html?username=3dot141#test");//?表示參數(shù),#表示錨點(diǎn) url.getProtocol();//獲取協(xié)議 url.getHost();//獲取主機(jī) url.getPort();//如果沒(méi)有指定端口號(hào),根據(jù)協(xié)議不同使用默認(rèn)端口。此時(shí)getPort()方法的返回值為 -1 url.getPath();//獲取文件路徑 url.getFile();//文件名,包括文件路徑+參數(shù) url.getRef();//相對(duì)路徑,就是錨點(diǎn),即#號(hào)后面的內(nèi)容 url.getQuery();//查詢字符串,即參數(shù)
讀取網(wǎng)頁(yè)內(nèi)容
//使用URL讀取網(wǎng)頁(yè)內(nèi)容 //創(chuàng)建一個(gè)URL實(shí)例 URL url =new URL("http://www.baidu.com"); InputStream is = url.openStream();//通過(guò)openStream方法獲取資源的字節(jié)輸入流 InputStreamReader isr =newInputStreamReader(is,"UTF-8");//將字節(jié)輸入流轉(zhuǎn)換為字符輸入流,如果不指定編碼,中文可能會(huì)出現(xiàn)亂碼 BufferedReader br =newBufferedReader(isr);//為字符輸入流添加緩沖,提高讀取效率 String data = br.readLine();//讀取數(shù)據(jù) while(data!=null){ System.out.println(data);//輸出數(shù)據(jù) data = br.readerLine(); } br.close(); isr.colose(); is.close();3. Socket
首先介紹下關(guān)于 linux 下的套接字連接原理,幫助理解
下面介紹java 下 Socket的使用
1.Socket 的構(gòu)造方法(1)Socket() (2)Socket(InetAddress address, int port)throws UnknownHostException,IOException // 設(shè)定遠(yuǎn)程服務(wù)器地址與客戶端地址 (3)Socket(InetAddress address, int port, InetAddress localAddr, int localPort)throws IOException (4)Socket(String host, int port) throws UnknownHostException,IOException // 設(shè)定遠(yuǎn)程服務(wù)器地址與客戶端地址 (5)Socket(String host, int port, InetAddress localAddr, int localPort) throws IOException2.獲取Socket信息
1. getInetAddress():獲得遠(yuǎn)程服務(wù)器的IP地址。 2. getPort():獲得遠(yuǎn)程服務(wù)器的端口。 3. getLocalAddress():獲得客戶本地的IP地址。 4. getLocalPort():獲得客戶本地的端口。 5. getInputStream():獲得輸入流。如果Socket還沒(méi)有連接,或者已經(jīng)關(guān)閉,或者已經(jīng)通過(guò)shutdownInput()方法關(guān)閉輸入流,那么此方法會(huì)拋出IOException。 6. getOutputStream():獲得輸出流。如果Socket還沒(méi)有連接,或者已經(jīng)關(guān)閉,或者已經(jīng)通過(guò)shutdownOutput()方法關(guān)閉輸出流,那么此方法會(huì)拋出IOException。3.Socket 狀態(tài)
關(guān)閉狀態(tài)
1. close() // 狀態(tài)測(cè)試方法 1. isClosed() 2. IsConnected() 3. isBound()
半關(guān)閉狀態(tài)
1. shutdownInput() 2. shutdownOutput() // 狀態(tài)測(cè)試方法 1. isInputShutDown() 2. isOutputShutdown()4.Socket 使用實(shí)例
以上就是 Socket 類的基本方法。 下面讓我們進(jìn)入實(shí)戰(zhàn),來(lái)看一下,Socket 類如何使用
服務(wù)器端
/** * 基于TCP協(xié)議的Socket通信,實(shí)現(xiàn)用戶登錄,服務(wù)端 */ //1、創(chuàng)建一個(gè)服務(wù)器端Socket,即ServerSocket,指定綁定的端口,并監(jiān)聽(tīng)此端口 ServerSocket serverSocket =newServerSocket(33521);//1024-65535的某個(gè)端口 //2、調(diào)用accept()方法開(kāi)始監(jiān)聽(tīng),等待客戶端的連接 Socket socket = serverSocket.accept(); //3、獲取輸入流,并讀取客戶端信息 InputStream is = socket.getInputStream(); InputStreamReader isr =newInputStreamReader(is); BufferedReader br =newBufferedReader(isr); String info =null; while((info=br.readLine())!=null){ System.out.println("我是服務(wù)器,客戶端說(shuō):"+info); } socket.shutdownInput();//關(guān)閉輸入流 //4、獲取輸出流,響應(yīng)客戶端的請(qǐng)求 OutputStream os = socket.getOutputStream(); PrintWriter pw = new PrintWriter(os); pw.write("歡迎您!"); pw.flush(); //5、關(guān)閉資源 pw.close(); os.close(); br.close(); isr.close(); is.close(); socket.close(); serverSocket.close();
客戶端
//客戶端 //1、創(chuàng)建客戶端Socket,指定服務(wù)器地址和端口 Socket socket =newSocket("localhost",33521); //2、獲取輸出流,向服務(wù)器端發(fā)送信息 OutputStream os = socket.getOutputStream();//字節(jié)輸出流 PrintWriter pw =newPrintWriter(os);//將輸出流包裝成打印流 pw.write("用戶名:3dot141;密碼:hahah"); pw.flush(); socket.shutdownOutput(); //3、獲取輸入流,并讀取服務(wù)器端的響應(yīng)信息 InputStream is = socket.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(is)); String info = null; while((info=br.readLine())!null){ System.out.println("我是客戶端,服務(wù)器說(shuō):"+info); } //4、關(guān)閉資源 br.close(); is.close(); pw.close(); os.close(); socket.close();
結(jié)果
我是服務(wù)器,客戶端說(shuō):用戶名:3dot141;密碼:hahah 我是客戶端,服務(wù)器說(shuō):歡迎您!
多線程中的運(yùn)用
服務(wù)器端創(chuàng)建ServerSocket,使用while(true)循環(huán)調(diào)用accept()等待客戶端連接
客戶端創(chuàng)建一個(gè)socket并請(qǐng)求和服務(wù)器端連接
服務(wù)器端接受請(qǐng)求,創(chuàng)建socket與該客戶建立專線連接
建立連接的兩個(gè)socket在一個(gè)多帶帶的線程上對(duì)話
服務(wù)器端繼續(xù)等待新的連接
public class ServerThread implements runnable{ //服務(wù)器線程處理 //和本線程相關(guān)的socket Socket socket =null; // public ServerThread(Socket socket){ this.socket = socket; } publicvoid run(){ //服務(wù)器處理代碼 } } //服務(wù)器代碼 ServerSocket serverSocket =newServerSocket(33521); Socket socket =null; int count =0;//記錄客戶端的數(shù)量 while(true){ socket = serverScoket.accept(); ServerThread serverThread =new ServerThread(socket); serverThread.start(); count++; System.out.println("客戶端連接的數(shù)量:"+count); }4. UDP 編程 1. 簡(jiǎn)單介紹
UDP 是面向無(wú)連接的協(xié)議,反應(yīng)迅速,適用于適時(shí)場(chǎng)景,但是丟包后不能發(fā)現(xiàn)。
用于 直播等網(wǎng)速要求較高的應(yīng)用
DatagramSocket 端到端的通信類.
//本機(jī)地址 // 隨機(jī) DatagramSocket() // 指定 DatagramSocket(int port, InetAddress) // 發(fā)送與接收 send(DatagramPacket) receive(DatagramPacket)
DatagramPacket 數(shù)據(jù)報(bào), 為 IP 和 UDP 等網(wǎng)絡(luò)層以上的包的單位 。雖然這些都是包,但不同的層擁有不同的稱呼。數(shù)據(jù)鏈路層中 叫 幀 , TCP 則表示 為 段 .
方法 :
// 構(gòu)造方法 // 接收時(shí) DatagramPacket(byte[] buf, int length); // 發(fā)送時(shí) DatagramPacket(byte[] buf, int length, InetAddress iAdrr, int Port); // 使用方法 // 用于服務(wù)器獲得 客戶端地址 getAddress() // 用于服務(wù)器獲得 客戶端接口 getPort()2. 基本使用
服務(wù)器端
//服務(wù)器端,實(shí)現(xiàn)基于UDP的用戶登錄 //1、創(chuàng)建服務(wù)器端DatagramSocket,指定端口 DatagramSocket socket =new datagramSocket(33521); //2、創(chuàng)建數(shù)據(jù)報(bào),用于接受客戶端發(fā)送的數(shù)據(jù) byte[] data =newbyte[1024];// DatagramPacket packet =newDatagramPacket(data,data.length); //3、接受客戶端發(fā)送的數(shù)據(jù) socket.receive(packet);//此方法在接受數(shù)據(jù)報(bào)之前會(huì)一致阻塞 //4、讀取數(shù)據(jù) String info =newString(data,o,data.length); System.out.println("我是服務(wù)器,客戶端告訴我"+info); //========================================================= //向客戶端響應(yīng)數(shù)據(jù) //1、定義客戶端的地址、端口號(hào)、數(shù)據(jù) // 這里也可以自己設(shè)置 InetAddress address = packet.getAddress(); int port = packet.getPort(); byte[] data2 = "歡迎您!".geyBytes(); //2、創(chuàng)建數(shù)據(jù)報(bào),包含響應(yīng)的數(shù)據(jù)信息 DatagramPacket packet2 = new DatagramPacket(data2,data2.length,address,port); //3、響應(yīng)客戶端 socket.send(packet2); //4、關(guān)閉資源 socket.close();
客戶端
//客戶端 //1、定義服務(wù)器的地址、端口號(hào)、數(shù)據(jù) InetAddress address =InetAddress.getByName("localhost"); int port =33521; byte[] data ="用戶名:3dot141;密碼:hahah".getBytes(); //2、創(chuàng)建數(shù)據(jù)報(bào),包含發(fā)送的數(shù)據(jù)信息 DatagramPacket packet = newDatagramPacket(data,data,length,address,port); //3、創(chuàng)建DatagramSocket對(duì)象 DatagramSocket socket =newDatagramSocket(); //4、向服務(wù)器發(fā)送數(shù)據(jù) socket.send(packet); //接受服務(wù)器端響應(yīng)數(shù)據(jù) //====================================== //1、創(chuàng)建數(shù)據(jù)報(bào),用于接受服務(wù)器端響應(yīng)數(shù)據(jù) byte[] data2 = new byte[1024]; DatagramPacket packet2 = new DatagramPacket(data2,data2.length); //2、接受服務(wù)器響應(yīng)的數(shù)據(jù) socket.receive(packet2); String raply = new String(data2,0,packet2.getLenth()); System.out.println("我是客戶端,服務(wù)器說(shuō):"+reply); //4、關(guān)閉資源 socket.close();OkHttp 框架
在項(xiàng)目中,我對(duì) OkHttp 進(jìn)行了簡(jiǎn)單的封裝,基本滿足我在項(xiàng)目中的需要。
下面貼上我的 工具類
public class OkhttpUtil { public static final MediaType JSON = MediaType.parse("application/json;charset=UTF-8"); public static String doGet(String url) throws IOException { OkHttpClient client = new OkHttpClient(); Request get = new Request.Builder().url(url).build(); Response response = client.newCall(get).execute(); return response.body().string(); } public static String doGet(String url, Mapmap) throws IOException { OkHttpClient client = new OkHttpClient(); String newUrl = url; if (map != null) { int loop = 0; for (String key : map.keySet()) { if (loop == 0) { newUrl = newUrl + "?" + key + "=" + map.get(key); } else { newUrl = newUrl + "&" + key + "=" + map.get(key); } loop = 1; } } Request get = new Request.Builder().url(newUrl).build(); Response response = client.newCall(get).execute(); return response.body().string(); } public static String doPost(String url, String requestBody) throws IOException { OkHttpClient client = new OkHttpClient(); Request post = new Request.Builder().url(url).post(RequestBody.create(JSON, requestBody)).build(); Response response = client.newCall(post).execute(); if (!response.isSuccessful()) { throw new IOException("沒(méi)能得到數(shù)據(jù)" + response); } return response.body().string(); } }
如果有對(duì) okhttp 框架感興趣的,可以參閱下面的網(wǎng)址。我就不獻(xiàn)丑了。
okhttp 源碼解析
okhttp 使用教程
路漫漫其修遠(yuǎn)兮,吾將上下而求索。
在程序員的道路上,我還只是一個(gè)剛上路的小學(xué)生,懷著對(duì)代碼世界的向往,砥礪前行。
stay hungry, stay foolish
與諸君共勉。
您的每一次點(diǎn)贊,關(guān)注都是對(duì)我的一種激勵(lì)。
我的個(gè)人博客 -- killCode
謝謝。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/70466.html
摘要:構(gòu)造函數(shù)默認(rèn)空閑的最大連接數(shù)為個(gè),的時(shí)間為秒通過(guò)構(gòu)造函數(shù)可以看出默認(rèn)的空閑的最大連接數(shù)為個(gè),的時(shí)間為秒。實(shí)例化實(shí)例化是在實(shí)例化時(shí)進(jìn)行的在的構(gòu)造函數(shù)中調(diào)用了省略省略緩存操作提供對(duì)進(jìn)行操作的方法分別為和幾個(gè)操作。 1.引子 在了解OkHttp的復(fù)用連接池之前,我們首先要了解幾個(gè)概念。 TCP三次握手 通常我們進(jìn)行HTTP連接網(wǎng)絡(luò)的時(shí)候我們會(huì)進(jìn)行TCP的三次握手,然后傳輸數(shù)據(jù),然后再釋放連接...
摘要:個(gè)高級(jí)多線程面試題及回答后端掘金在任何面試當(dāng)中多線程和并發(fā)方面的問(wèn)題都是必不可少的一部分。目前在生產(chǎn)環(huán)基于的技術(shù)問(wèn)答網(wǎng)站系統(tǒng)實(shí)現(xiàn)后端掘金這一篇博客將詳細(xì)介紹一個(gè)基于的問(wèn)答網(wǎng)站的實(shí)現(xiàn),有詳細(xì)的代碼。 15 個(gè)高級(jí) Java 多線程面試題及回答 - 后端 - 掘金在任何Java面試當(dāng)中多線程和并發(fā)方面的問(wèn)題都是必不可少的一部分。如果你想獲得任何股票投資銀行的前臺(tái)資訊職位,那么你應(yīng)該準(zhǔn)備很多...
摘要:個(gè)高級(jí)多線程面試題及回答后端掘金在任何面試當(dāng)中多線程和并發(fā)方面的問(wèn)題都是必不可少的一部分。目前在生產(chǎn)環(huán)基于的技術(shù)問(wèn)答網(wǎng)站系統(tǒng)實(shí)現(xiàn)后端掘金這一篇博客將詳細(xì)介紹一個(gè)基于的問(wèn)答網(wǎng)站的實(shí)現(xiàn),有詳細(xì)的代碼。 15 個(gè)高級(jí) Java 多線程面試題及回答 - 后端 - 掘金在任何Java面試當(dāng)中多線程和并發(fā)方面的問(wèn)題都是必不可少的一部分。如果你想獲得任何股票投資銀行的前臺(tái)資訊職位,那么你應(yīng)該準(zhǔn)備很多...
閱讀 2430·2021-11-25 09:43
閱讀 3520·2021-10-25 09:48
閱讀 1400·2021-09-13 10:24
閱讀 2801·2019-08-29 15:07
閱讀 1346·2019-08-29 13:14
閱讀 3332·2019-08-29 12:22
閱讀 1407·2019-08-29 11:32
閱讀 3315·2019-08-29 11:23