文章目錄
- 前言
- 一、網絡程式設計概述
- 1、什麼是網絡程式設計
- 2、網絡通信要素
- 認識網絡通信協定
- 要素1:IP位址和端口号
- 知識補充
- 認識InetAddress類
- 要素2:網絡協定
- 二、TCP網絡程式設計
- 例題一:建立用戶端與服務端實作發送與接收
- 例題二:用戶端發送一張圖檔到伺服器端
- 例題三:用戶端發送資料到服務端,服務端再傳回資料到用戶端
- 服務端—Tomcat
- 三、UDP網絡程式設計
- 認識UDP的相關類
- 小案例
- 四、URL程式設計
- 1、認識URL及URL類
- 2、針對Http協定的URLConnection類
- 小案例
- 參考資料
前言
去年四月份大一下半學期正式開始學習Java,一路從java基礎、資料庫、jdbc、javaweb、ssm以及Springboot,其中也學習了一段時間資料結構。
在javaweb期間做了圖書商城項目、ssm階段做了權限管理項目,springboot學了之後手癢去b站看視訊做了個個人部落格項目(已部署到伺服器,正在備案中)。期間也不斷進行做筆記,總結,但是越學到後面越感覺有點虛,覺得自己基礎還有欠缺。
之後一段時間我會重新回顧java基礎、學習一些設計模式,學習多線程并發之類,以及接觸一些jvm的相關知識,越學到後面越會感覺到基礎的重要性,之後也會以部落格形式輸出學習的内容。
現在整理的java知識基礎點是在之前學習尚矽谷java課程的筆記基礎之上加工彙總,部分圖檔會引用尚矽谷或網絡上搜集或自己畫,在重新回顧的過程中也在不斷進行查漏補缺,盡可能将之前困惑的點都解決,讓自己更上一層樓吧。
部落格目錄索引:部落格目錄索引(持續更新)
一、網絡程式設計概述
1、什麼是網絡程式設計
Java
是Internet上的語言,從語言級别上提供了網絡應用程式的支援,通過
java.net
網絡功能包,能夠很容易的開發網絡應用程式。
- 聯網的底層細節被隐藏在Java的本機安裝系統裡,由
進行控制。并且Java實作了一個跨平台的網絡庫,相當于程式員面對的是一個統一的網絡程式設計環境。JVM
說是說給我們提供了網絡功能包,但是對于網絡一些基礎知識應該是在要知曉并且了解的,負責碰到實際一些麻煩時若是沒有一些基礎會找不到問題源頭所在。
計算機網絡:将分布在不同地理區域的計算機與專門的外部裝置用通信線路互連城一個規模大、功能強的網絡系統,進而使衆多的計算機可以友善地互相傳遞資訊、共享硬體、軟體、資料資訊等資源。
網絡程式設計目的:直接或間接地通過網絡協定與其他計算機實作資料交換,進行通訊。
2、網絡通信要素
認識網絡通信協定
問題描述
問題1:如何準确定位網絡上一台或多太主機;定位主機上的特定應用?
- 通過IP位址與端口号
問題2:找到主機後如何進行可靠高效的資料傳輸?
- 提供網絡通信協定:TCP/IP參考模型(應用層、傳輸層、網絡層、實體層以及資料鍊路層)
網絡通信也可以稱為
socket通信
或者
socket程式設計
。
認識一下網絡通信協定
對于網絡通信協定有兩套參考模型:
-
參考模型:模型過于理想化,未在網際網路上廣泛推行。OSI
-
參考模型(或TCP/IP協定):事實上的國際标準。TCP/IP
網絡通信協定對速率、傳輸代碼、代碼結構、傳輸控制步驟以及出錯控制等制定标準。
網絡通信涉及内容很多,例如指定源位址和目标位址、加密節目,壓縮加壓,差錯控制,流量控制,路由控制,那麼這麼多内容如何更好的處理呢?
- 将通信協定分層,即同層間可以通信、上一層可以調用下一層,并且與下一層不發生關系,各層互不影響便于系統開發與擴充。
分層如下圖:

