網絡編程入門
計算機網絡
是指將地理位置不同的具有獨立功能的多臺計算機及其外部設備,通過通信線路連接起來,在網絡操作系 統,網絡管理軟件及網絡通信協議的管理和協調下,實現資源共享和信息傳遞的計算機系統
網絡編程
在網絡通信協議下,實現網絡互連的不同計算機上運行的程序間可以進行數據交換
網絡編程三要素
IP地址
- 要想讓網絡中的計算機能夠互相通信,必須爲每臺計算機指定一個標識號,通過這個標識號來指定要接收數 據的計算機和識別發送的計算機,而IP地址就是這個標識號。也就是設備的標識
IP地址詳解
- IP地址:指互聯網協議地址(Internet Protocol Address),俗稱IP。IP地址用來給一個網絡中的計算機設 備做唯一的編號。假如我們把“個人電腦”比作“一臺電話”的話,那麼“IP地址”就相當於“電話號碼”。
IP地址分類
- IPv4:是一個32位的二進制數,通常被分爲4個字節,表示成 a.b.c.d 的形式,例如 192.168.65.100 。其 中a、b、c、d都是0~255之間的十進制整數,那麼最多可以表示42億個。
- IPv6:由於互聯網的蓬勃發展,IP地址的需求量愈來愈大,但是網絡地址資源有限,使得IP的分配越發緊張。 有資料顯示,全球IPv4地址在2011年2月分配完畢。 爲了擴大地址空間,擬通過IPv6重新定義地址空間,採用128位地址長度,每16個字節一組,分成8組十六進 制數,表示成 ABCD:EF01:2345:6789:ABCD:EF01:2345:6789 ,號稱可以爲全世界的每一粒沙子編上一個網址,這樣就解決了網絡地址資源數量不夠的問題。
常用命令
- 查看本機IP地址,在控制檯輸入:ipconfig
- 檢查網絡是否連通,在控制檯輸入:ping 空格 IP地址
特殊的IP地址
- 本機IP地址: 127.0.0.1 、 localhost
端口
- 網絡的通信,本質上是兩個進程(應用程序)的通信。每臺計算機都有很多的進程,那麼在網絡通信時,如何區分 這些進程呢? 如果說IP地址可以唯一標識網絡中的設備,那麼端口號就可以唯一標識設備中的進程(應用程序)了。
- 端口號:用兩個字節表示的整數,它的取值範圍是0~65535。其中,0~1023之間的端口號用於一些知名的網絡服務和應用,普通的應用程序需要使用1024以上的端口號。如果端口號被另外一個服務或應用所佔用,會 導致當前程序啓動失敗。
協議
- 通過計算機網絡可以使多臺計算機實現連接,位於同一個網絡中的計算機在進行連接和通信時需要遵守一定 的規則,這就好比在道路中行駛的汽車一定要遵守交通規則一樣。在計算機網絡中,這些連接和通信的規則 被稱爲網絡通信協議,它對數據的傳輸格式、傳輸速率、傳輸步驟等做了統一規定,通信雙方必須同時遵守 才能完成數據交換。常見的協議有UDP協議和TCP協議
UDP協議詳解
- 用戶數據報協議(User Datagram Protocol)
- UDP是無連接通信協議,即在數據傳輸時,數據的發送端和接收端不建立邏輯連接。簡單來說,當一臺 計算機向另外一臺計算機發送數據時,發送端不會確認接收端是否存在,就會發出數據,同樣接收端在 收到數據時,也不會向發送端反饋是否收到數據。
- 由於使用UDP協議消耗資源小,通信效率高,所以通常都會用於音頻、視頻和普通數據的傳輸
- 例如視頻會議通常採用UDP協議,因爲這種情況即使偶爾丟失一兩個數據包,也不會對接收結果產生太 大影響。但是在使用UDP協議傳送數據時,由於UDP的面向無連接性,不能保證數據的完整性,因此在 傳輸重要數據時不建議使用UDP協議
TCP協議詳解
TCP協議是面向連接的通信協議,即傳輸數據之前,在發送端和接收端建立邏輯連接,然後再傳輸數據,它提供了兩臺計算機之間可靠無差錯的數據傳輸。在TCP連接中必須要明確客戶端與服務器端,由 客戶端向服務端發出連接請求,每次連接的創建都需要經過“三次握手”。三次握手:TCP協議中,在發送數據的準備階段,客戶端與服務器之間的三次交互,以保證連接的可靠
- 第一次握手,客戶端向服務器端發出連接請求,等待服務器確認
- 第二次握手,服務器端向客戶端回送一個響應,通知客戶端收到了連接請求
- 第三次握手,客戶端再次向服務器端發送確認信息,確認連接
InetAdress類
此類表示Internet協議(IP)地址 InetAddress類沒有提供公共的構造器,而是提供瞭如下幾個靜態方法來獲取 InetAddress實例
- public static InetAddress getLocalHost()
- public static InetAddress getByName(String host)
InetAddress提供瞭如下幾個常用的方法
- public String getHostAddress():返回 IP 地址字符串(以文本表現形式)。
- public String getHostName():獲取此 IP 地址的主機名
- public boolean isReachable(int timeout):測試是否可以達到該地址
代碼舉例
package ThreadDemo;
import java.net.InetAddress;
import java.net.UnknownHostException;
public class InetAddressDemo {
public static void main(String[] args) throws UnknownHostException {
InetAddress address = InetAddress.getByName("192.168.1.66");
//public String getHostName():獲取此IP地址的主機名
String name = address.getHostName();
//public String getHostAddress():返回文本顯示中的IP地址字符串
String ip = address.getHostAddress();
System.out.println("主機名:" + name);
System.out.println("IP地址:" + ip);
}
}
Socket
- 利用套接字(Socket)開發網絡應用程序早已被廣泛的採用,以至於成爲事實 上的標準。
- 網絡上具有唯一標識的IP地址和端口號組合在一起才能構成唯一能識別的標 識符套接字。
- 通信的兩端都要有Socket,是兩臺機器間通信的端點。
- 網絡通信其實就是Socket間的通信。
- Socket允許程序把網絡連接當成一個流,數據在兩個Socket間通過IO傳輸。
- 一般主動發起通信的應用程序屬客戶端,等待通信請求的爲服務端。
Socket分類:
- 流套接字(stream socket):使用TCP提供可依賴的字節流服務
- 數據報套接字(datagram socket):使用UDP提供“盡力而爲”的數據報服務
Socket類的常用構造器:
- public Socket(InetAddress address,int port)創建一個流套接字並將其連接到指定 IP 地址的指定端口號。
- public 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。 即不能通過此套接字的輸出流發送任何數據。
UDP網絡通信
- 類 DatagramSocket 和 DatagramPacket 實現了基於 UDP 協議網絡程序。
- UDP數據報通過數據報套接字 DatagramSocket 發送和接收,系統不保證 UDP數據報一定能夠安全送到目的地,也不能確定什麼時候可以抵達。
- DatagramPacket 對象封裝了UDP數據報,在數據報中包含了發送端的IP 地址和端口號以及接收端的IP地址和端口號。
- UDP協議中每個數據報都給出了完整的地址信息,因此無須建立發送方和 接收方的連接。如同發快遞包裹一樣。
DatagramPacket類的常用方法
- 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()返回將要發送或接收到的數據的長度。
流 程:
- DatagramSocket與DatagramPacket
- 建立發送端,接收端
- 建立數據包
- 調用Socket的發送、接收方法
- 關閉Socket
發送端與接收端是兩個獨立的運行程序
接收端,要指定監聽的端口。
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
/*
UDP接收數據的步驟
1:創建接收端的Socket對象(DatagramSocket)
2:創建一個數據包,用於接收數據
3:調用DatagramSocket對象的方法接收數據
4:解析數據包,並把數據在控制檯顯示
5:關閉接收端
*/
public class ReceiveDemo {
public static void main(String[] args) throws IOException {
//創建接收端的Socket對象(DatagramSocket)
//DatagramSocket(int port) 構造數據報套接字並將其綁定到本地主機上的指定端口
DatagramSocket ds = new DatagramSocket(10086);
//創建一個數據包,用於接收數據
//DatagramPacket(byte[] buf, int length) 構造一個 DatagramPacket用於接收長度爲 length數據包
byte[] bys = new byte[1024];
DatagramPacket dp = new DatagramPacket(bys,bys.length);
//調用DatagramSocket對象的方法接收數據
ds.receive(dp);
//解析數據包,並把數據在控制檯顯示
//byte[] getData() 返回數據緩衝區
// byte[] datas = dp.getData();
//int getLength() 返回要發送的數據的長度或接收到的數據的長度
// int len = dp.getLength();
// String dataString = new String(datas,0,len);
// System.out.println("數據是:" + dataString);
System.out.println("數據是:" + new String(dp.getData(),0,dp.getLength()));
//關閉接收端
ds.close();
}
}
發送端
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
/*
UDP發送數據:
數據來自於鍵盤錄入,直到輸入的數據是886,發送數據結束
*/
public class SendDemo {
public static void main(String[] args) throws IOException {
//創建發送端的Socket對象(DatagramSocket)
DatagramSocket ds = new DatagramSocket();
//自己封裝鍵盤錄入數據
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String line;
while ((line = br.readLine()) != null) {
//輸入的數據是886,發送數據結束
if ("886".equals(line)) {
break;
}
//創建數據,並把數據打包
byte[] bys = line.getBytes();
DatagramPacket dp = new DatagramPacket(bys, bys.length, InetAddress.getByName("192.168.1.66"), 12345);
//調用DatagramSocket對象的方法發送數據
ds.send(dp);
}
//關閉發送端
ds.close();
}
}
TCP網絡編程
- 創建 Socket:根據指定服務端的 IP 地址或端口號構造 Socket 類對象。若服務器端 響應,則建立客戶端到服務器的通信線路。若連接失敗,會出現異常。
- 打開連接到 Socket 的輸入/出流: 使用 getInputStream()方法獲得輸入流,使用 getOutputStream()方法獲得輸出流,進行數據傳輸
- 按照一定的協議對 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發起連接。
客戶端建立socketAtClient對象的過程就是向服務器發出套接字連接請求
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
/*
TCP發送數據的步驟
1:創建客戶端的Socket對象(Socket)
2:獲取輸出流,寫數據
3:釋放資源
*/
public class ClientDemo {
public static void main(String[] args) throws IOException {
//創建客戶端的Socket對象(Socket)
//Socket(InetAddress address, int port) 創建流套接字並將其連接到指定IP地址的指定端口號
// Socket s = new Socket(InetAddress.getByName("192.168.1.66"),10000);
//Socket(String host, int port) 創建流套接字並將其連接到指定主機上的指定端口號
Socket s = new Socket("192.168.1.66",10000);
//獲取輸出流,寫數據
//OutputStream getOutputStream() 返回此套接字的輸出流
OutputStream os = s.getOutputStream();
os.write("hello,tcp,我來了".getBytes());
//釋放資源
s.close();
}
}
服務器程序的工作過程包含以下四個基本的步驟:
- 調用 ServerSocket(int port) :創建一個服務器端套接字,並綁定到指定端口上。用於監聽客戶端的請求。
- 調用 accept():監聽連接請求,如果客戶端請求連接,則接受連接,返回通信套接字對象。
- 調用 該Socket類對象的 getOutputStream() 和 getInputStream ():獲取輸出 流和輸入流,開始網絡數據的發送和接收。
- 關閉ServerSocket和Socket對象:客戶端訪問結束,關閉通信套接字。
ServerSocket 對象負責等待客戶端請求建立套接字連接,類似郵局某個窗口 中的業務員。也就是說,服務器必須事先建立一個等待客戶請求建立套接字 連接的ServerSocket對象。
所謂“接收”客戶的套接字請求,就是accept()方法會返回一個 Socket 對象
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
/*
TCP接收數據的步驟
1:創建服務器端的Socket對象(ServerSocket)
2:獲取輸入流,讀數據,並把數據顯示在控制檯
3:釋放資源
*/
public class ServerDemo {
public static void main(String[] args) throws IOException {
//創建服務器端的Socket對象(ServerSocket)
//ServerSocket(int port) 創建綁定到指定端口的服務器套接字
ServerSocket ss = new ServerSocket(10000);
//Socket accept() 偵聽要連接到此套接字並接受它
Socket s = ss.accept();
//獲取輸入流,讀數據,並把數據顯示在控制檯
InputStream is = s.getInputStream();
byte[] bys = new byte[1024];
int len = is.read(bys);
String data = new String(bys,0,len);
System.out.println("數據是:" + data);
//釋放資源
s.close();
ss.close();
}
}