網路編程
1. 網路編程概述
網路編程概述
- Java是Internet上的語言,他從語言級上提供了網路編程應用程式的支持,程式員能夠很容易開發常見的網路應用程式,
- Java提供的網路類別庫,可以實作無痛的網路連接,聯網的底層細節被隱藏再Java的本機安裝系統里,有JVM進行控制,并且Java實作了一個跨屏太的網路庫,程式員面對的是一個統一的網路編程環境,
網路基礎
-
計算機網路
? 把分布在不同地理區域的計算機與專門的外部設備用通信線路互連成一個規模大、功能強的網路系統,從而使眾多的計算機可以方便地互相傳遞資訊、共享硬體、軟體、資料資訊等資源,
-
網路編程的目的:
直接或間接地通過網路協議與其它計算機實作資料交換,進行通訊,
-
網路編程中有兩個主要的問題:
- 如何準確地定位網路上一臺或多臺主機;定位主機上的特定的應用?
- 找到主機后如何可靠高效地進行資料傳輸?
2. 網路通信要素概述
如何實作網路中的主機互相通信
- 通信雙方地址
- IP
- 埠號
- 一定的規則(即:網路通信協議,有兩套參考模型)
- OSI參考模型:模型過于理想化,未能在因特網上進行廣泛推廣
- TCP/IP參考模型(或TCP/IP協議):事實上的國際標準,
網路通信協議


3. 通信要素1:IP和埠號
IP 地址:InetAddress
- 唯一的標識 Internet 上的計算機(通信物體)
- 本地回環地址(hostAddress):127.0.0.1 主機名(hostName):localhost
- IP地址分類方式1:IPV4 和 IPV6
- IPV4:4個位元組組成,4個0-255,大概42億,30億都在北美,亞洲4億,2011年初已經用盡,以點分十進制表示,如192.168.0.1
- IPV6:128位(16個位元組),寫成8個無符號整數,每個整數用四個十六進制位表示,數之間用冒號(:)分開,如:3ffe:3201:1401:1280:c8ff:fe4d:db39:1984
- IP地址分類方式2:? 動態/私有埠:49152~65535,公網地址(萬維網使用)和私有地址(局域網使用),192.168.開頭的就是私有址址,范圍即為192.168.0.0--192.168.255.255,專門為組織機構內部使用
- 特點:不易記憶
埠號
-
埠號標識正在計算機上運行的行程(程式)
- 不同的行程有不同的埠號
- 被規定為一個 16 位的整數 0~65535,
- 埠分類:
- 公認埠:0~1023,被預先定義的服務通信占用(如:HTTP占用埠80,FTP占用埠21,Telnet占用埠23)
- 注冊埠:1024~49151,分配給用戶行程或應用程式,(如:Tomcat占用埠8080,MySQL占用埠3306,Oracle占用埠1521等),
- 動態/私有埠:49152~65535,
-
埠號與IP地址的組合得出一個網路套接字:Socket,

netAddress類
-
Internet上的主機有兩種方式表示地址:
- 域名(hostName):www.atguigu.com
- IP 地址(hostAddress):202.108.35.210
-
InetAddress類主要表示IP地址,兩個子類:Inet4Address、Inet6Address,
-
**InetAddress **類物件含有一個 Internet 主機地址的域名和IP 地址:www.atguigu.com 和 202.108.35.210,
-
域名容易記憶,當在連接網路時輸入一個主機的域名后,域名服務器(DNS)負責將域名轉化成IP地址,這樣才能和主機建立連接, -----域名決議

