Java基础:网络编程
1. 網絡編程概述
自從互聯網誕生以來,現在基本上所有的程序都是網絡程序,很少有單機版的程序了。
計算機網絡就是把各個計算機連接到一起,讓網絡中的計算機可以互相通信。網絡編程就是如何在程序中實現兩臺計算機的通信。
舉個例子,當你使用瀏覽器訪問新浪網時,你的計算機就和新浪的某臺服務器通過互聯網連接起來了,然后,新浪的服務器把網頁內容作為數據通過互聯網傳輸到你的電腦上。
由于你的電腦上可能不止瀏覽器,還有QQ、Skype、Dropbox、郵件客戶端等,不同的程序連接的別的計算機也會不同,所以,更確切地說,網絡通信是兩臺計算機上的兩個進程之間的通信。比如,瀏覽器進程和新浪服務器上的某個Web服務進程在通信,而QQ進程是和騰訊的某個服務器上的某個進程在通信。
1.1 計算機網絡
是指將地理位置不同的具有獨立功能的多臺計算機及其外部設備,通過通信線路連接起來,在網絡操作系統,網絡管理軟件及網絡通信協議的管理和協調下,實現資源共享和信息傳遞的計算機系統。
1.2 網絡編程
就是用來實現網絡互連的不同計算機上運行的程序間可以進行數據交換。
1.3 網絡模型
計算機網絡之間以何種規則進行通信,就是網絡模型研究問題。
網絡模型一般是指OSI(Open System Interconnection開放系統互連)參考模型或者TCP/IP參考模型。
| 應用層(包括Telnet、FTP、SNTP協議) | 會話層、表示層和應用層 |
| 傳輸層(包括TCP、UDP協議) | 傳輸層 |
| 網絡層(包括ICMP、IP、ARP等協議) | 網絡層 |
| 數據鏈路層 | 物理層和數據鏈路層 |
- 應用層:http、https、ftp、smtp
- 安全層:TSL、SSL
- 傳輸層:TCP、UDP
- 網絡層:IP
- 數據鏈路層
- 物理層
1.4 網絡模型7層概述
物理層:主要定義物理設備標準,如網線的接口類型、光纖的接口類型、各種傳輸介質的傳輸速率等。它的主要作用是傳輸比特流(就是由1、0轉化為電流強弱來進行傳輸,到達目的地后在轉化為1、0,也就是我們常說的數模轉換與模數轉換)。這一層的數據叫做比特。
數據鏈路層:主要將從物理層接收的數據進行MAC地址(網卡的地址)的封裝與解封裝。常把這一層的數據叫做幀。在這一層工作的設備是交換機,數據通過交換機來傳輸。
網絡層:主要將從下層接收到的數據進行IP地址(例192.168.0.1)的封裝與解封裝。在這一層工作的設備是路由器,常把這一層的數據叫做數據包。
傳輸層:定義了一些傳輸數據的協議和端口號(WWW端口80等),如:TCP(傳輸控制協議,傳輸效率低,可靠性強,用于傳輸可靠性要求高,數據量大的數據),UDP(用戶數據報協議,與TCP特性恰恰相反,用于傳輸可靠性要求不高,數據量小的數據,如QQ聊天數據就是通過這種方式傳輸的)。 主要是將從下層接收的數據進行分段和傳輸,到達目的地址后再進行重組。常常把這一層數據叫做段。
會話層:通過傳輸層(端口號:傳輸端口與接收端口)建立數據傳輸的通路。主要在你的系統之間發起會話或者接受會話請求(設備之間需要互相認識可以是IP也可以是MAC或者是主機名)
表示層:主要是進行對接收的數據進行解釋、加密與解密、壓縮與解壓縮等(也就是把計算機能夠識別的東西轉換成人能夠能識別的東西(如圖片、聲音等)。
應用層:主要是一些終端的應用,比如說FTP(各種文件下載),WEB(IE瀏覽),QQ之類的(可以把它理解成我們在電腦屏幕上可以看到的東西.就是終端應用)。
PS:
- 每個網卡的MAC地址都是全球唯一的。
- 路由器實現將數據包發送到指定的地點。
- 應用軟件之間通信的過程就是層與層之間封包、解封包的過程。
- OSI參考模型雖然設計精細,但過于麻煩,效率不高,因此才產生了簡化版的TCP/IP參考模型。
1.5 封包、解封包的過程
2. 網絡編程三要素
網絡模型說完了,我們要進行通訊,需要哪些要素呢?
比如說:我要跟你說話
- 第一個條件:我要先找到你 (IP)
要想使網絡中的計算機能夠進行通信,必須為每臺計算機指定一個標識號,通過這個標識號來指定接收數據的計算機或者發送數據的計算機。在TCP/IP協議中,這個標識號就是IP地址,它可以唯一標識一臺計算機。目前,IP地址廣泛使用的版本是IPv4,它由4個字節大小的二進制數來表示,如:00001010000000000000000000000001。由于二進制形式表示的IP地址非常不便記憶和處理,因此通常會將IP地址寫成十進制的形式,每個字節用一個十進制數字(0-255)表示,數字間用符號“.”分開,如 “10.0.0.1”。
隨著計算機網絡規模的不斷擴大,對IP地址的需求也越來越多,IPv4這種用4個字節表示的IP地址將面臨使用枯竭的局面。為解決此問題,IPv6 便應運而生。IPv6使用16個字節表示IP地址,它所擁有的地址容量約是IPv4的8×1028倍,達到2128個(算上全零的),這樣就解決了網絡地址資源數量不足的問題。
IP地址由兩部分組成,即“網絡.主機”的形式,其中網絡部分表示其屬于互聯網的哪一個網絡,是網絡的地址編碼,主機部分表示其屬于該網絡中的哪一臺主機,是網絡中一個主機的地址編碼,二者是主從關系。IP地址總共分為5類,常用的有3類,介紹如下。
- A類地址:由第一段的網絡地址和其余三段的主機地址組成,范圍是1.0.0.0到127.255.255.255
- B類地址:由前兩段的網絡地址和其余兩段的主機地址組成,范圍是128.0.0.0到191.255.255.255
- C類地址:由前三段的網絡地址和最后一段的主機地址組成,范圍是192.0.0.0到223.255.255.255
另外,還有一個回送地址127.0.0.1,指本機地址,該地址一般用來測試使用,例如:ping 127.0.0.1 來測試本機TCP/IP是否正常。
- 第二個條件:你得有接收數據的地方,耳朵 (端口)
通過IP地址可以連接到指定計算機,但如果想訪問目標計算機中的某個應用程序,還需要指定端口號。在計算機中,不同的應用程序是通過端口號區分的。端口號是用兩個字節(16位的二進制數)表示的,它的取值范圍是0~65535,其中,0~1023之間的端口號由操作系統的網絡服務所占用,用戶的普通應用程序需要使用1024以上的端口號,從而避免端口號被另外一個應用或服務所占用。
IP地址和端口號的作用,如下圖所示:
從上圖中可以清楚地看到,位于網絡中的一臺計算機可以通過IP地址去訪問另一臺計算機,并通過端口號訪問目標計算機中的某個應用程序。
第三個條件:我跟你說話,你能接收到,咱按什么方式接收啊,我說英文你懂嗎,說韓文你懂嗎,不懂是吧,所以我還是說中文把(協議)
2.1 IP地址
網絡中計算機的唯一標識,不易記憶,可用主機名。本地回環地址:127.0.0.1,主機名:localhost。計算機只能識別二進制的數據,所以我們的IP地址應該是一個二進制的數據。為了方便表示IP地址,我們就把IP地址的每一個字節上的數據換算成十進制,然后用.分開來表示:”點分十進制”。
所謂IP地址就是給每個連接在Internet上的主機分配的一個32bit地址。按照TCP/IP規定,IP地址用二進制來表示,每個IP地址長32bit,比特換算成字節,就是4個字節。例如一個采用二進制形式的IP地址是“00001010000000000000000000000001”,這么長的地址,人們處理起來也太費勁了。為了方便人們的使用,IP地址經常被寫成十進制的形式,中間使用符號“.”分開不同的字節。于是,上面的IP地址可以表示為“10.0.0.1”。IP地址的這種表示法叫做“點分十進制表示法”,這顯然比1和0容易記憶得多。
通過ping 127.0.0.1可以測試網絡是不是通,如果不通,可能是網卡出問題了
通過ping命令還可以獲取到url對應的IP地址,例如獲取網易新聞url(c.m.163.com)的IP地址
查看本機IP地址ipconfig
2.1.1 IP地址分類
IP地址的組成:IP地址 = 網絡號碼+主機地址。IPV4數量已經不夠分配,所以產生了IPV6。
2.1.2 InetAddress類的使用
在JDK中,提供了一個與IP地址相關的InetAddress類,該類用于封裝一個IP地址,并提供了一系列與IP地址相關的方法,下表中列舉了InetAddress類的一些常用方法。
上表中,列舉了InetAddress的五個常用方法。其中,前兩個方法用于獲得該類的實例對象,第一個方法用于獲得表示指定主機的InetAddress對象,第二個方法用于獲得表示本地的InetAddress對象。通過InetAddress對象便可獲取指定主機名,IP地址等。
| InetAddress | getByName(String host) | 根據主機名或者IP地址的字符串表示得到IP地址對象 |
| String | getHostName() | 獲取此 IP 地址的主機名 |
| String | getHostAddress() | 返回 IP 地址字符串 |
代碼示例:
package cn.itcast_01; import java.net.InetAddress; import java.net.UnknownHostException; public class InetAddressDemo {public static void main(String[] args) throws UnknownHostException {// public static InetAddress getByName(String host)// InetAddress address = InetAddress.getByName("liuyi");// InetAddress address = InetAddress.getByName("192.168.12.92");InetAddress address = InetAddress.getByName("192.168.12.63");// 獲取兩個東西:主機名,IP地址// public String getHostName()String name = address.getHostName();// public String getHostAddress()String ip = address.getHostAddress();System.out.println(name + "---" + ip);} }運行結果:
2.2 端口號
正在運行的程序的標識,用于標識進程的邏輯地址,不同進程的標識。有效端口:0~65535,其中0~1024系統使用或保留端口。
端口分為:物理端口,網卡口;邏輯端口,我們指的就是邏輯端口。
- A:每個網絡程序都會至少有一個邏輯端口
- B:用于標識進程的邏輯地址,不同進程的標識
- C:有效端口:0~65535,其中0~1024系統使用或保留端口。
- D:所謂防火墻,其功能就是將發送到某程序端口的數據屏蔽掉以及將從該程序端口發出的數據也屏蔽掉。
2.3 傳輸協議
雖然通過計算機網絡可以使多臺計算機實現連接,但是位于同一個網絡中的計算機在進行連接和通信時必須要遵守一定的規則,這就好比在道路中行駛的汽車一定要遵守交通規則一樣。在計算機網絡中,這些連接和通信的規則被稱為網絡通信協議,它對數據的傳輸格式、傳輸速率、傳輸步驟等做了統一規定,通信雙方必須同時遵守才能完成數據交換。
網絡通信協議有很多種,目前應用最廣泛的是TCP/IP協議(Transmission Control Protocol/Internet Protocol,傳輸控制協議/英特網互聯協議)、UDP協議(User Datagram Protocol,用戶數據報協議)、ICMP協議(Internet Control Message Protocol,Internet 控制報文協議)和其他一些協議的協議組。
TCP/IP(又稱TCP/IP協議簇)是一組用于實現網絡互連的通信協議,其名稱來源于該協議簇中兩個重要的協議(TCP協議和IP協議)。基于TCP/IP的參考模型將協議分成四個層次,如下圖所示:
TCP/IP協議中的四層分別是鏈路層、網絡層、傳輸層和應用層,每層分別負責不同的通信功能
- 鏈路層:也稱為網絡接口層,該層負責監視數據在主機和網絡之間的交換。事實上,TCP/IP本身并未定義該層的協議,而由參與互連的各網絡使用自己的物理層和數據鏈路層協議與TCP/IP的網絡互聯層進行連接。
- 網絡層:也稱網絡互聯層,是整個TCP/IP協議的核心,它主要用于將傳輸的數據進行分組,將分組數據發送到目標計算機或者網絡。
- 傳輸層:主要使網絡程序進行通信,在進行網絡通信時,可以采用TCP協議,也可以采用UDP協議。
- 應用層:主要負責應用程序的協議,例如HTTP協議、FTP協議等。
傳輸協議就是通訊的規則,常見協議:TCP,UDP。
UDP將數據源和目的封裝成數據包中,不需要建立連接;每個數據報的大小在限制在64k;因無連接,是不可靠協議;不需要建立連接,速度快
TCP建立連接,形成傳輸數據的通道;在連接中進行大數據量傳輸;通過三次握手完成連接,是可靠協議;必須建立連接,效率會稍低
UDP和TCP的特點
- UDP:面向無連接;不可靠;速度快;將數據封包傳輸,數據包最大64k
舉例:聊天留言,在線視頻,視頻會議,發短信,郵局包裹。 - TCP:面向連接;安全可靠效率稍低;通過三次握手確保連接的建立。
舉例:下載,打電話,QQ聊天(你在線嗎,在線,就回應下,就開始聊天了)
2.4 域名解析
Internet管理機構采取了在主機名后加上后綴名的方法標識一臺主機,其后綴名被稱為域名。
在瀏覽器中輸入新浪的域名,DNS解析域名成IP,然后計算機再通過獲取到的IP訪問新浪服務器。
域名解析,最先走是本地的hosts(C:\WINDOWS\system32\drivers\etc\hosts)文件,解析失敗了,才去訪問DNS服務器解析、獲取IP地址。
import java.net.InetAddress; import java.net.UnknownHostException;public class IPDemo {public static void main(String[] args) throws UnknownHostException {InetAddress ip = InetAddress.getLocalHost();ip = InetAddress.getByName("192.168.1.110");System.out.println(ip.getHostAddress());System.out.println(ip.getHostName());} }運行結果
應用:通過hosts文件可以屏蔽游戲網站內容彈出,例如:在hosts文件中添加,127.0.0.1 www.game18.com
3. Socket套接字
為了更方便地開發網絡應用程序,美國的伯克利大學在UNIX上推出了一種應用程序訪問通信協議的操作系統調用套接字(socket)。socket的出現,使得程序員可以很方便地訪問TCP/IP,從而開發各種網絡應用的程序。后來,套接字被引進到Windows等操作系統,成為開發網絡應用程序的有效工具。
3.1 Socket套接字
網絡上具有唯一標識的IP地址和端口號組合在一起才能構成唯一能識別的標識符套接字。
3.2 Socket原理機制
- 通信的兩端都有Socket
- 網絡通信其實就是Socket間的通信
- 數據在兩個Socket間通過IO傳輸
3.3 Socket機制圖解
4. UDP編程
在介紹TCP/IP結構時,提到傳輸層的兩個重要的高級協議,分別是UDP和TCP,其中UDP是User Datagram Protocol的簡稱,稱為用戶數據報協議,TCP是Transmission Control Protocol的簡稱,稱為傳輸控制協議。
UDP是無連接通信協議,即在數據傳輸時,數據的發送端和接收端不建立邏輯連接。簡單來說,當一臺計算機向另外一臺計算機發送數據時,發送端不會確認接收端是否存在,就會發出數據,同樣接收端在收到數據時,也不會向發送端反饋是否收到數據。由于使用UDP協議消耗資源小,通信效率高,所以通常都會用于音頻、視頻和普通數據的傳輸,例如視頻會議使用UDP協議,因為這種情況即使偶爾丟失一兩個數據包,也不會對接收結果產生太大影響。但是在使用UDP協議傳送數據時,由于UDP的面向無連接性,不能保證數據的完整性,因此在傳輸重要數據時不建議使用UDP協議。
UDP:UDP 協議全稱是用戶數據報協議,在網絡中它與TCP 協議一樣用于處理數據包,是一種無連接的協議。在OSI 模型中,在第四層——傳輸層,處于IP 協議的上一層。UDP 有不提供數據包分組、組裝和不能對數據包進行排序的缺點,也就是說,當報文發送之后,是無法得知其是否安全完整到達的。UDP 用來支持那些需要在計算機之間傳輸數據的網絡應用。包括網絡視頻會議系統在內的眾多的客戶/服務器模式的網絡應用都需要使用UDP協議。UDP 協議從問世至今已經被使用了很多年,雖然其最初的光彩已經被一些類似協議所掩蓋,但是即使是在今天UDP 仍然不失為一項非常實用和可行的網絡傳輸層協議。
4.1 UDP傳輸
- DatagramSocket與DatagramPacket
- 建立發送端,接收端
- 建立數據包
- 調用Socket的發送接收方法
- 關閉Socket
- 發送端與接收端是兩個獨立的運行程序
4.2 DatagramPacket
此類表示數據報包。數據報包用來實現無連接包投遞服務。每條報文僅根據該包中包含的信息從一臺機器路由到另一臺機器。從一臺機器發送到另一臺機器的多個包可能選擇不同的路由,也可能按不同的順序到達。不對包投遞做出保證。
UDP是一種面向無連接的協議,因此,在通信時發送端和接收端不用建立連接。UDP通信的過程就像是貨運公司在兩個碼頭間發送貨物一樣,在碼頭發送和接收貨物時都需要使用集裝箱來裝載貨物。UDP通信也是一樣,發送和接收的數據也需要使用“集裝箱”進行打包,為此JDK中提供了一個DatagramPacket類,該類的實例對象就相當于一個集裝箱,用于封裝UDP通信中發送或者接收的數據。
想要創建一個DatagramPacket對象,首先需要了解一下它的構造方法。在創建發送端和接收端的DatagramPacket對象時,使用的構造方法有所不同,接收端的構造方法只需要接收一個字節數組來存放接收到的數據,而發送端的構造方法不但要接收存放了發送數據的字節數組,還需要指定發送端IP地址和端口號。
- DatagramPacket(byte[] buf,int length)
使用該構造方法在創建DatagramPacket對象時,指定了封裝數據的字節數組和數據的大小,沒有指定IP地址和端口號。很明顯,這樣的對象只能用于接收端,不能用于發送端。因為發送端一定要明確指出數據的目的地(IP地址和端口號),而接收端不需要明確知道數據的來源,只需要接收到數據即可。
- DatagramPacket(byte[] buf,int length,InetAddress addr,int port)
使用該構造方法在創建DatagramPacket對象時,不僅指定了封裝數據的字節數組和數據的大小,還指定了數據包的目標IP地址(addr)和端口號(port)。該對象通常用于發送端,因為在發送數據時必須指定接收端的IP地址和端口號,就好像發送貨物的集裝箱上面必須標明接收人的地址一樣。
- DatagramPacket(byte[] buf,int offset,int length)
該構造方法與第一個構造方法類似,同樣用于接收端,只不過在第一個構造方法的基礎上,增加了一個offset參數,該參數用于指定接收到的數據在放入buf緩沖數組時是從offset處開始的。
- DatagramPacket(byte[] buf,int offset,int length,InetAddress addr,int port)
該構造方法與第二個構造方法類似,同樣用于發送端,只不過在第二個構造方法的基礎上,增加了一個offset參數,該參數用于指定一個數組中發送數據的偏移量為offset,即從offset位置開始發送數據。
DatagramPacket類中的常用方法
上表中,列舉了DatagramPacket類的四個常用方法及其功能,通過這四個方法,可以得到發送或者接收到的DatagramPacket數據包中的信息。
4.3 DatagramSocket
此類表示用來發送和接收數據報包的套接字
數據報套接字是包投遞服務的發送或接收點。每個在數據報套接字上發送或接收的包都是單獨編址和路由的。從一臺機器發送到另一臺機器的多個包可能選擇不同的路由,也可能按不同的順序到達
在 DatagramSocket 上總是啟用 UDP 廣播發送。為了接收廣播包,應該將 DatagramSocket 綁定到通配符地址。在某些實現中,將 DatagramSocket 綁定到一個更加具體的地址時廣播包也可以被接收。
DatagramPacket數據包的作用就如同是“集裝箱”,可以將發送端或者接收端的數據封裝起來,然而運輸貨物只有“集裝箱”是不夠的,還需要有“碼頭”。同理,在程序中,要實現通信只有DatagramPacket數據包也是不行的,它也需要一個“碼頭”。為此,JDK提供了一個DatagramSocket類,該類的作用就類似于“碼頭”,使用這個類的實例對象就可以發送和接收DatagramPacket數據包。發送數據的過程如下圖所示。
在創建發送端和接收端的DatagramSocket對象時,使用的構造方法也有所不同,下面對DatagramSocket類中常用的構造方法進行講解。
- DatagramSocket()
該構造方法用于創建發送端的DatagramSocket對象,在創建DatagramSocket對象時,并沒有指定端口號,此時,系統會分配一個沒有被其他網絡程序所使用的端口號。
- DatagramSocket(int port)
該構造方法既可用于創建接收端的DatagramSocket對象,又可以創建發送端的DatagramSocket對象,在創建接收端的DatagramSocket對象時,必須要指定一個端口號,這樣就可以監聽指定的端口。
- DatagramSocket(int port,InetAddress addr)
使用該構造方法在創建DatagramSocket對象時,不僅指定了端口號,還指定了相關的IP地址。該對象的使用適用于計算機上有多塊網卡的情況,在使用時可以明確規定數據通過哪塊網卡向外發送和接收哪塊網卡的數據。由于計算機中針對不同的網卡會分配不同的IP,因此在創建DatagramSocket對象時需要通過指定IP地址來確定使用哪塊網卡進行通信。
DatagramSocket(int port) // 創建數據報套接字并將其綁定到本地主機上的指定端口 DatagramSocket(int port, InetAddress laddr) // 創建數據報套接字,將其綁定到指定的本地地址DatagramSocket類中的常用方法
上表中,針對DatagramSocket類中的常用方法及其功能進行了介紹。其中前兩個方法可以完成數據的發送或者接收的功能。
4.4 UDP傳輸-發送端思路
- 建立udp的socket服務
- 將要發送的數據封裝成數據包
- 通過udp的socket服務,將數據包發送出
- 關閉資源
4.5 UDP傳輸-接收端思路
- 建立udp的socket服務.
- 通過receive方法接收數據
- 將收到的數據存儲到數據包對象中
- 通過數據包對象的功能來完成對接收到數據進行解析
- 可以對資源進行關閉
運行結果:
4.6 UDP案例
從鍵盤錄入數據進行發送,如果輸入的是886那么客戶端就結束輸入數據。
發送端
package cn.itcast_04;import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress;/** 數據來自于鍵盤錄入* 鍵盤錄入數據要自己控制錄入結束。*/ public class SendDemo {public static void main(String[] args) throws IOException {// 創建發送端的Socket對象DatagramSocket ds = new DatagramSocket();// 封裝鍵盤錄入數據BufferedReader br = new BufferedReader(new InputStreamReader(System.in));String line = null;while ((line = br.readLine()) != null) {if ("886".equals(line)) {break;}// 創建數據并打包byte[] bys = line.getBytes();// DatagramPacket dp = new DatagramPacket(bys, bys.length,// InetAddress.getByName("192.168.12.92"), 12345);DatagramPacket dp = new DatagramPacket(bys, bys.length,InetAddress.getByName("192.168.12.255"), 12345);// 發送數據ds.send(dp);}// 釋放資源ds.close();} }運行結果:
接收端
package cn.itcast_04;import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket;/** 多次啟動接收端:* java.net.BindException: Address already in use: Cannot bind* 端口被占用。*/ public class ReceiveDemo {public static void main(String[] args) throws IOException {// 創建接收端的Socket對象DatagramSocket ds = new DatagramSocket(12345);while (true) {// 創建一個包裹byte[] bys = new byte[1024];DatagramPacket dp = new DatagramPacket(bys, bys.length);// 接收數據ds.receive(dp);// 解析數據String ip = dp.getAddress().getHostAddress();String s = new String(dp.getData(), 0, dp.getLength());System.out.println("from " + ip + " data is : " + s);}// 釋放資源// 接收端應該一直開著等待接收數據,是不需要關閉// ds.close();} }運行結果:
5. TCP編程
TCP協議是面向連接的通信協議,即在傳輸數據前先在發送端和接收端建立邏輯連接,然后再傳輸數據,它提供了兩臺計算機之間可靠無差錯的數據傳輸。在TCP連接中必須要明確客戶端與服務器端,由客戶端向服務器端發出連接請求,每次連接的創建都需要經過“三次握手”。第一次握手,客戶端向服務器端發出連接請求,等待服務器確認;第二次握手,服務器端向客戶端回送一個響應,通知客戶端收到了連接請求;第三次握手,客戶端再次向服務器端發送確認信息,確認連接。
由于TCP協議的面向連接特性,它可以保證傳輸數據的安全性,所以是一個被廣泛采用的協議,例如在下載文件時,如果數據接收不完整,將會導致文件數據丟失而不能被打開,因此,下載文件時必須采用TCP協議。
5.1 TCP/IP協議
雖然大家現在對互聯網很熟悉,但是計算機網絡的出現比互聯網要早很多。
計算機為了聯網,就必須規定通信協議,早期的計算機網絡,都是由各廠商自己規定一套協議,IBM、Apple和Microsoft都有各自的網絡協議,互不兼容,這就好比一群人有的說英語,有的說中文,有的說德語,說同一種語言的人可以交流,不同的語言之間就不行了。
為了把全世界的所有不同類型的計算機都連接起來,就必須規定一套全球通用的協議,為了實現互聯網這個目標,互聯網協議簇(Internet Protocol Suite)就是通用協議標準。Internet是由inter和net兩個單詞組合起來的,原意就是連接“網絡”的網絡,有了Internet,任何私有網絡,只要支持這個協議,就可以聯入互聯網。
因為互聯網協議包含了上百種協議標準,但是最重要的兩個協議是TCP和IP協議,所以,大家把互聯網的協議簡稱TCP/IP協議。
通信的時候,雙方必須知道對方的標識,好比發郵件必須知道對方的郵件地址。互聯網上每個計算機的唯一標識就是IP地址,類似123.123.123.123。如果一臺計算機同時接入到兩個或更多的網絡,比如路由器,它就會有兩個或多個IP地址,所以,IP地址對應的實際上是計算機的網絡接口,通常是網卡。
IP協議負責把數據從一臺計算機通過網絡發送到另一臺計算機。數據被分割成一小塊一小塊,然后通過IP包發送出去。由于互聯網鏈路復雜,兩臺計算機之間經常有多條線路,因此,路由器就負責決定如何把一個IP包轉發出去。IP包的特點是按塊發送,途徑多個路由,但不保證能到達,也不保證順序到達。
TCP協議則是建立在IP協議之上的。TCP協議負責在兩臺計算機之間建立可靠連接,保證數據包按順序到達。TCP協議會通過握手建立連接,然后,對每個IP包編號,確保對方按順序收到,如果包丟掉了,就自動重發。
許多常用的更高級的協議都是建立在TCP協議基礎上的,比如用于瀏覽器的HTTP協議、發送郵件的SMTP協議等。
一個IP包除了包含要傳輸的數據外,還包含源IP地址和目標IP地址,源端口和目標端口。
端口有什么作用?在兩臺計算機通信時,只發IP地址是不夠的,因為同一臺計算機上跑著多個網絡程序。一個IP包來了之后,到底是交給瀏覽器還是QQ,就需要端口號來區分。每個網絡程序都向操作系統申請唯一的端口號,這樣,兩個進程在兩臺計算機之間建立網絡連接就需要各自的IP地址和各自的端口號。
一個進程也可能同時與多個計算機建立鏈接,因此它會申請很多端口。
TCP/IP:Transmission Control Protocol/Internet Protocol 的簡寫,中譯名為傳輸控制協議/因特網互聯協議,又名網絡通訊協議,是Internet 最基本的協議、Internet 國際互聯網絡的基礎,由網絡層的IP 協議和傳輸層的TCP協議組成。TCP/IP 定義了電子設備如何連入因特網,以及數據如何在它們之間傳輸的標準。協議采用了4 層的層級結構,每一層都呼叫它的下一層所提供的協議來完成自己的需求。通俗而言:TCP 負責發現傳輸的問題,一有問題就發出信號,要求重新傳輸,直到所有數據安全正確地傳輸到目的地。而IP 是給因特網的每一臺聯網設備規定一個地址。
TCP/IP 協議棧主要分為四層:應用層、傳輸層、網絡層、數據鏈路層,每層都有相應的協議,如下圖:
所謂的協議就是雙方進行數據傳輸的一種格式。
5.2 TCP傳輸
TCP通信同UDP通信一樣,也能實現兩臺計算機之間的通信,但TCP通信的兩端需要創建socket對象。UDP通信與TCP通信的區別在于,UDP中只有發送端和接收端,不區分客戶端與服務器端,計算機之間可以任意地發送數據;而TCP通信是嚴格區分客戶端與服務器端的,在通信時,必須先由客戶端去連接服務器端才能實現通信,服務器端不可以主動連接客戶端,并且服務器端程序需要事先啟動,等待客戶端的連接。
在JDK中提供了兩個用于實現TCP程序的類,一個是ServerSocket類,用于表示服務器端;一個是Socket類,用于表示客戶端。通信時,首先要創建代表服務器端的ServerSocket對象,創建該對象相當于開啟一個服務,此服務會等待客戶端的連接;然后創建代表客戶端的Socket對象,使用該對象向服務器端發出連接請求,服務器端響應請求后,兩者才建立連接,開始通信。整個通信過程如下圖所示:
- Socket和ServerSocket
- 建立客戶端和服務器端
- 建立連接后,通過Socket中的IO流進行數據的傳輸
- 關閉socket
- 同樣,客戶端與服務器端是兩個獨立的應用程序。
5.3 ServerSocket
此類實現服務器套接字。服務器套接字等待請求通過網絡傳入。它基于該請求執行某些操作,然后可能向請求者返回結果。
在開發TCP程序時,首先需要創建服務器端程序。JDK的java.net包中提供了一個ServerSocket類,該類的實例對象可以實現一個服務器端的程序。ServerSocket類提供了多種構造方法。
- ServerSocket()
使用該構造方法在創建ServerSocket對象時并沒有綁定端口號,這樣的對象創建的服務器端沒有監聽任何端口,不能直接使用,還需要繼續調用bind(SocketAddress endpoint)方法將其綁定到指定的端口號上,才可以正常使用。
- ServerSocket(int port) 創建綁定到特定端口的服務器套接字
使用該構造方法在創建ServerSocket對象時,可以將其綁定到一個指定的端口號上(參數port就是端口號)。端口號可以指定為0,此時系統就會分配一個還沒有被其他網絡程序所使用的端口號。由于客戶端需要根據指定的端口號來訪問服務器端程序,因此端口號隨機分配的情況并不常用,通常都會讓服務器端程序監聽一個指定的端口號。
- ServerSocket(int port, int backlog)
該構造方法就是在第二個構造方法的基礎上,增加了一個backlog參數。該參數用于指定在服務器忙時,可以與之保持連接請求的等待客戶數量,如果沒有指定這個參數,默認為50。
- ServerSocket(int port, int backlog, InetAddress bindAddr)
該構造方法就是在第三個構造方法的基礎上,增加了一個bindAddr參數,該參數用于指定相關的IP地址。該構造方法的使用適用于計算機上有多塊網卡和多個IP的情況,使用時可以明確規定ServerSocket在哪塊網卡或IP地址上等待客戶的連接請求。顯然,對于一般只有一塊網卡的情況,就不用專門的指定了。
在以上介紹的構造方法中,第二個構造方法是最常使用的。了解了如何通過ServerSocket的構造方法創建對象后,接下來學習一下ServerSocket的常用方法,如下表所示:
ServerSocket對象負責監聽某臺計算機的某個端口號,在創建ServerSocket對象后,需要繼續調用該對象的accept()方法,接收來自客戶端的請求。當執行了accept()方法之后,服務器端程序會發生阻塞,直到客戶端發出連接請求時,accept()方法才會返回一個Socket對象用于和客戶端實現通信,程序才能繼續向下執行。
5.4 Socket
此類實現客戶端套接字(也可以就叫“套接字”)。套接字是兩臺機器間通信的端點。
ServerSocket對象,它可以實現服務端程序,但只實現服務器端程序還不能完成通信,此時還需要一個客戶端程序與之交互,為此JDK提供了一個Socket類,用于實現TCP客戶端程序。Socket類同樣提供了多種構造方法。
- Socket()
使用該構造方法在創建Socket對象時,并沒有指定IP地址和端口號,也就意味著只創建了客戶端對象,并沒有去連接任何服務器。通過該構造方法創建對象后還需調用connect(SocketAddress endpoint)方法,才能完成與指定服務器端的連接,其中參數endpoint用于封裝IP地址和端口號。
- Socket(String host, int port) 創建一個流套接字并將其連接到指定主機上的指定端口號
使用該構造方法在創建Socket對象時,會根據參數去連接在指定地址和端口上運行的服務器程序,其中參數host接收的是一個字符串類型的IP地址。
- Socket(InetAddress address, int port) 創建一個流套接字并將其連接到指定 IP 地址的指定端口號
該構造方法在使用上與第二個構造方法類似,參數address用于接收一個InetAddress類型的對象,該對象用于封裝一個IP地址。
Socket的常用方法
其中getInputStream()和getOutputStream()方法分別用于獲取輸入流和輸出流。當客戶端和服務端建立連接后,數據是以IO流的形式進行交互的,從而實現通信。接下來通過一張圖來描述服務器端和客戶端的數據傳輸,如下圖所示:
5.5 TCP傳輸-客戶端思路
- 建立客戶端的Socket服務,并明確要連接的服務器。
- 如果連接建立成功,就表明,已經建立了數據傳輸的通道.就可以在該通道通過IO進行數據的讀取和寫入.該通道稱為Socket流,Socket流中既有讀取流,也有寫入流.
- 通過Socket對象的方法,可以獲取這兩個流
- 通過流的對象可以對數據進行傳輸
- 如果傳輸數據完畢,關閉資源
5.6 TCP傳輸-服務器端思路
- 建立服務器端的socket服務,需要一個端口
- 服務端沒有直接流的操作,而是通過accept方法獲取客戶端對象,在通過獲取到的客戶端對象的流和客戶端進行通信
- 通過客戶端的獲取流對象的方法,讀取數據或者寫入數據
- 如果服務完成,需要關閉客戶端,然后關閉服務器,但是,一般會關閉客戶端,不會關閉服務器,因為服務端是一直提供服務的
5.7 TCP傳輸案例
客戶端鍵盤錄入,服務器輸出到控制臺
客戶端:
package cn.itcast_08;import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.Socket;/** 客戶端鍵盤錄入,服務器輸出到控制臺*/ public class ClientDemo {public static void main(String[] args) throws IOException {// 創建客戶端Socket對象Socket s = new Socket("192.168.12.92", 22222);// 鍵盤錄入數據BufferedReader br = new BufferedReader(new InputStreamReader(System.in));// 把通道內的流給包裝一下BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));String line = null;while ((line = br.readLine()) != null) {// 鍵盤錄入數據要自定義結束標記if ("886".equals(line)) {break;}bw.write(line);bw.newLine();bw.flush();}// 釋放資源// bw.close();// br.close();s.close();} }運行結果:
服務器端:
package cn.itcast_08;import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.ServerSocket; import java.net.Socket;public class ServerDemo {public static void main(String[] args) throws IOException {// 創建服務器Socket對象ServerSocket ss = new ServerSocket(22222);// 監聽客戶端連接Socket s = ss.accept();// 包裝通道內容的流BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));String line = null;while ((line = br.readLine()) != null) {System.out.println(line);}// br.close();s.close();// ss.close();} }運行結果:
5.8 上傳圖片案例
客戶端:
package cn.itcast_13;import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.net.Socket;public class UploadClient {public static void main(String[] args) throws IOException {// 創建客戶端Socket對象Socket s = new Socket("192.168.12.92", 19191);// 封裝圖片文件BufferedInputStream bis = new BufferedInputStream(new FileInputStream("林青霞.jpg"));// 封裝通道內的流BufferedOutputStream bos = new BufferedOutputStream(s.getOutputStream());byte[] bys = new byte[1024];int len = 0;while ((len = bis.read(bys)) != -1) {bos.write(bys, 0, len);bos.flush();}s.shutdownOutput();// 讀取反饋InputStream is = s.getInputStream();byte[] bys2 = new byte[1024];int len2 = is.read(bys2);String client = new String(bys2, 0, len2);System.out.println(client);// 釋放資源bis.close();s.close();} }服務器端:
package cn.itcast_13;import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket;public class UploadServer {public static void main(String[] args) throws IOException {// 創建服務器Socket對象ServerSocket ss = new ServerSocket(19191);// 監聽客戶端連接Socket s = ss.accept();// 封裝通道內流BufferedInputStream bis = new BufferedInputStream(s.getInputStream());// 封裝圖片文件BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("mn.jpg"));byte[] bys = new byte[1024];int len = 0;while ((len = bis.read(bys)) != -1) {bos.write(bys, 0, len);bos.flush();}// 給一個反饋OutputStream os = s.getOutputStream();os.write("圖片上傳成功".getBytes());bos.close();s.close();} }運行結果:
5.9 TCP傳輸容易出現的問題
- 客戶端連接上服務端,兩端都在等待,沒有任何數據傳輸
- 通過例程分析:因為read方法或者readLine方法是阻塞式
- 解決辦法:自定義結束標記,使用shutdownInput,shutdownOutput方法
6. TCP、UDP 特點對比
TCP 協議是面向連接、保證高可靠性(數據無丟失、數據無失序、數據無錯誤、數據無重復到達)傳輸層協議。UDP 協議也是傳輸層協議,它是無連接,不保證可靠的傳輸層協議。
| 面向連接 | 面向非連接 |
| 可靠的連接 | 不可靠的連接 |
| 速度慢 | 速度快 |
| 大文件、重要的數據等 | 適合小數據、不重要 |
7. TCP 三次握手過程
1、請求端(通常稱為客戶)發送一個SYN 段指明客戶打算連接的服務器的端口,以及初始序號(ISN)
2、服務器發回包含服務器的初始序號的SYN 報文段(報文段2)作為應答。同時,將確認序號設置為客戶的ISN加1 以對客戶的SYN 報文段進行確認。
3、客戶必須將確認序號設置為服務器的ISN 加1 以對服務器的SYN 報文段進行確認(報文段3)這三個報文段完成連接的建立。這個過程也稱為三次握手(three-way handshake)。
上面的過程如下圖所示:
三次握手建立連接
| URG,urgent | 緊急指針(urgent pointer)有效 |
| ACK,acknowledgement | 確認序號有效 |
| PSH,push | 接收方應該盡快將這個報文交給應用層 |
| RST,reset | 重置連接 |
| SYN,synchronous | 發起一個新連接 |
| FIN,finish | 釋放一個連接 |
所謂三次握手(Three-Way Handshake)即建立TCP連接,就是指建立一個TCP連接時,需要客戶端和服務端總共發送3個包以確認連接的建立。在socket編程中,這一過程由客戶端執行connect來觸發,整個流程如下圖所示:
首先Client端發送連接請求報文,Server端接受連接后回復ACK報文,并為這次連接分配資源。Client端接收到ACK報文后也向Server段發生ACK報文,并分配資源,這樣TCP連接就建立了
- 第一次握手:Client將標志位SYN置為1,隨機產生一個值seq=J,并將該數據包發送給Server,Client進入SYN_SENT狀態,等待Server確認。
- 第二次握手:Server收到數據包后由標志位SYN=1知道Client請求建立連接,Server將標志位SYN和ACK都置為1,ack=J+1,隨機產生一個值seq=K,并將該數據包發送給Client以確認連接請求,Server進入SYN_RCVD狀態。
- 第三次握手:Client收到確認后,檢查ack是否為J+1,ACK是否為1,如果正確則將標志位ACK置為1,ack=K+1,并將該數據包發送給Server,Server檢查ack是否為K+1,ACK是否為1,如果正確則連接建立成功,Client和Server進入ESTABLISHED狀態,完成三次握手,隨后Client與Server之間可以開始傳輸數據了。
四次握手斷開連接
客戶端和服務端總共發送4個包以確認連接的斷開,中斷連接端可以是Client端,也可以是Server端
- 第一次揮手:Client發送一個FIN,用來關閉Client到Server的數據傳送,Client進入FIN_WAIT_1狀態。
- 第二次揮手:Server收到FIN后,發送一個ACK給Client,確認序號為收到序號+1(與SYN相同,一個FIN占用一個序號),Server進入CLOSE_WAIT狀態。
- 第三次揮手:Server發送一個FIN,用來關閉Server到Client的數據傳送,Server進入LAST_ACK狀態。
- 第四次揮手:Client收到FIN后,Client進入TIME_WAIT狀態,接著發送一個ACK給Server,確認序號為收到序號+1,Server進入CLOSED狀態,完成四次揮手。
為什么連接的時候是三次握手,關閉的時候卻是四次握手?
因為當Server端收到Client端的SYN連接請求報文后,可以直接發送SYN+ACK報文。其中ACK報文是用來應答的,SYN報文是用來同步的。但是關閉連接時,當Server端收到FIN中斷連接報文時,很可能并不會立即關閉SOCKET,所以只能先回復一個ACK報文,告訴Client端,”你發的FIN報文我收到了”。只有等到我Server端所有的報文都發送完了,我才能發送FIN報文,因此不能一起發送。故需要四步握手。
8. 客戶端和服務器端原理
8.1 常見的客戶端、服務器端
最常見的客戶端:瀏覽器,IE/chrome
最常見的服務端:服務器,Tomcat
8.2 常見網絡結構
8.3 URL&URLConnection
URI:統一資源標識符
URI是統一資源標識符,是一個用于標識某一互聯網資源名稱的字符串。 該種標識允許用戶對任何(包括本地和互聯網)的資源通過特定的協議進行交互操作。URI由包括確定語法和相關協議的方案所定義。由是三個組成部分:訪問資源的命名機制、存放資源的主機名、資源自身的名稱,由路徑表示。
URL:統一資源定位符
也就是說根據URL能夠定位到網絡上的某個資源,它是指向互聯網“資源”的指針。
每個URL都是URI,但不一定每個URI都是URL。這是因為URI還包括一個子類,即統一資源名稱(URN),它命名資源但不指定如何定位資源。
URL是統一資源定位,是對可以從互聯網上得到的資源的位置和訪問方法的一種簡潔的表示,是互聯網上標準資源的地址。互聯網上的每個文件都有一個唯一的URL,它包含的信息指出文件的位置以及瀏覽器應該怎么處理它。
比如百度URL即是http://www.baidu.com。
9. TCP的三次握手/四次揮手
TCP是面向連接的運輸層協議,TCP協議提供可靠的連接服務,所以用了建立鏈接的三次握手和關閉連接的四次揮手來保證可靠服務。
通過TCP通信就像是兩個應用在打電話一樣,打電話前得先撥號建立連接,通話結束后要掛機釋放連接。
9.1 建立TCP連接的三次握手
TCP連接的三次握手分別為:
- 客戶端發送一個帶SYN標志的TCP報文到服務器,表示告訴服務器我想建立一個連接。
- 服務器收到客戶端的帶SYN標志的文后,就給客戶端回復一個帶ACK標志和帶SYN標志的報文,ACK表示回復客戶端:OK,我準備好了建立連接;然后SYN表示服務器又問客戶端:你準備好建立連接了么?
- 然后客戶端又要發送一個帶ACK標志的TCP報文,回答服務器說:我準備好了。
然后一個TCP連接就建立起來了。
SYN相當于詢問的標志,ACK相當于回復的標志。
這里有一個問題:為什么最后客戶端還要發送一次確認呢?這主要是防止已經失效了的請求報文段突然又傳到了服務器,因而產生錯誤。
“已經失效了的請求報文段”大致是這樣產生的:A發出第一個連接請求報文段并沒有丟失,在一些網絡結點上面長時間滯留,以致延誤到連接釋放以后的某個時間才到達B。本來這是一個早已失效的報文段。但B收到這個失效的報文段后,就誤以為是A發出的又一次新的連接請求,于是就向A發出確認報文段,同意建立連接,如果不采用三次握手,那么只要B發出確認后,新的連接就建立了。
9.2 釋放TCP連接的四次揮手
由于TCP是全雙工的,所以在釋放TCP連接時,要雙方都得單獨關閉。意思就是服務器和客戶端都要釋放連接。原則是某一方主動關閉時,先發一個FIN報文來表示終止這個方向的連接,收到一個FIN報文就意味著這個方向不再有數據流動,但另一個方向仍可以有數據流動,當這一個方向也發送了FIN報文后,那么這一方的連接也可以關閉了。
釋放TCP連接相對于要復雜點,具體釋放TCP連接的四次揮手流程如下:
- A發送一個FIN給B,說:我這邊要傳給你的數據已經傳完了,我要關閉連接了。A進入FIN-WAIT-1狀態,等待B確認。
- B收到了上面的FIN報文后,回復一個ACK報文說:OK。A就關閉了A->B的連接。但是此時B還能給A發送數據,A也能接收B發來的數據。(此時A收到確認后進入FIN-WAIT-2狀態。TCP處于半關閉狀態)
- 當B也發送完數據后,就給A發送一個FIN報文說:我這邊要傳給你的數據也已經傳完了,我也要關閉連接了。(B進入LAST-ACK狀態,等待A確認)
- A收到了上面的報文后,回復一個ACK報文說:OK。A進入TIME-WAIT狀態。現在TCP連接還沒有釋放掉,然后經過等待計時器(TIME-WAIT timer)設置的時間2MSL后,A才進入CLOSE狀態。
然后,當A撤銷相應的傳輸控制塊TCB后,一個TCP連接就關閉了。
10. Http、Tcp、Udp、Socket的區別
IP,網絡層協議;TCP和UDP,傳輸層協議;HTTP,應用層協議;SOCKET:TCP/IP網絡的API。
TCP/IP代表傳輸控制協議/網際協議,指的是一系列協議。
TCP和UDP使用IP協議從一個網絡傳送數據包到另一個網絡。把IP想像成一種高速公路,它允許其它協議在上面行駛并找到到其它電腦的出口。TCP和UDP是高速公路上的“卡車”,它們攜帶的貨物就是像HTTP,文件傳輸協議FTP這樣的協議等。
TCP和UDP是FTP,HTTP和SMTP之類使用的傳輸層協議。雖然TCP和UDP都是用來傳輸其他協議的,它們卻有一個顯著的不同:TCP提供有保證的數據傳輸,而UDP不提供。這意味著TCP有一個特殊的機制來確保數據安全的不出錯的從一個端點傳到另一個端點,而UDP不提供任何這樣的保證。
HTTP(超文本傳輸協議)是利用TCP在兩臺電腦(通常是Web服務器和客戶端)之間傳輸信息的協議。客戶端使用Web瀏覽器發起HTTP請求給Web服務器,Web服務器發送被請求的信息給客戶端。
記住,需要IP協議來連接網絡;TCP是一種允許我們安全傳輸數據的機制,使用TCP協議來傳輸數據的HTTP是Web服務器和客戶端使用的特殊協議。
Socket 接口是TCP/IP網絡的API,Socket接口定義了許多函數或例程,用以開發TCP/IP網絡上的應用程序。
本節原文鏈接:http://www.jianshu.com/p/1f512687ea19
11. URLConnection
public class URLDemo {public static void main(String[] args) throws MalformedURLException,IOException {String str_url = "http://192.168.1.100:8080/myweb/1.html?name=lisi";URL url = new URL(str_url);//獲取url對象的Url連接器對象。將連接封裝成了對象:// java中內置的可以解析的具體協議對象+socket。URLConnection conn = url.openConnection();System.out.println(conn);//由于URLConnection對象已經把響應頭給解析了,所以,// 可以通過URLConnection對象獲取響應頭某屬性名對應的屬性值。String value = conn.getHeaderField("Content-Type");System.out.println(value);} }運行結果
12. HttpURLConnection
URL newURL = new URL(url); URLConnection urlConnection = newURL.openConnection(); urlConnection.setConnectTimeout(mConfig.connTimeOut); urlConnection.setReadTimeout(mConfig.soTimeOut); urlConnection.setDoInput(true); urlConnection.setUseCaches(false);// HttpsURLConnection HttpsURLConnection.setDefaultSSLSocketFactory(sslFactory); HttpsURLConnection.setDefaultHostnameVerifier();HttpURLConnection常用方法
| addRequestProperty() | 添加請求屬性 |
| setRequestMethod() | 設置請求方式 |
| connect() | 連接網絡 |
| disconnect() | 斷開連接 |
| setDoOutput() | 設置打開連接對象輸出流,把要提交的數據寫入流中 |
| setDoInput() | 設置打開連接對象輸入流 |
| setConnectTimeout() | 設置連接超時 |
| setReadTimeout() | 設置讀取超時 |
| setUseCaches() | 設置是否使用緩存 |
| getResponseCode() | 獲取響應碼 |
| getOutputStream() | 獲取輸出流 |
| getInputStream() | 獲取輸入流 |
| getErrorStream() | 獲取錯誤流 |
| getResponseMessage() | 獲取響應信息 |
| getContentLength() | 獲取內容長度 |
| getContentEncoding() | 獲取內容編碼 |
| getContentType() | 獲取內容類型 |
| getHeaderFields() | 獲取所有的頭字段 |
setRequestProperty和addRequestProperty的區別
setRequestProperty和addRequestProperty的區別就是,setRequestProperty會覆蓋已經存在的key的所有values,有清零重新賦值的作用。而addRequestProperty則是在原來key的基礎上繼續添加其他value。
/*** Adds the given property to the request header. Existing properties with* the same name will not be overwritten by this method.*/public void addRequestProperty(String field, String newValue) {...}字節流轉換為字符
public class Tools {public static String getTextFromStream(InputStream is) {try {byte[] b = new byte[1024];int len;ByteArrayOutputStream bos = new ByteArrayOutputStream();while ((len = is.read(b)) != -1) {bos.write(b, 0, len);}//把輸出流里的內容轉換成字節數組String text = new String(bos.toByteArray());return text;} catch (IOException e) {e.printStackTrace();}return null;} }13. URLEncoder和URLDecoder
當使用Get請求的時候,請求參數是跟在url的后面,但是url中不能出現中文,如果參數中帶有中文,需要使用URLEncoder編碼
URLEncoder.encode(); // 編碼 URLDecoder.decode(); // 解碼總結
以上是生活随笔為你收集整理的Java基础:网络编程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android Manager
- 下一篇: java美元兑换,(Java实现) 美元