最近在作一個項目的時候,由於項目要求跨域鏈接。因此,使用了Okhttp框架。其內部原理是基於 socket 網絡編程的。由於本身在這方面比較薄弱,因此寫這一篇文章進行相關的總結。html
一、TCP/IP 參考模型
這位大佬寫的很詳細---點擊即看java
二、socket 套接字
每一個套接字都是鏈接的一個端點,有相應的套接字地址。由一個IP地址與16位的整數端口組成.一個鏈接由兩端的套接字地址惟一肯定。叫套接字對。
如:(cliaddr:cliport, servaddr:servport)
端口號分爲:
標準既定的端口號: 0~49151. 其中知名端口號由 0~1023 ** 組成。FTP 通常使用 21號端口號,HTTP 通訊通常使用 80 號端口號。
動態分配的端口號: 49152~65535. 操做系統爲之分配不一樣的端口號。而後應用程序使用時,由操做系統將鏈接創建。linux
三、java 中的網絡編程類android
InetAddress:用於標識網絡上的硬件資源,主要是IP地址 URL:統一資源定位符,經過URL能夠直接讀取或寫入網絡上的數據 Sockets:使用TCP協議實現的網絡通訊Socket相關的類 Datagram:使用UDP協議,將數據保存在用戶數據報中,經過網絡進行通訊。UDP協議中,使用 數據報 爲傳輸單位。
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地址");
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();
首先介紹下關於 linux 下的套接字鏈接原理,幫助理解json
下面介紹java 下 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 IOException
1. getInetAddress():得到遠程服務器的IP地址。 2. getPort():得到遠程服務器的端口。 3. getLocalAddress():得到客戶本地的IP地址。 4. getLocalPort():得到客戶本地的端口。 5. getInputStream():得到輸入流。若是Socket尚未鏈接,或者已經關閉,或者已經經過shutdownInput()方法關閉輸入流,那麼此方法會拋出IOException。 6. getOutputStream():得到輸出流。若是Socket尚未鏈接,或者已經關閉,或者已經經過shutdownOutput()方法關閉輸出流,那麼此方法會拋出IOException。
1. close() // 狀態測試方法 1. isClosed() 2. IsConnected() 3. isBound()
1. shutdownInput() 2. shutdownOutput() // 狀態測試方法 1. isInputShutDown() 2. isOutputShutdown()
以上就是 Socket 類的基本方法。 下面讓咱們進入實戰,來看一下,Socket 類如何使用數組
/** * 基於TCP協議的Socket通訊,實現用戶登陸,服務端 */ //一、建立一個服務器端Socket,即ServerSocket,指定綁定的端口,並監聽此端口 ServerSocket serverSocket =newServerSocket(33521);//1024-65535的某個端口 //二、調用accept()方法開始監聽,等待客戶端的鏈接 Socket socket = serverSocket.accept(); //三、獲取輸入流,並讀取客戶端信息 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();//關閉輸入流 //四、獲取輸出流,響應客戶端的請求 OutputStream os = socket.getOutputStream(); PrintWriter pw = new PrintWriter(os); pw.write("歡迎您!"); pw.flush(); //五、關閉資源 pw.close(); os.close(); br.close(); isr.close(); is.close(); socket.close(); serverSocket.close();
//客戶端 //一、建立客戶端Socket,指定服務器地址和端口 Socket socket =newSocket("localhost",33521); //二、獲取輸出流,向服務器端發送信息 OutputStream os = socket.getOutputStream();//字節輸出流 PrintWriter pw =newPrintWriter(os);//將輸出流包裝成打印流 pw.write("用戶名:3dot141;密碼:hahah"); pw.flush(); socket.shutdownOutput(); //三、獲取輸入流,並讀取服務器端的響應信息 InputStream is = socket.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(is)); String info = null; while((info=br.readLine())!null){ System.out.println("我是客戶端,服務器說:"+info); } //四、關閉資源 br.close(); is.close(); pw.close(); os.close(); socket.close();
我是服務器,客戶端說:用戶名:3dot141;密碼:hahah 我是客戶端,服務器說:歡迎您!
多線程中的運用服務器
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); }
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()
//服務器端,實現基於UDP的用戶登陸 //一、建立服務器端DatagramSocket,指定端口 DatagramSocket socket =new datagramSocket(33521); //二、建立數據報,用於接受客戶端發送的數據 byte[] data =newbyte[1024];// DatagramPacket packet =newDatagramPacket(data,data.length); //三、接受客戶端發送的數據 socket.receive(packet);//此方法在接受數據報以前會一致阻塞 //四、讀取數據 String info =newString(data,o,data.length); System.out.println("我是服務器,客戶端告訴我"+info); //========================================================= //向客戶端響應數據 //一、定義客戶端的地址、端口號、數據 // 這裏也能夠本身設置 InetAddress address = packet.getAddress(); int port = packet.getPort(); byte[] data2 = "歡迎您!".geyBytes(); //二、建立數據報,包含響應的數據信息 DatagramPacket packet2 = new DatagramPacket(data2,data2.length,address,port); //三、響應客戶端 socket.send(packet2); //四、關閉資源 socket.close();
//客戶端 //一、定義服務器的地址、端口號、數據 InetAddress address =InetAddress.getByName("localhost"); int port =33521; byte[] data ="用戶名:3dot141;密碼:hahah".getBytes(); //二、建立數據報,包含發送的數據信息 DatagramPacket packet = newDatagramPacket(data,data,length,address,port); //三、建立DatagramSocket對象 DatagramSocket socket =newDatagramSocket(); //四、向服務器發送數據 socket.send(packet); //接受服務器端響應數據 //====================================== //一、建立數據報,用於接受服務器端響應數據 byte[] data2 = new byte[1024]; DatagramPacket packet2 = new DatagramPacket(data2,data2.length); //二、接受服務器響應的數據 socket.receive(packet2); String raply = new String(data2,0,packet2.getLenth()); System.out.println("我是客戶端,服務器說:"+reply); //四、關閉資源 socket.close();
在項目中,我對 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, Map<String, String> map) 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謝謝。