-
InetAddress類沒有提供公共的構造器,而是提供了如下幾個靜態方法來獲取InetAddress實體
public static InetAddress getLocalHost() //回傳本地主機的地址 public static InetAddress getByName(String host) //確定主機名稱的IP地址, -
InetAddress提供了如下幾個常用的方法
public String getHostAddress(); //回傳 IP 地址字串(以文本表現形式), public String getHostName(); //獲取此 IP 地址的主機名 public boolean isReachable(int timeout); //測驗是否可以達到該地址 -
InetAddress代碼實體
public static void main(String[] args) throws UnknownHostException { InetAddress address = InetAddress.getByName("www.zhiyou100.com"); //獲取InetAddress物件的域名和地址 System.out.println(address);//www.zhiyou100.com/180.76.184.151 //獲取InetAddress物件所包含的域名 System.out.println(address.getHostName());//www.zhiyou100.com //獲取InetAddress物件的IP地址 System.out.println(address.getHostAddress());//180.76.184.151 //獲取本機的域名和IP地址 System.out.println(InetAddress.getLocalHost());//DESKTOP-PHJGSH5/192.168.14.145 }
4. 通信要素2:網路協議
網路通信協議
-
網路通信協議
計算機網路中實作通信必須有一些約定,即通信協議,對速率、傳輸代碼、代碼結構、傳輸控制步驟、出錯控制等制定標準,
-
問題:網路協議太復雜
計算機網路通信涉及內容很多,比如指定源地址和目標地址,加密解密,壓縮解壓縮,差錯控制,流量控制,路由控制,如何實作如此復雜的網路協議呢?
-
通信協議分層的思想
在制定協議時,把復雜成份分解成一些簡單的成份,再將它們復合起來,最常用的復合方式是層次方式,即同層間可以通信、上一層可以呼叫下一層,而與再下一層不發生關系,各層互不影響,利于系統的開發和擴展,
TCP/IP協議簇
- 傳輸層協議中有兩個非常重要的協議:
- 傳輸控制協議TCP(Transmission Control Protocol)
- 用戶資料報協議UDP(User Datagram Protocol),
- TCP/IP 以其兩個主要協議:傳輸控制協議(TCP)和網路互聯協議(IP)而得名,實際上是一組協議,包括多個具有不同功能且互為關聯的協議,
- IP(Internet Protocol)協議是網路層的主要協議,支持網間互連的資料通信
- TCP/IP協議模型從更實用的角度出發,形成了高效的四層體系結構,即物理鏈路層、IP層、傳輸層和應用層,
TCP 和 UDP
- TCP協議:
- 使用TCP協議前,須先建立TCP連接,形成傳輸資料通道
- 傳輸前,采用“三次握手”方式,點對點通信,是可靠的
- TCP協議進行通信的兩個應用行程:客戶端、服務端,
- 在連接中可進行大資料量的傳輸
- 傳輸完畢,需釋放已建立的連接,效率低
- UDP協議:
- 將資料、源、目的封裝成資料包,不需要建立連接
- 每個資料報的大小限制在64K內
- 發送不管對方是否準備好,接收方收到也不確認,故是不可靠的
- 可以廣播發送
- 發送資料結束時無需釋放資源,開銷小,速度快
TCP 三次握手

TCP四次揮手

Socket
描述
- 利用套接字(Socket)開發網路應用程式早已被廣泛的采用,以至于成為事實上的標準,
- 網路上具有唯一標識的IP地址和埠號組合在一起才能構成唯一能識別的識別符號套接字,
- 通信的兩端都要有Socket,是兩臺機器間通信的端點,
- 網路通信其實就是Socket間的通信,
- Socket允許程式把網路連接當成一個流,資料在兩個Socket間通過IO傳輸,
- 一般主動發起通信的應用程式屬客戶端,等待通信請求的為服務端,
- Socket分類:
- 流套接字(stream socket):使用TCP提供可依賴的位元組流服務
- 資料報套接字(datagram socket):使用UDP提供“盡力而為”的資料報服務
Socket類常用構造器
Socket?() //創建一個未連接的套接字,并使用系統默認型別的SocketImpl,
Socket(InetAddress address,int port) //創建一個流套接字并將其連接到指定IP 地址的指定埠號,
Socket(String host,int port) //創建一個流套接字并將其連接到指定主機上的指定埠號,
Socket類常用方法
public InputStream getInputStream() //回傳此套接字的輸入流,可以用于接收網路訊息
public OutputStream getOutputStream() //回傳此套接字的輸出流,可以用于發送網路訊息
public InetAddress getInetAddress() //此套接字連接到的遠程 IP 地址;如果套接字是未連接的,則回傳null,
public InetAddress getLocalAddress() //獲取套接字系結的本地地址,即本端的IP地址
public int getPort() //此套接字連接到的遠程埠號;如果尚未連接套接字,則回傳0,
public int getLocalPort() //回傳此套接字系結到的本地埠, 如果尚未系結套接字,則回傳 -1,即本端的埠號,
public void close() //關閉此套接字,套接字被關閉后,便不可在以后的網路連接中使用(即無法重新連接或重新系結),需要創建新的套接字物件, 關閉此套接字也將會關閉該套接字的 InputStream 和OutputStream,
public void shutdownInput() //如果在套接字上呼叫 shutdownInput() 后從套接字輸入流讀取內容,則流將回傳EOF(檔案結束符),即不能在從此套接字的輸入流中接收任何資料,
public void shutdownOutput() //禁用此套接字的輸出流,對于 TCP 套接字,任何以前寫入的資料都將被發送,并且后跟 TCP 的正常連接終止序列, 如果在套接字上呼叫 shutdownOutput() 后寫入套接字輸出流,則該流將拋出IOException,即不能通過此套接字的輸出流發送任何資料,
5. TCP網路編程
基于Socket的TCP編程
通信模型圖:
Java語言的基于套接字編程分為服務端編程和客戶端編程,其通信模型如圖所示:(先啟動服務端)

客戶端Socket的作業程序包含以下四個基本的步驟:
- 創建Socket:根據指定服務端的 IP 地址或埠號構造 Socket 類物件,若服務器端回應,則建立客戶端到服務器的通信線路,若連接失敗,會出現例外,
- 打開連接到Socket 的輸入/出流:使用 getInputStream()方法獲得輸入流,使用getOutputStream()方法獲得輸出流,進行資料傳輸
- 按照一定的協議對Socket 進行讀/寫操作:通過輸入流讀取服務器放入線路的資訊(但不能讀取自己放入線路的資訊),通過輸出流將資訊寫入執行緒,
- 關閉Socket:斷開客戶端到服務器的連接,釋放線路
客戶端創建Socket物件
-
客戶端程式可以使用Socket類創建物件,創建的同時會自動向服務器方發起連接,Socket的構造器是:
Socket(String host,int port)throws UnknownHostException,IOException; //向服務器(域名是host,埠號為port)發起TCP連接,若成功,則創建Socket物件,否則拋出例外, Socket(InetAddress address,int port)throws IOException; //根據InetAddress物件所表示的IP地址以及埠號port發起連接, -
客戶端建立socketAtClien物件的程序就是向服務器發出套接字連接請求
服務器程式的作業程序包含以下四個基本的步驟:
- **呼叫 ServerSocket(int port) **:創建一個服務器端套接字,并系結到指定埠上,用于監聽客戶端的請求,
- 呼叫 accept():監聽連接請求,如果客戶端請求連接,則接受連接,回傳通信套接字物件,
- 呼叫 該Socket類物件的 getOutputStream() 和 getInputStream ():獲取輸出流和輸入流,開始網路資料的發送和接收,
- 關閉ServerSocket和Socket物件:客戶端訪問結束,關閉通信套接字,
服務器建立 ServerSocket 物件
- ServerSocket 物件負責等待客戶端請求建立套接字連接,類似郵局某個視窗中的業務員,也就是說,服務器必須事先建立一個等待客戶請求建立套接字連接的ServerSocket物件,
- 所謂“接收”客戶的套接字請求,就是accept()方法會回傳一個 **Socket **物件
客戶端—服務端
- 客戶端:
- 自定義
- 瀏覽器
- 服務端:
- 自定義
- Tomcat服務器
代碼實體客戶端給服務端發送資訊
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
//客戶端
public class Client {
public static void main(String[] args) {
String host = null;
try {
//獲取本地計算機的ip地址 getHostAddress() 回傳文本顯示中的IP地址字串,
host = InetAddress.getLocalHost().getHostAddress();
} catch (UnknownHostException e) {
e.printStackTrace();
}
try (
//創建客戶端傳入要寫入的ip地址和埠號
Socket socket = new Socket(host, 8888);
//獲取位元組輸入流
OutputStream os = socket.getOutputStream()
) {
//給服務端寫入檔案
os.write("你好,我是客戶端".getBytes());
} catch (IOException e) {
e.printStackTrace();
}
//關流先開后關
}
}
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
//服務端
public class Server {
public static void main(String[] args) {
try (
//創建服務端
ServerSocket server = new ServerSocket();
//呼叫accept()表示接收來自客戶端的socket
Socket socket = server.accept();
//獲取客戶端的位元組輸入流
InputStream is = socket.getInputStream();
//創建記憶體操作流
ByteArrayOutputStream baos = new ByteArrayOutputStream();
) {
//創建byte陣列
byte[] buffer = new byte[5];
int len;
while ((len = is.read(buffer)) != -1) {
//使用記憶體操作流寫入陣列里面的資料
baos.write(buffer);
}
System.out.println(baos.toString());
System.out.println("收到了來自:"+socket.getInetAddress().getHostAddress()+"的資料")
} catch (IOException e) {
e.printStackTrace();
}
}
}
客戶端發送檔案給服務端,服務端將檔案保存再本地
//客戶端
@Test
public void Cilent() {
try (
//1
Socket socket = new Socket("127.0.0.1", 6666);
//2
OutputStream os = socket.getOutputStream();
//3
FileInputStream fis = new FileInputStream(new File("a.txt"));
) {
byte[] buffer = new byte[1024];
int len;
while ((len = fis.read(buffer)) != -1) {
os.write(buffer);
}
} catch (IOException e) {
e.printStackTrace();
}
}
//服務端
@Test
public void server(){
try (
//1
ServerSocket server = new ServerSocket(6666);
//2
Socket socket = server.accept();
//3
InputStream is = socket.getInputStream();
//4
FileOutputStream fos = new FileOutputStream(new File("b.txt"));
) {
byte[] buffer = new byte[1024];
int len;
while ((len = is.read(buffer)) != -1) {
fos.write(buffer);
}
} catch (IOException e) {
e.printStackTrace();
}//5
}
6. URP網路編程
UDP網路通信
- 類 DatagramSocket 和 DatagramPacket 實作了基于 UDP 協議網路程式,
- UDP資料報通過資料報套接字 DatagramSocket 發送和接收,系統不保證UDP資料報一定能夠安全送到目的地,也不能確定什么時候可以抵達,
- DatagramPacket 物件封裝了UDP資料報,在資料報中包含了發送端的IP地址和埠號以及接收端的IP地址和埠號,
- UDP協議中每個資料報都給出了完整的地址資訊,因此無須建立發送方和接收方的連接,如同發快遞包裹一樣,
DatagramSocket 類的常用方法
public DatagramSocket(int port) //創建資料報套接字并將其系結到本地主機上的指定埠,套接字將被系結到通配符地址,IP 地址由內核來選擇,
public DatagramSocket(int port,InetAddress laddr) //創建資料報套接字,將其系結到指定的本地地址,本地埠必須在 0 到 65535 之間(包括兩者),如果IP 地址為 0.0.0.0,套接字將被系結到通配符地址,IP 地址由內核選擇,
public void close() //關閉此資料報套接字,
public void send(DatagramPacket p) //從此套接字發送資料報包,DatagramPacket 包含的資訊指示:將要發送的資料、其長度、遠程主機的IP 地址和遠程主機的埠號,
public void receive(DatagramPacket p) //從此套接字接收資料報包,當此方法回傳時,DatagramPacket的緩沖區填充了接收的資料,資料報包也包含發送方的 IP 地址和發送方機器上的埠號, 此方法在接收到資料報前一直阻塞,資料報包物件的 length 欄位包含所接收資訊的長度,如果資訊比包的長度長,該資訊將被截短,
public InetAddress getLocalAddress() //獲取套接字系結的本地地址,
public int getLocalPort() //回傳此套接字系結的本地主機上的埠號,
public InetAddress getInetAddress() //回傳此套接字連接的地址,如果套接字未連接,則回傳null,
public int getPort() //回傳此套接字的埠,如果套接字未連接,則回傳-1,
public DatagramPacket(byte[] buf,int length) //構造 DatagramPacket,用來接收長度為length 的資料包,length 引數必須小于等于buf.length,
public DatagramPacket(byte[] buf,int length,InetAddress address,int port) //構造資料報包,用來將長度為 length 的包發送到指定主機上的指定埠號,length引數必須小于等于buf.length,
public InetAddress getAddress() //回傳某臺機器的 IP 地址,此資料報將要發往該機器或者是從該機器接收到的,
public int getPort() //回傳某臺遠程主機的埠號,此資料報將要發往該主機或者是從該主機接收到的,
public byte[] getData() //回傳資料緩沖區,接收到的或將要發送的資料從緩沖區中的偏移量offset 處開始,持續length 長度,
public int getLength() //回傳將要發送或接收到的資料的長度,
UDP網路通信
- 流 程:
- DatagramSocket與DatagramPacket
- 建立發送端,接收端
- 建立資料包
- 呼叫Socket的發送、接收方法
- 關閉Socket
- 發送端與接收端是兩個獨立的運行程式
代碼實體
//發送端
@Test
public void sender() throws IOException {
//創建DatagramSocket物件
DatagramSocket socket = new DatagramSocket();
String str = "我是UDP方式發送的導彈";
byte[] data = https://www.cnblogs.com/zk2020/p/str.getBytes();
//獲取本地的主機
InetAddress inet = InetAddress.getLocalHost();
//創建DatagramPacket物件,構造器中出入要發送的資料和埠號
DatagramPacket packet = new DatagramPacket(data, 0, data.length, inet, 9090);
socket.send(packet);
socket.close();
}
//接收端
@Test
public void receiver() throws IOException {
DatagramSocket socket = new DatagramSocket(9090);
byte[] buffer = new byte[100];
DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);
socket.receive(packet);
System.out.println(new String(buffer));
socket.close();
}
7. URL編程
URL
-
URL(Uniform Resource Locator):統一資源定位符,它表示 Internet 上某一資源的地址,
-
它是一種具體的URI,即URL可以用來標識一個資源,而且還指明了如何locate這個資源,
-
通過 **URL **我們可以訪問 **Internet **上的各種網路資源,比如最常見的 www,ftp站點,瀏覽器通過決議給定的 URL 可以在網路上查找相應的檔案或其他資源,
-
URL的基本結構由5部分組成:
<傳輸協議>://<主機名>:<埠號>/<檔案名>#片段名?引數串列-
例如:
http://192.168.1.100:8080/helloworld/index.jsp#a?username=shkstart&password=123 協議 主機名 埠號 資源地址 引數串列片段名:即錨點,例如看小說,直接定位到章節
引數串列格式:引數名=引數值&引數名=引數值 ...
-
URL類構造器
-
為了表示URL,java.net 中實作了類 URL,我們可以通過下面的構造器來初始化一個 URL 物件:
public URL (String spec); //通過一個表示URL地址的字串可以構造一個URL物件,例如:URL url = new URL ("http://www. atguigu.com/"); public URL(URL context, String spec); //通過基 URL 和相對 URL 構造一個 URL 物件,例如:URL downloadUrl = new URL(url, “download.html") public URL(String protocol, String host, String file); //例如:new URL("http","www.atguigu.com", “download. html"); public URL(String protocol, String host, int port, String file); //例如: URL gamelan = new URL("http", "www.atguigu.com", 80, “download.html"); -
URL類的構造器都宣告拋出非運行時例外,必須要對這一例外進行處理,通常是用 try-catch 陳述句進行捕獲,