對于傳輸的資料在不同層也進行了封裝:
要素1:IP位址和端口号
知識補充
①IP位址(InetAddress):唯一辨別Internet的計算機。
- 分類一:IPV4和IPV6
- IPV4:4個位元組組成,4個0-255,大概42億個,北美有30億,亞洲4億,在2011年初已經用盡,例如192.168.0.1
- IPV6:16個位元組,寫成8個無符号整數,每個整數用四個十六進制來表示,例如:3ffe:3201:1401:1280:c8ff:fe4d:db39:1984。(冒号隔開)
- 分類2:公網位址(網際網路使用)和私有位址(區域網路使用)。例如192.168.開頭就是私有位址,範圍為192.168.0.0-192.168.255.255。
本地回環位址(hostAddress):127.0.0.1 主機名(hostName):localhost
②TCP端口:隻是一個16位寬、用來識别伺服器上特定程式的數字。
- 網頁伺服器(8080),Telnet(23),POP3郵件伺服器(110),SMTP郵局交換伺服器(25),Tomcat(8080),Mysql(3306),Oracle(1521)。
- 每個伺服器上都有65536個端口(0-65535)
- 0-1023的TCP端口号是保留給已知的特定伺服器使用,不應該使用這個範圍的,若是我們自己使用的話一般在1024-65535這個範圍。
不同程式無法使用同一個端口,若是想要使用(稱綁定)會受到
BindException。
。
IP位址與端口号組合就能夠得出一個網絡套接字:
Socket
。
- 通過
進行連接配接,Socket
是個代表兩台機器之間網絡連接配接的對象(java.net.Socket),我們不需要在乎低層的細節,因為這是在底層的網絡裝置中處理掉的。這種 網絡裝置是一種讓運作在Java虛拟機上的程式能夠找到方法去通過實際的硬體(如網卡)在機器之間傳送資料的機制。Socket
- 這部分由作業系統的特定部分以及Java的網絡API所組成,我們隻需要考慮高層的部分。
認識InetAddress類
在Java中使用
InetAddress
類來代表IP位址,檢視一下執行個體化方法:
- 比較常用的是
、getByName(String host)
getLocalhost()
并且這裡列舉兩個常用方法:
-
:擷取主機位址getHostAddress()
-
:擷取主機域名getHostName()
@Test
public void test01() throws UnknownHostException {
//擷取執行個體方法1:傳回回送位址
InetAddress ip = InetAddress.getLoopbackAddress();
System.out.println(ip);//localhost/127.0.0.1
//擷取執行個體方法2:通過輸入主機名擷取id位址 涉及到DNS解析
InetAddress ip1 = InetAddress.getByName("www.baidu.com");
System.out.println(ip1);//www.baidu.com/36.152.44.95
//使用兩個常用方法分别擷取主機名以及ip位址
System.out.println(ip1.getHostName());//www.baidu.com
//擷取原始ip位址
System.out.println(ip1.getAddress());//[B@621be5d1
System.out.println(ip1.getHostAddress());//36.152.44.95
}
要素2:網絡協定
網絡協定有很多很多,對于不同層也有不同的協定。
傳輸層兩個重要的協定:
- 傳輸控制協定
(Transmission Control Protocal)CP
- 使用該協定前需要建立TCP連接配接,采用三次握手方式(可靠的),形成傳輸資料通道之後進行大資料量傳輸,傳輸完畢之後還有四次揮手來中斷連接配接。安全,但是效率低。
-
協定可以解決資料在傳送過程中的丢失、損壞、重複、亂序以及網絡 擁擠等問題,它保證資料可靠的傳送。TCP
- 使用者資料報協定
(User Datagram Protocal)UDP
- 直接将資料、源、目的封裝成資料包發送過去,不需要進行連接配接,直接發送。每個資料包大小限制在64K内,發送資料結束後也無需釋放資源,開銷小速度快,但是不安全,容易丢失。
TCP場景:打電話
UDP場景:發送短信,發電報
二、TCP網絡程式設計
例題一:建立用戶端與服務端實作發送與接收
用戶端:
//用戶端
@Test
public void test01() {
//首先建立ip位址執行個體
InetAddress ip = InetAddress.getLocalHost();
//建立socket執行個體,添加一個目标端口
try(Socket socket = new Socket(ip, 8899);
OutputStream os = socket.getOutputStream();){
//發送資料,通過寫入位元組傳輸
os.write("服務端你好,我是用戶端".getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
- 建立Socket執行個體(包含ip位址以及端口号),接着使用
擷取到其中的輸出流,直接使用write()寫入想要傳的字元串即可發送過去。getOutputStream()
服務端:
//服務端
@Test
public void test02(){
try( //建立ServerSocket用來接收Socket
ServerSocket ss = new ServerSocket(8899);
//accept()方法會在等待使用者的Socket連接配接時閑置下來,一旦使用者連接配接,會傳回一個Socket來友善通信
Socket socket = ss.accept();
InputStream is = socket.getInputStream();
//通過這個位元組數組輸出流來擷取傳入過來的位元組
ByteArrayOutputStream baos = new ByteArrayOutputStream();){
//進行讀取資料
byte[] data = new byte[20];
int len;
while((len = is.read(data))!=-1){
baos.write(data,0,len);
}
//列印出輸入到該流中的内容
System.out.println("接收到主機名:"+socket.getInetAddress().getHostName()+
",ip位址為"+socket.getInetAddress().getHostAddress()+" 接收内容如下:");
System.out.println(baos.toString());
} catch (IOException e) {
e.printStackTrace();
}
}
- 建立
執行個體,指定開放的端口,通過accept()方法等待接收ServerSocket
資料包。Socket
- 通過
來存儲從ByteArrayOutputStream
中讀出的資料,建立Socket
不需要指定節點流,擷取讀出的位元組内容直接使用toString()方法即可。ByteArrayOutputStream
先啟動服務端,之後啟動用戶端發送資料包:
例題二:用戶端發送一張圖檔到伺服器端
思路:用戶端使用
FileInputStream
來讀取本地的圖檔位元組,之後通過指定的IP位址與端口号的
Socket
将資料傳輸出去,服務端使用
FileOutputStream
從
ServiceSocket
中的
Socket
讀取傳來的資料直接儲存到本地。
用戶端:
//用戶端
@Test
public void test01() {
InetAddress ip = InetAddress.getLocalHost();
try( Socket socket = new Socket(ip, 8899);
//擷取輸入流
OutputStream os = socket.getOutputStream();
//讀取本地檔案
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("1234.jpg"));){
byte[] data = new byte[1024];
int len;
while((len = bis.read(data))!=-1){
//發送位元組
os.write(data,0,len);
}
} catch (IOException e) {
e.printStackTrace();
}
}
服務端:
//服務端
@Test
public void test02(){
try( //建立ServerSocket用來接收Socket
ServerSocket ss = new ServerSocket(8899);
//accept()方法會在等待使用者的Socket連接配接時閑置下來,一旦使用者連接配接,會傳回一個Socket來友善通信
Socket socket = ss.accept();
InputStream is = socket.getInputStream();
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("changlu.jpg"));){
//進行讀取資料
byte[] data = new byte[20];
int len;
while((len = is.read(data))!=-1){
bos.write(data,0,len);
}
//列印出輸入到該流中的内容
System.out.println("接收到主機名:"+socket.getInetAddress().getHostName()+
",ip位址為"+socket.getInetAddress().getHostAddress()+"發送的圖檔");
} catch (IOException e) {
e.printStackTrace();
}
}
- 這裡使用了緩沖流來處理檔案流。
例題三:用戶端發送資料到服務端,服務端再傳回資料到用戶端
與上面例2有些相同,隻不過多了一些做的内容,本題在接收到資料之後還要重新發送資料到用戶端,用戶端也要進行接收,接下來看下面的示範,主要是-------------下内容。
用戶端:
//用戶端
@Test
public void test01() {
InetAddress ip = InetAddress.getLocalHost();
try( Socket socket = new Socket(ip, 8899);
//擷取輸入流
OutputStream os = socket.getOutputStream();
//讀取本地檔案
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("1234.jpg"));){
byte[] data = new byte[1024];
int len;
while((len = bis.read(data))!=-1){
//發送位元組
os.write(data,0,len);
}
System.out.println("用戶端已成功發送圖檔");
//-----------------------------------
//主要來接收服務端收到我們照片後發來資訊
//首先禁用此套接字的輸出流,之後進行讀取操作
socket.shutdownOutput();
InputStream is = socket.getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
data = new byte[1024];
len = 0;
while((len = is.read(data)) != -1){
baos.write(data,0,len);
}
System.out.println("接收到服務端發送的資料為:"+baos.toString());
} catch (IOException e) {
e.printStackTrace();
}
}
- 關鍵部分是21行的
是關閉輸出流,如果不手動關閉的話會有阻塞問題,如下socket.shutdownOutput();
-
Java學習筆記 10、網絡程式設計
服務端:
//服務端
@Test
public void test02(){
try( //建立ServerSocket用來接收Socket
ServerSocket ss = new ServerSocket(8899);
//accept()方法會在等待使用者的Socket連接配接時閑置下來,一旦使用者連接配接,會傳回一個Socket來友善通信
Socket socket = ss.accept();
InputStream is = socket.getInputStream();
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("changlu.jpg"));){
//進行讀取資料
byte[] data = new byte[20];
int len;
while((len = is.read(data))!=-1){
bos.write(data,0,len);
}
//列印出輸入到該流中的内容
System.out.println("接收到主機名:"+socket.getInetAddress().getHostName()+
",ip位址為"+socket.getInetAddress().getHostAddress()+"發送的圖檔");
//------------------------------------
//發送資料到用戶端
//擷取到資料流
OutputStream os = socket.getOutputStream();
os.write("服務端已接收到圖檔,感謝你的分享!".getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
- 這裡當圖檔資料讀取之後可以直接擷取
的輸出流,再通過輸出流Socket
即可發送資料了。write()
服務端—Tomcat
伺服器處理流程:針對于jsp
- 用戶端請求 —> tomcat伺服器 -->java程式 —>傳回相對應的html(前後端沒有分離傳回的是html,分離了就傳回json資料結構)
**介紹:**伺服器實際上就是已經使用代碼編寫号的一個可以根據浏覽器發送的請求到本地伺服器并調用執行對應邏輯代碼的容器。我們隻需要安裝伺服器到本地并将事先編寫好的處理業務邏輯請求的代碼放置到伺服器指定位置。伺服器一旦啟動就能夠根據接收到的請求來執行指定的邏輯代碼。
之後我們會使用servlet來處理業務邏輯。
三、UDP網絡程式設計
認識UDP的相關類
UDP是直接發送資料,不需要與服務端進行連接配接的,使用UDP程式設計的話,java也有相應的API可供調用使用,一般使用
DatagramSocket
與
DatagramPacket
搭配并使用
send()
與
receive()
方法進行發送與接收。
相對于TCP程式設計不同點介紹:
- 作為發送端
是無參構造器,而DatagramSocket
的構造器中則需要填入指定内容的位元組數組、長度、ip位址以及端口号。DatagramPacket
- 作為接收端
需要确定端口号,DatagramSocket
僅僅填入位元組數組與長度DatagramPacket
兩個類介紹:
DatagramSocket
:資料報包,用于實作無連接配接分組傳送服務,下面是常用方法
-
:擷取套接字綁定的本地位址。public InetAddress getLocalAddress()
-
:傳回此套接字綁定的本地主機上的端口号。public int getLocalPort()
-
:傳回此套接字連接配接的位址。如果套接字未連接配接,則傳回 null。public InetAddress getInetAddress()
-
:傳回此套接字的端口。如果套接字未連接配接,則傳回 -1。public int getPort()
DatagramSocket
:發送與接收資料報資料包的套接字,下面是常用方法
-
:傳回某台機器的 IP 位址,此資料報将要發往該 機器或者是從該機器接收到的。public InetAddress getAddress()
-
:傳回某台遠端主機的端口号,此資料報将要發往該主機或 者是從該主機接收到的。public int getPort()
-
:傳回資料緩沖區。接收到的或将要發送的資料從緩沖區 中的偏移量 offset 處開始,持續 length 長度。public byte[] getData()
-
:傳回将要發送或接收到的資料的長度。public int getLength()
小案例
描述:使用UDP來發送指定内容的資料包到接收端,列印出來。
發送端:
//發送端
@Test
public void test01() {
//建立一個空參的DatagramSocket執行個體
try(DatagramSocket ds = new DatagramSocket();){
byte[] data = "我是UDP傳來的資料包".getBytes();
//建立資料包 待發出的位元組數組、發送資料包長度,InetAddress執行個體,端口号
DatagramPacket packet = new DatagramPacket(data, data.length, InetAddress.getLocalHost(), 8899);
//發送資料包
ds.send(packet);
}catch (IOException e) {
e.printStackTrace();
}
}
- 直接将資料放置到
執行個體中,并用DatagramPacket
的send()發送資料包DatagramSocket
接收端:
//接收端
@Test
public void test02(){
//建立執行個體時需要指定端口
try(DatagramSocket ds = new DatagramSocket(8899);){
byte[] data = new byte[1024];
//這裡需要填入一個位元組數組用于等會進行接收,還有作為接收的長度
DatagramPacket packet = new DatagramPacket(data, data.length);
//進行接收,需要資料包作為參數之後将資料放置到其中
ds.receive(packet);
//使用ds.getData()方法擷取位元組數組,之後轉為字元串列印輸出
System.out.println(new String(packet.getData(),0,packet.getData().length));
} catch (IOException e) {
e.printStackTrace();
}
}
- 我們需要拿到用戶端發送的資料包内容那麼就需要使用
執行個體的DatagramSocket
方法,注意其中需要有一個receive()
執行個體來進行接收資料。DatagramPacket
- 如何拿到包中的資料呢?調用
的getData()即可拿到傳輸過來的位元組。DatagramPacket
**注意:**UDP程式設計與TCP程式設計最大的不同就是TCP需要開啟服務端之後再進行發送端發送,才能夠順利進行;UDP是直接發送資料過去,速度快但是并不穩定安全,系統不保證 UDP資料報一定能夠安全送到目的地,也不能确定什麼時候可以抵達。
四、URL程式設計
1、認識URL及URL類
了解一下URL
URL
(Uniform Resource Locator):統一資源定位符,它表示 Internet 上某一資源的位址。
- URL不僅用來辨別一個資源,還指名了如何locate(定位)這個資源。
- 通過URL我們可以通路Internet上的各種網絡資源,例如最常見的
,www
站點。ftp
- 浏覽器通過解析指定的URL可以在網絡上查找相應的檔案及資源。
URL基本組成(5部分):
<傳輸協定>://<主機名>:<端口号>/<檔案名>#片段名?參數清單
-
表示指定錨點,用于目前頁面的指定部分。#
- 參數清單:表示傳遞的參數
認識URL類
通過URL對象可以建立目前應用程式和 URL 表示的網絡資源之 間的連接配接,這樣目前程式就可以讀取網絡資源資料,或者把自己的資料傳送到網絡上去
在java中使用
URL
類來表示URL,我們通過構造器來建立執行個體,其執行個體會抛出異常:
-
:通過一個表示URL位址的字元串可以構造一個URL對象public URL (String spec)
- 例如:URL url = new URL (“http://www. atguigu.com/”);
-
:通過基 URL 和相對 URL 構造一個 URL 對象public URL(URL context, String spec)
- 例如:URL downloadUrl = new URL(url, “download.html")
-
:通過協定,主機名及指定頁面public URL(String protocol, String host, String file);
- 例如:URL down = 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執行個體方法:
-
:擷取該URL的協定名public String getProtocol( )
-
:擷取該URL的主機名public String getHost( )
-
:擷取該URL的端口号public String getPort( )
-
:擷取該URL的檔案路徑public String getPath( )
-
:擷取該URL的檔案名public String getFile( )
-
:擷取該URL的查詢名public String getQuery( )
實操一下:
//用戶端
@Test
public void test01() throws MalformedURLException {
URL url = new URL("https://www.baidu.com/");
System.out.println("Protocol():"+url.getProtocol());
System.out.println("getHost():"+url.getHost());
System.out.println("getPort():"+url.getPort());
System.out.println("getPath():"+url.getPath());
System.out.println("getFile():"+url.getFile());
System.out.println("getQuery():"+url.getQuery());
}
2、針對Http協定的URLConnection類
若我們想向伺服器發送一些資料,例如向伺服器端的CGI(公共網關接口-Common GatewayInterface,是使用者浏覽器與伺服器端的應用程式連接配接的接口)資料,我們就需要與
URL
建立連接配接,之後才能進行讀寫操作,那麼就需要使用
URLConnection
。
URLConnection
類:表示到URL所引用的遠端對象連接配接。當我們執行個體化URL建立連接配接時,首先要在URL對象上通過方法
openConnection()
生成對應的URLConnection對象。
- 通過該對象來擷取輸入流與輸出流,與伺服器端的CGI程式進行互動。
相關方法:
-
:若是調用時尚未與url連接配接,那麼打開與此URL引用的資源通信連結。public void connect()
-
:檢索此url連接配接的内容。public Object getContent( ) throws IOException
-
:傳回content-encoding标題字段的值。public int getContentLength( )
-
:傳回content-type标題字段的值。public String getContentType( )
-
:取到date字段的值。public long getDate( )
-
:取得last-modified的值。public long getLastModified( )
-
:獲得打開連接配接的讀取輸入流。public InputStream getInputStream( )throws IOException
-
:擷取寫入此連接配接的輸出流。public OutputSteram getOutputStream( )throws IOException
小案例
下載下傳指定url的圖檔:
@Test
public void test01() throws IOException {
URL url = new URL("https://pics7.baidu.com/feed/fc1f4134970a304ec448a9204a685981c8175c2e.jpeg?token=b8477ffbb8442bf478c2a6cfeeefc62a&s=FCCB905416190DD0962277900300D09C");
//擷取URLConnection執行個體
URLConnection conn = url.openConnection();
//進行連接配接
conn.connect();
//擷取連接配接的輸入流
InputStream is = conn.getInputStream();
//建立位元組緩沖流包裹檔案輸出流
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("upload.jpg"));
//讀取操作
byte[] data = new byte[1024];
int len;
while((len = is.read(data))!=-1){
bos.write(data,0,len);
}
}
- 将指定url位址的圖檔下載下傳到本地。
參考資料
[1]. 尚矽谷-Java30天基礎-網絡程式設計(宋紅康)
我是長路,感謝你的閱讀,如有問題請指出,我會聽取建議并進行修正。
歡迎關注我的公衆号:長路Java,其中會包含軟體安裝等其他一些資料,包含一些視訊教程以及學習路徑分享。
學習讨論qq群:891507813 我們可以一起探讨學習
注明:轉載可,需要附帶上文章連結