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