URL類常用方法
-
一個URL物件生成后,其屬性是不能被改變的,但可以通過它給定的方法來獲取這些屬性:
public String getProtocol(); //獲取該URL的協議名 public String getHost(); //取該URL的主機名 public String getPort(); //獲取該URL的埠號 public String getPath(); //獲取該URL的檔案路徑 public String getFile(); //獲取該URL的檔案名 public String getQuery(); //獲取該URL的查詢名
代碼練習
public static void main(String[] args) {
try {
URL url = new URL("https://home.51cto.com/space?uid=14944368");
// public String getProtocol(); //獲取該URL的協議名
System.out.println(url.getProtocol());
// public String getHost(); //取該URL的主機名
System.out.println(url.getHost());
// public String getPort(); //獲取該URL的埠號
System.out.println(url.getPort());
// public String getPath(); //獲取該URL的檔案路徑
System.out.println(url.getPath());
// public String getFile(); //獲取該URL的檔案名
System.out.println(url.getFile());
// public String getQuery(); //獲取該URL的查詢名
System.out.println(url.getQuery());
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
/*
https
home.51cto.com
-1
/space
/space?uid=14944368
uid=14944368
*/
URLConnection類
針對HTTP協議的URLConnection類
- URL的方法 openStream():能從網路上讀取資料
- 若希望輸出資料,例如向服務器端的 CGI (公共網關介面-Common Gateway Interface-的簡稱,是用戶瀏覽器和服務器端的應用程式進行連接的介面)程式發送一些資料,則必須先與URL建立連接,然后才能對其進行讀寫,此時需要使用URLConnection ,
- URLConnection:表示到URL所參考的遠程物件的連接,當與一個URL建立連接時,首先要在一個 URL 物件上通過方法 openConnection() 生成對應的 URLConnection物件,如果連接程序失敗,將產生IOException.
- URL netchinaren = new URL ("http://www.atguigu.com/index.shtml");
- URLConnectonn u = netchinaren.openConnection( );
方法
-
通過URLConnection物件獲取的輸入流和輸出流,即可以與現有的CGI程式進行互動,
public Object getContent( ) throws IOException public int getContentLength( ) public String getContentType( ) public long getDate( ) public long getLastModified( ) public InputStream getInputStream( )throws IOException public OutputSteram getOutputStream( )throws IOException
URI、URL和URN的區別
-
URI,是uniform resource identifier,統一資源識別符號,用來唯一的標識一個資源,而URL是uniform resource locator,統一資源定位符,它是一種具體的URI,即URL可以用來標識一個資源,而且還指明了如何locate這個資源,而URN,uniform resource name,統一資源命名,是通過名字來標識資源,比如mailto:[email protected],也就是說,URI是以一種抽象的,高層次概念定義統一資源標識,而URL和URN則是具體的資源標識的方式,URL和URN都是一種URI,
-
在Java的URI中,一個URI實體可以代表絕對的,也可以是相對的,只要它符合URI的語法規則,而URL類則
不僅符合語意,還包含了定位該資源的資訊,
因此它不能是相對的,

代碼實作網路下載檔案:
public static void main(String[] args) throws IOException {
URL url = new URL("http:localhost:8080/examples/beauty.jpg");
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
//獲取連接
urlConnection.connect();
InputStream is = urlConnection.getInputStream();
FileOutputStream fos = new FileOutputStream("day20\\beauty12.jpg");
byte[] buffer = new byte[1024];
int len;
while ((len = is.read(buffer)) != -1) {
fos.write(buffer);
}
fos.close();
is.close();
urlConnection.disconnect();//斷開連接
}
小結
- 位于網路中的計算機具有唯一的IP地址,這樣不同的主機可以互相區分,
- 客戶端-服務器是一種最常見的網路應用程式模型,服務器是一個為其客戶端提供某種特定服務的硬體或軟體,客戶機是一個用戶應用程式,用于訪問某臺服務器提供的服務,埠號是對一個服務的訪問場所,它用于區分同一物理計算機上的多個服務,套接字用于連接客戶端和服務器,客戶端和服務器之間的每個通信會話使用一個不同的套接字,TCP協議用于實作面向連接的會話,
- Java 中有關網路方面的功能都定義在 java.net 程式包中,Java 用 InetAddress 物件表示 IP地址,該物件里有兩個欄位:主機名(String) 和 IP 地址(int),
- 類 Socket 和 ServerSocket 實作了基于TCP協議的客戶端-服務器程式,Socket是客戶端和服務器之間的一個連接,連接創建的細節被隱藏了,這個連接提供了一個安全的資料傳輸通道,這是因為 TCP 協議可以解決資料在傳送程序中的丟失、損壞、重復、亂序以及網路擁擠等問題,它保證資料可靠的傳送,
- 類 URL 和 URLConnection 提供了最高級網路應用,URL 的網路資源的位置來同一表示Internet 上各種網路資源,通過URL物件可以創建當前應用程式和 URL 表示的網路資源之間的連接,這樣當前程式就可以讀取網路資源資料,或者把自己的資料傳送到網路上去,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/247278.html
標籤:Java
上一篇:淺談大型網站之負載均衡架構
