記錄一個咸魚大學生三個月的奮進生活022
- 復習Java網路編程.NET包
- 網路層知識
- 傳輸層知識
- java.net包
- InetAddress類
- ServerSocket類和Socket類的使用(基于TCP的通訊)
- DatagramSocket和DatagramPacket使用(基于UDP的通訊)
- 學習Java面試題(Redis哨兵模式)
- 照片分享
復習Java網路編程.NET包
在正式開始之前我們先來了解一下什么是網路?
網路: 以某種介質連接各個終端實作資源共享和通信的通信系統
ISO模型/七層協議
這個知識其實在軟考的每一科,無論中級還是高級的考試中都屬于一個必考的知識點,應該是每個程式員都要記住的知識
這是我之前備戰軟考時的筆記,要是大家實在覺得難記,就可以背個口訣:巫術忘傳會飚鷹(從下往上每一層)
然后還有個模型也很重要叫 TCP/IP模型
TCP/IP模型 和 ISO模型是相輔相成的,也就是我筆記中右邊的圖
應用層(3個) 對應著 應用層、表示層、會話層
傳輸層(1個) 對應著 傳輸層
網路層(1個) 對應著 網路層
網路介面層(2個) 對應著 資料鏈路層、物理層
我們這次主要學習傳輸層和網路層這兩個知識,Java的網路編程用的最多的也就是這兩層模型
網路層知識
網路層最常見的應用就是IP地址的應用和協議
IP地址根據位數分為 IPV4 和 IPV6
IPV4(現在很多網站常用):0-255.0-255.0-255.0-255
IPV6(解決IPV4不夠用的情況):0-255.0-255.0-255.0-255.0-255.0-255
IP地址還分為 靜態IP 和 動態IP
動態IP:上網不用IP時就換人,誰用誰上
靜態IP:給常駐機器例如服務器一個IP地址
DNS域名地址:就是最常用的網站域名,例如:www.csdn.net
而 IP地址 和 DNS域名地址 也是能相互轉換的
例如:www.baidu.com 就是百度的DNS域名地址
然后我們可以通過DOS命令輸入指令獲取IP地址
ping www.baidu.com
獲取到百度的IP地址,如下圖:
又因為 IP地址 和 DNS域名地址 是可以相互轉換的
所以我們可以通過在瀏覽器地址欄輸入www.baidu.com 或者 14.215.177.39 這兩種方法來訪問百度
埠:
用于實作程式間的通信
常用的埠有:
Telnet協議 —— 23
簡單郵件傳輸協議 —— 25
檔案傳輸協議 —— 21
超文本傳輸協議 —— 80
協議:
網路中計算機之間通信的規則
常用的協議有:
超文本傳輸協議 (HTTP)
檔案傳輸協議 (FTP)
簡單郵件傳輸協議 (SMTP)
網路新聞傳輸協議 (NNTP)
傳輸層知識
傳輸層最常見的應用就是TCP傳輸和UDP傳輸
TCP: 雙方都不間斷交流,安全,穩定的資料流(就像打電話),因為是資料流所以資訊都是以位元組的形式傳遞
UDP: 單方面的間斷的,不安全不穩定的資料包(就像寫信),因為是資料包所以新訊息都是以byte陣列的形式傳遞
java.net包
InetAddress類
封裝了 IP地址 和 DNS域名
InetAddress實體化時只能用其中的getByName()方法進行實體化:
InetAddress 實體名 = InetAddress.getByName(“IP地址或DNS”);
.getHostName()方法 —— 回傳呼叫的實體的DNS域名
.getHostAddress()方法 —— 回傳呼叫的實體的IP地址
ServerSocket類和Socket類的使用(基于TCP的通訊)
Socket類
Socket可以使一個應用從網路中讀取和寫入資料,不同計算機上的兩個應用可以通過連接發送和接受位元組流,就像是兩個客戶端要通信時進行傳輸要用的類,所以Socket經常會發起通信,然后通信建立后就是兩個Socket在進行傳輸,
Socket實體化: Socket 實體名 = new Socket(“要通訊的IP地址”, 要通訊的Port值);
Socket類的常用方法:
.getLocalPort()方法 —— 獲取自己的Port值
.getPort()方法 —— 獲取通訊對方的Port值
ServerSocket類
因為要實作網路傳輸,所以要實作一個服務器應用,服務器需隨時待命,因為不知道客戶端什么時候會發來請求,此時,我們就要使用ServerSocket,
ServerSocket與Socket不同,ServerSocket是等待客戶端的請求,一旦獲得一個連接請求,就創建一個Socket示例來與客戶端進行通信,ServerSocket就像是兩個終端(Socket)之間通訊的轉化操作,
ServerSocket實體化: ServerSocket 實體名 = new ServerSocket(port值); 【這個port值是用于其他終端聯系這個ServerSocket的,也就是Socket類實體化時需要輸入的Port值,不指定的話系統會給一個隨機的port值】
ServerSocket類的常用方法:
.accept()方法 —— 回傳跟本類ServerSocket進行通訊的Socket類
常出現的問題:
Connection reset例外(兩邊任意一個終端例外終止就會報這個錯,因為網路通信之中用I/O讀取資訊,所以經常會報這個錯,回圈讀取的時候加個判斷條件跳出回圈就可以解決)
例子(用ServerSocket類和Socket類進行網路通信):
Work29_wangluochuanshuTCPSocket【ServerSocket類】//記住要先啟動這個ServerSocket類才能接收資訊:
package com.javawork29;
// ServerSocket和Socket使用(基于TCP的通訊)
// 這是被通訊的ServerSocket然后再用Socket進行讀取顯示
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
public class Work29_wangluochuanshuTCPServerSocket {
public static void main(String[] args) {
ServerSocket serverSocket = null; // ServerSocket就像是TCP通訊中的兩個終端通訊之間的轉化操作
Socket socket = null; // Socket就像兩個通訊終端里的一個被通訊的終端
BufferedReader reader = null;
BufferedWriter writer = null;
try {
serverSocket = new ServerSocket(8888); // 實體化:ServerSocket 名 = new ServerSocket(port值); 這個port數是用于其他終端聯系這個ServerSocket的,不指定的話系統會給一個隨機的port值
socket = serverSocket.accept(); // .accept()方法 回傳跟本類ServerSocket進行通訊的Socket類
// 之后是用I/O包對Socket進行資料讀取
reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); // 先用.getInputStream()方法獲取Socket實體的位元組,然后InputStreamReader將位元組轉換為字符,然后再用BufferedReader緩沖流讀取(記得因為InputStreamReader和BufferedReader都是處理流所以需要嵌套實體化使用)
String info = null;
while(true) {
info = reader.readLine();
System.out.println("ServerSocket收到的訊息:" + info);
if("再見!".equals(info)) {
break;
}
}
// 之后是通過I/O包像另一終端進行通訊(原理是剛才獲取的跟本類進行通訊的socket物件再將內容通過I/O更改為其他內容,)
writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
writer.write("沒錢了就告訴老爸!\n");
writer.flush();
writer.write("你努力學好軟體開發!\n");
writer.flush();
writer.write("再見!\n");
writer.flush();
// socket類中的方法
System.out.println(socket.getLocalPort()); // .getLocalPort()方法 獲得自己的Port值
System.out.println(socket.getPort()); // .getPort()方法 獲得通訊對方的Port值
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
// 關閉in和out操作
if(reader != null) {
reader.close();
reader = null;
}
if(writer != null) {
writer.close();
writer = null;
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
Work29_wangluochuanshuTCPSocket【Socket類】:
package com.javawork29;
// ServerSocket和Socket使用(基于TCP的通訊)
// 這是先進行通訊的連接ServerSocket的Socket
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.net.UnknownHostException;
public class Work29_wangluochuanshuTCPSocket {
public static void main(String[] args) {
Socket socket = null;
BufferedWriter writer = null;
BufferedReader reader = null;
try {
socket = new Socket("127.0.0.1", 8888); // Socket實體化:Socket 名 = new Socket("要通訊的IP地址", 要通訊的Port值); 這就建立通訊了,之后再在這個Socket實體里進行I/O的輸寫資訊
// 通過I/O書寫Socket進行傳輸資訊,因為那邊readLine方法所以有換行才能讀取
writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
writer.write("你好,老王!\n");
writer.flush();
writer.write("最近缺錢了!\n");
writer.flush();
writer.write("再打一千!\n");
writer.flush();
writer.write("再見!\n");
writer.flush();
// 通過I/O讀取Socket進行顯示資訊
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String info = null;
while(true) {
info = reader.readLine();
System.out.println("Socket收到的資訊:" + info);
if("再見!".equals(info)) {
break;
}
}
// socket類中的方法
System.out.println(socket.getLocalPort()); // .getLocalPort()方法 獲得自己的Port值
System.out.println(socket.getPort()); // .getPort()方法 獲得通訊對方的Port值
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
// 關閉in和out操作
if(reader != null) {
reader.close();
reader = null;
}
if(writer != null) {
writer.close();
writer = null;
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
運行結果【發起通信的Socket類】:
運行結果【接收到通信的ServerSocket類】:
DatagramSocket和DatagramPacket使用(基于UDP的通訊)
DatagramSocket類
DatagramSocket是基于UDP的連接,所以客戶端不需要先連接資料,可以直接發送給指定服務端,
DatagramSocket實體化: DatagramSocket 實體名 = DatagramSocket(port值); —— 需要給一個port值以供傳輸資訊
DatagramSocket類的常用方法:
.send()方法 —— 用于發送packet物件
.receive()方法 —— 用于接收packet物件
DatagramPacket類
DatagramPacket就像UDP通信協議中用來建立通訊的兩個客戶端,當需要發送訊息時和接收訊息時兩個實體化的方法是不一樣的,
DatagramPacket實體化:
當需要發送資訊時的DatagramPacket:
DatagramPacket 實體名 = new DatagramPacket(pool, pool.length, InetAddress.getByName(“發送的IP地址”), 對方的port值);
當需要接收資訊時的DatagramPacket:
DatagramPacket 實體名 = new DatagramPacket(pool, pool.length);
DatagramPacket類的常用方法:
.setData(“內容”.getBytes()) —— 設定packet內容的方法,里面寫需要發送內容的byte陣列值
.getData() —— 獲取packet的內容,接收到的packet物件里面是byte陣列,需要用實體化String里的轉化byte陣列內容的構造方法實體化:String info = new String(packet.getData());
常出現的問題:
因為UDP是通過byte陣列進行傳播資料的,所以要宣告一個byte陣列pool,大小為8的倍數
例子(用DatagramSocket類和DatagramPacket類進行網路通信):
Work29_wangluochuanshuUDPDatagram1【發送資訊的DatagramPacket類】:
package com.javawork29;
// DatagramSocket和DatagramPacket使用,本類是終端1(基于UDP的通訊)
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
public class Work29_wangluochuanshuUDPDatagram1 {
public static void main(String[] args) {
System.out.println("test1開始");
DatagramSocket socket = null; // DatagramSocket進行發送資訊
DatagramPacket packet = null; // DatagramPacket進行資訊撰寫,根據發送還是接收實體化格式不同
try {
socket = new DatagramSocket(5555); // 實體化DatagramSocket(port值)時也需要給一個port值以供傳輸資訊
byte[] pool = new byte[1024]; // 因為UDP是通過byte陣列進行傳播資料的,所以要宣告一個byte陣列pool,大小為8的倍數
// 實體化發送資訊時的DatagramPacket: DatagramPacket 名 = new DatagramPacket(pool, pool.length, InetAddress.getByName("發送的IP地址"), 對方的port值);
packet = new DatagramPacket(pool, pool.length, InetAddress.getByName("127.0.0.1"), 6666);
packet.setData("你好test2".getBytes()); // DatagramPacket物件的.setData("內容".getBytes())設定packet內容方法,里面寫需要發送內容的byte陣列值
socket.send(packet); // socket.send(packet); .send()方法 發送packet物件
} catch (SocketException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Work29_wangluochuanshuUDPDatagram2【接收資訊的DatagramPacket類】//記住要先啟動這個接收資訊的DatagramPacket類才能接收到資訊:
package com.javawork29;
// DatagramSocket和DatagramPacket使用,本類是終端2(基于UDP的通訊)
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.net.UnknownHostException;
public class Work29_wangluochuanshuUDPDatagram2 {
public static void main(String[] args) {
System.out.println("test2開始");
DatagramSocket socket = null; // DatagramSocket進行發送資訊
DatagramPacket packet = null; // DatagramPacket進行資訊撰寫,根據發送還是接收實體化格式不同
try {
socket = new DatagramSocket(6666); // 實體化DatagramSocket(port值)時也需要給一個port值以供傳輸資訊
byte[] pool = new byte[1024];
// 實體化接收資訊時的DatagramPacket: DatagramPacket 名 = new DatagramPacket(pool, pool.length);
packet = new DatagramPacket(pool, pool.length);
socket.receive(packet); // socket.receive(packet); .receive()方法 接收packet物件
String info = new String(packet.getData()); // 接收到的packet物件里面是byte陣列,需要用實體化String里的轉化byte陣列內容的構造方法實體化
// DatagramPacket物件的.getData()方法獲取packet的內容
System.out.println("test2收到的資訊:" + info);
} catch (SocketException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
運行結果【接收資訊的DatagramPacket類也就是test2類】:
運行結果【發送資訊的DatagramPacket類也就是test1類】:
好了以上就是網路編程所學內容,下次帖子開始我們就要復習第二個專案了,就是根據之前所學的 javaswing、多執行緒、I/O、網路通信 所做的簡易在線聊天系統,敬請期待哦
學習Java面試題(Redis哨兵模式)
指路陳哈哈大佬的Redis相關面試題原帖
照片分享
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/290984.html
標籤:其他
