目錄
一、網絡的相關概念
1.網絡通信
?2.網絡
3.ip 地址?
?4.ipv4 地址分類
5.域名
6.網絡通信協議
7.TCP 和 UDP?
二、InetAddress類?
1.相關方法
2.代碼示例如下:
三、Socket
1.基本介紹
四、TCP 網絡通信編程
1.基本介紹
?2.應用示例:
2.1題目一(字節流)要求如下:
2.1.1服務端代碼如下:
?2.1.2客戶端代碼如下:
2.2題目二(字節流)要求如下:
?2.2.1服務端代碼如下:
2.2.2客戶端代碼如下:
2.3題目三?(字符流)要求如下:
2.3.1服務端代碼如下:
2.3.2客戶端代碼如下:
2.4題目四(網絡上傳文件-字節流)要求如下:
2.4.1工具包StreamUtils代碼如下:
2.4.2服務端代碼如下:
2.4.3客戶端代碼如下:
五、UDP 網絡通信編程[了解]
1.基本介紹
2. 基本流程
3.應用案例
3.1要求如下:
3.2接受端代碼如下:
3.3發送端代碼如下:
一、網絡的相關概念
1.網絡通信
- 概念:兩臺設備之間通過網絡實現數據傳輸
- 網絡通信:將數據通過網絡從一臺設備傳輸到另一臺設備
- java.net包下提供了一系列的類或接口,供程序員使用,完成網絡通信
?2.網絡
- 概念:兩臺或多臺設備通過一定物理設備連接起來構成了網絡
- 根據網絡的覆蓋范圍不同,對網絡進行分類:
- 局域網:覆蓋范圍最小,僅僅覆蓋一個教室或一個機房
- 城域網:覆蓋范圍較大,可以覆蓋一個城市
- 廣域網:覆蓋范圍最大,可以覆蓋全國,甚至全球,萬維網是廣域網的代
3.ip 地址?
- 概念:用于唯一標識網絡中的每臺計算機 / 主機
- 查看 ip 地址:ipconfig
- ip 地址的表示形式:點分十進制 xx.xx.xx.xx
- 每一個十進制數的范圍:0~255
- ip 地址的組成 = 網絡地址 + 主機地址,比如:192.168.16.69
- IPv6 是互聯網工程任務組設計的用于替代 IPv4 的下一代 IP 協議,其地址數量號稱可以為全世界的每一粒沙子編上一個地址 [1] 。
- 由于 IPv4 最大的問題在于網絡地址資源有限,嚴重制約了互聯網的應用和發展。IPv6 的使用,不僅能解決網絡地址資源數量的問題,而且也解決了多種接入設備連入互聯網的障礙
?4.ipv4 地址分類
? ? ? ? ? IPv4 地址是 32 位二進制數,通常以點分十進制表示(如 192.168.1.1)。傳統分類基于第一個八位組的前綴,分為A、B、C、D、E 五類,其中 A、B、C 類為常用單播地址,D 類為組播,E 類保留。以下是詳細分類:
5.域名
- www.baidu.com
- 好處:為了方便記憶,解決記 ip 的困難
- 概念:將 ip 地址映射成域名,這里怎么映射上,HTTP 協議
?端口號
- 概念:用于標識計算機上某個特定的網絡程序
- 表示形式:以整數形式,端口范圍 0~65535 [2 個字節表示端口 0~2^16-1]
- 0~1024 已經被占用,比如 ssh 22,ftp 21,smtp 25,http 80
- 常見的網絡程序端口號:
? tomcat :8080
? mysql:3306
? oracle:1521
? sqlserver:1433
6.網絡通信協議
協議 (tcp/ip)
TCP/IP(Transmission Control Protocol/Internet Protocol)的簡寫,中文譯名為傳輸控制協議 / 因特網互聯協議,又叫網絡通訊協議,這個協議是 Internet 最基本的協議、Internet 國際互聯網絡的基礎,簡單地說,就是由網絡層的 IP 協議和傳輸層的 TCP 協議組成的。[示意圖如下:]
7.TCP 和 UDP?
- TCP 協議:傳輸控制協議
- 使用 TCP 協議前,須先建立 TCP 連接,形成傳輸數據通道
- 傳輸前,采用 “三次握手” 方式,是可靠的
- TCP 協議進行通信的兩個應用進程:客戶端、服務端
- 在連接中可進行大數據量的傳輸
- 傳輸完畢,需釋放已建立的連接,效率低
- UDP 協議:用戶數據協議
- 將數據、源、目的封裝成數據包,不需要建立連接
- 每個數據報的大小限制在 64K 內,不適合傳輸大量數據
- 因無需連接,故是不可靠的
- 發送數據結束時無需釋放資源 (因為不是面向連接的),速度快
- 舉例:廁所通知;發短信
二、InetAddress類?
1.相關方法
- 獲取本機 InetAddress 對象 getLocalHost
- 根據指定主機名 / 域名獲取 ip 地址對象 getByName
- 獲取 InetAddress 對象的主機名 getHostName
- 獲取 InetAddress 對象的地址 getHostAddress
2.代碼示例如下:
import java.net.InetAddress;
import java.net.UnknownHostException;public class API001 {public static void main(String[] args) throws UnknownHostException {//1.獲取本機InetAddress對象getLocalHostInetAddress localHost=InetAddress.getLocalHost(); //LAPTOP-BC9N4EFF/113.54.254.61System.out.println(localHost);//2.根據指定主機名/域名獲取ip地址對象getByNameInetAddress host2=InetAddress.getByName("LAPTOP-BC9N4EFF");System.out.println(host2);//3.根據域名返回InetAddress對象,比如:"www.baidu.com"InetAddress host3=InetAddress.getByName("www.baidu.com");System.out.println(host3);//4.通過InetAddress對象,獲取對應的地址String hostAddress=host3.getHostAddress();//IPSystem.out.println(hostAddress);//5.通過InetAddress對象,獲取對應的主機名/或者的域名String host3Name=host3.getHostName();System.out.println(host3Name);}
}
三、Socket
1.基本介紹
- 套接字 (Socket) 開發網絡應用程序被廣泛采用,以至于成為事實上的標準。
- 通信的兩端都要有 Socket,是兩臺機器間通信的端點
- 網絡通信其實就是 Socket 間的通信。
- Socket 允許程序把網絡連接當成一個流,數據在兩個 Socket 間通過 IO 傳輸。
- 一般主動發起通信的應用程序屬客戶端,等待通信請求的為服務端
四、TCP 網絡通信編程
1.基本介紹
- 基于客戶端 — 服務端的網絡通信
- 底層使用的是 TCP/IP 協議
- 應用場景舉例:客戶端發送數據,服務端接受并顯示控制臺
- 基于 Socket 的 TCP 編程
?
?2.應用示例:
2.1題目一(字節流)要求如下:
- 編寫一個服務器端,和一個客戶端
- 服務器端在 9999 端口監聽
- 客戶端連接到服務器端,發送 "hello, server",然后退出
- 服務器端接收到 客戶端發送的 信息,輸出,并退出
創建2個Java文件,并先運行服務端代碼(運行后不要關閉),在運行客戶端代碼。(如果條件允許,最好在兩臺電腦進行)。
2.1.1服務端代碼如下:
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;public class SocketTCP01Server01 {public static void main(String[] args) throws IOException {//思路//1.在本機的9999端口監聽,等待連接//細節:要求在本機沒有其它服務在監聽9999//細節:這個ServerSocket可以通過accept()返回多個Socket[多個客戶端連接服務器的并發]ServerSocket serverSocket=new ServerSocket(9999);System.out.println("服務端,在 9999 端口監聽,等待連接..");//2. 當沒有客戶端連接9999端口時,程序會 阻塞, 等待連接// 如果有客戶端連接,則會返回Socket對象,程序繼續Socket socket = serverSocket.accept();System.out.println("服務端 socket =" + socket.getClass());//3. 通過socket.getInputStream() 讀取客戶端寫入到數據通道的數據, 顯示InputStream inputStream = socket.getInputStream();//4. IO 讀取byte[] buf = new byte[1024];int readLen = 0;while ((readLen = inputStream.read(buf)) !=-1) {System.out.println(new String(buf, 0, readLen));//根據讀取到的實際長度,顯示內容.}//5.關閉流和socketinputStream.close();socket.close();serverSocket.close();//關閉}
}
?2.1.2客戶端代碼如下:
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;//客戶端,發送 "hello,server" 給服務端
public class SocketTCP01Client01 {public static void main(String[] args) throws IOException {//思路//1. 連接服務端 (ip, 端口)//解讀: 連接本機的 9999端口, 如果連接成功,返回Socket對象Socket socket = new Socket(InetAddress.getLocalHost(), 9999);//這里使用的是本機,如果是遠程服務器改為對應的IP或域名System.out.println("客戶端 socket 返回=" + socket.getClass());//2. 連接上后,生成Socket, 通過socket.getOutputStream()//得到 和 socket對象關聯的輸出流對象OutputStream outputStream = socket.getOutputStream();//3. 通過輸出流,寫入數據到 數據通道outputStream.write("hello, server".getBytes());//4. 關閉流對象和socket, 必須關閉outputStream.close();socket.close();System.out.println("客戶端退出.....");}
}
2.2題目二(字節流)要求如下:
- 編寫一個服務端,和一個客戶端
- 服務器端在 9999 端口監聽
- 客戶端連接到服務端,發送 "hello, server", 并接收服務器端回發的 "hello,client", 再退出
- 服務器端接收到客戶端發送的信息,輸出,并發送 "hello, client", 再退出
創建2個Java文件,并先運行服務端代碼(運行后不要關閉),在運行客戶端代碼。(如果條件允許,最好在兩臺電腦進行)。
注意:相比于上個案例,需要設置結束標記,就類似于對講機中的完畢,告訴別人我說完了?
?2.2.1服務端代碼如下:
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;public class SocketTCP01Server02 {public static void main(String[] args) throws IOException {//1.在本機的9999端口監聽,等待連接//細節:要求在本機沒有其它服務在監聽9999//細節:這個ServerSocket可以通過accept()返回多個Socket[多個客戶端連接服務器的并發]ServerSocket serverSocket=new ServerSocket(9999);System.out.println("服務端,在 9999 端口監聽,等待連接..");//2. 當沒有客戶端連接9999端口時,程序會 阻塞, 等待連接// 如果有客戶端連接,則會返回Socket對象,程序繼續Socket socket = serverSocket.accept();System.out.println("服務端 socket =" + socket.getClass());//3. 通過socket.getInputStream() 讀取客戶端寫入到數據通道的數據, 顯示InputStream inputStream = socket.getInputStream();//4. IO 讀取byte[] buf = new byte[1024];int readLen = 0;while ((readLen = inputStream.read(buf)) !=-1) {System.out.println(new String(buf, 0, readLen));//根據讀取到的實際長度,顯示內容.}System.out.println("======================源代碼增加處===========================");OutputStream outputStream = socket.getOutputStream();//5. 通過輸出流,寫入數據到 數據通道outputStream.write("hello, client".getBytes());///設置結束標記socket.shutdownOutput();//5.關閉流和socketoutputStream.close();inputStream.close();socket.close();serverSocket.close();//關閉}
}
2.2.2客戶端代碼如下:
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;public class SocketTCP01Client02 {public static void main(String[] args) throws IOException {//1. 連接服務端 (ip, 端口)//解讀: 連接本機的 9999端口, 如果連接成功,返回Socket對象Socket socket = new Socket(InetAddress.getLocalHost(), 9999);//這里使用的是本機,如果是遠程服務器改為對應的IP或域名System.out.println("客戶端 socket 返回=" + socket.getClass());//2. 連接上后,生成Socket, 通過socket.getOutputStream()//得到 和 socket對象關聯的輸出流對象OutputStream outputStream = socket.getOutputStream();//3. 通過輸出流,寫入數據到 數據通道outputStream.write("hello, server".getBytes());System.out.println("======================源代碼增加處===========================");設置結束標記socket.shutdownOutput();InputStream inputStream = socket.getInputStream();//4. IO 讀取byte[] buf = new byte[1024];int readLen = 0;while ((readLen = inputStream.read(buf)) !=-1) {System.out.println(new String(buf, 0, readLen));//根據讀取到的實際長度,顯示內容.}inputStream.close();outputStream.close();socket.close();}
}
2.3題目三?(字符流)要求如下:
- 編寫一個服務端,和一個客戶端
- 服務端在 9999 端口監聽
- 客戶端連接到服務端,發送 "hello, server", 并接收服務端回發的 "hello,client", 再退出
- 服務端接收到客戶端發送的信息,輸出,并發送 "hello, client", 再退出
提示:可以直接在上一個案例修改即可?
2.3.1服務端代碼如下:
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;public class SocketTCP01Server03 {public static void main(String[] args) throws IOException {//1.在本機的9999端口監聽,等待連接//細節:要求在本機沒有其它服務在監聽9999//細節:這個ServerSocket可以通過accept()返回多個Socket[多個客戶端連接服務器的并發]ServerSocket serverSocket=new ServerSocket(9999);System.out.println("服務端,在 9999 端口監聽,等待連接..");//2. 當沒有客戶端連接9999端口時,程序會 阻塞, 等待連接// 如果有客戶端連接,則會返回Socket對象,程序繼續Socket socket = serverSocket.accept();System.out.println("服務端 socket =" + socket.getClass());//3. 通過socket.getInputStream() 讀取客戶端寫入到數據通道的數據, 顯示InputStream inputStream = socket.getInputStream();//將字節流轉換成字符流BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));String str = bufferedReader.readLine();System.out.println(str);OutputStream outputStream = socket.getOutputStream();//字節流轉換成字符流BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));bufferedWriter.write("hello, client 字符流");bufferedWriter.newLine();//插入一個換行符,表示寫入的內容結束, 注意,要求對方使用readLine()!!!!bufferedWriter.flush(); //如果使用的字符流,需要手動刷新,否則數據不會寫入數據通道//5.關閉流和socketbufferedWriter.close();bufferedReader.close();socket.close();serverSocket.close();//關閉}
}
2.3.2客戶端代碼如下:
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;public class SocketTCP01Client03 {public static void main(String[] args) throws IOException {//1. 連接服務端 (ip, 端口)//解讀: 連接本機的 9999端口, 如果連接成功,返回Socket對象Socket socket = new Socket(InetAddress.getLocalHost(), 9999);//這里使用的是本機,如果是遠程服務器改為對應的IP或域名System.out.println("客戶端 socket 返回=" + socket.getClass());//2. 連接上后,生成Socket, 通過socket.getOutputStream()//得到 和 socket對象關聯的輸出流對象OutputStream outputStream = socket.getOutputStream();//字節流轉換成字符流BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));bufferedWriter.write("hello server 字符流");bufferedWriter.newLine();//插入一個換行符,表示寫入的內容結束, 注意,要求對方使用readLine()!!!!bufferedWriter.flush(); //如果使用的字符流,需要手動刷新,否則數據不會寫入數據通道無上一個案例的結束標記 InputStream inputStream = socket.getInputStream();//將字節流轉換成字符流BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));String str = bufferedReader.readLine();System.out.println(str);bufferedReader.close();bufferedWriter.close();socket.close();}
}
2.4題目四(網絡上傳文件-字節流)要求如下:
- 編寫一個服務端,和一個客戶端
- 服務器端在 8888 端口監聽
- 客戶端連接到服務端,發送一張圖片 e:\qie.png
- 服務器端接收到客戶端發送的圖片,保存到 src 下,發送 “收到圖片” 再退出
- 客戶端接收到服務端發送的 “收到圖片”,再退出
- 該程序要求使用 StreamUtils.java,我們直接使用
2.4.1工具包StreamUtils代碼如下:
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;/*** 此類用于演示關于流的讀寫方法**/
public class StreamUtils {/*** 功能:將輸入流轉換成byte[], 即可以把文件的內容讀入到byte[]* @param is* @return* @throws Exception*/public static byte[] streamToByteArray(InputStream is) throws Exception{ByteArrayOutputStream bos = new ByteArrayOutputStream();//創建輸出流對象byte[] b = new byte[1024];//字節數組int len;while((len=is.read(b))!=-1){//循環讀取bos.write(b, 0, len);//把讀取到的數據,寫入bos }byte[] array = bos.toByteArray();//然后將bos 轉成字節數組bos.close();return array;}/*** 功能:將InputStream轉換成String* @param is* @return* @throws Exception*/public static String streamToString(InputStream is) throws Exception{BufferedReader reader = new BufferedReader(new InputStreamReader(is));StringBuilder builder= new StringBuilder();String line;while((line=reader.readLine())!=null){builder.append(line+"\r\n");}return builder.toString();}}
2.4.2服務端代碼如下:
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;//文件上傳的服務端
public class TCPFileUploadServer001 {public static void main(String[] args) throws Exception {//1.服務端在本機監聽8888ServerSocket serverSocket = new ServerSocket(8888);System.out.println("服務端在8888端口監聽....");//2.等待連接Socket socket=serverSocket.accept();//3. 讀取客戶端發送的數據//通過Socket 得到輸入流BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());byte[] bytes = StreamUtils.streamToByteArray(bis);//4. 將得到 bytes 數組,寫入到指定的路徑,就得到一個文件了String destFilePath = "D:\\IDEA\\project\\chapter21\\Java002.png";BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destFilePath));bos.write(bytes);bos.close();// 向客戶端回復 "收到圖片"// 通過socket 獲取到輸出流(字符)BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));writer.write("收到圖片");writer.flush();//把內容刷新到數據通道socket.shutdownOutput();//設置寫入結束標記//關閉其他資源//writer.close();bis.close();socket.close();serverSocket.close();}
}
2.4.3客戶端代碼如下:
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;//文件上傳的客戶端
public class TCPFileUploadClient001 {public static void main(String[] args) throws Exception {//客戶端連接服務端 8888,得到Socket對象Socket socket = new Socket(InetAddress.getLocalHost(), 8888);//創建讀取磁盤文件的輸入流String filePath = "D:\\IDEA\\project\\chapter21\\Java.png";//String filePath = "e:\\abc.mp4";BufferedInputStream bis = new BufferedInputStream(new FileInputStream(filePath));//bytes 就是 filePath 對應的字節數組byte[] bytes = StreamUtils.streamToByteArray(bis);//通過socket 獲取到輸出流, 將bytes數據發送給服務端BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());bos.write(bytes);//將文件對應的字節數組的內容,寫入到數據通道bis.close();socket.shutdownOutput();//設置寫入數據的結束標記//=====接收從服務端回復的消息=====InputStream inputStream = socket.getInputStream();//使用StreamUtils 的方法,直接將 inputStream 讀取到的內容 轉成字符串String s = StreamUtils.streamToString(inputStream);System.out.println(s);//關閉相關的流inputStream.close();bos.close();socket.close();}
}
五、UDP 網絡通信編程[了解]
1.基本介紹
- 類 DatagramSocket 和 DatagramPacket [數據包 / 數據報] 實現了基于 UDP 協議網絡程序。
- UDP 數據報通過數據報套接字 DatagramSocket 發送和接收,系統不保證 UDP 數據報一定能夠安全送到目的地,也不能確定什么時候可以抵達。
- DatagramPacket 對象封裝了 UDP 數據報,在數據報中包含了發送端的 IP 地址和端口號以及接收端的 IP 地址和端口號。
- UDP 協議中每個數據報都給出了完整的地址信息,因此無須建立發送方和接收方的連接
2. 基本流程
- 核心的兩個類 / 對象 DatagramSocket 與 DatagramPacket
- 建立發送端,接收端 (沒有服務端和客戶端概念)
- 發送數據前,建立數據包 / 報 DatagramPacket 對象
- 調用 DatagramSocket 的發送、接收方法
- 關閉 DatagramSocket
3.應用案例
3.1要求如下:
- 編寫一個接收端 A, 和一個發送端 B
- 接收端 A 在 9999 端口等待接收數據 (receive)
- 發送端 B 向接收端 A 發送 數據 "hello,明天吃火鍋~"
- 接收端 A 接收到 發送端 B 發送的數據, 回復 "好的,明天見", 再退出
- 發送端接收 回復的數據,再退出
3.2接受端代碼如下:
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;public class UDPReceiverA {public static void main(String[] args) throws IOException {//1. 創建一個 DatagramSocket 對象,準備在9999接收數據DatagramSocket socket = new DatagramSocket(9999);//UDP 協議數據包最大 64k//2. 構建一個 DatagramPacket 對象,準備接收數據byte[] buf = new byte[1024];// 在前面講解UDP 協議時,老師說過一個數據包最大 64kDatagramPacket packet = new DatagramPacket(buf, buf.length);//3. 調用 接收方法, 將通過網絡傳輸的 DatagramPacket 對象// 填充到 packet對象// 當有數據包發送到 本機的9999端口時,就會接收到數據//如果沒有數據包發送到 本機的9999端口, 就會阻塞等待.System.out.println("接收端 A 等待接收數據..");socket.receive(packet);//4. 可以把packet 進行拆包,取出數據,并顯示.int length = packet.getLength();//實際接收到的數據字節長度byte[] data = packet.getData();//接收到數據String s = new String(data, 0, length);System.out.println(s);///==========回復代碼====================//2. 將需要發送的數據,封裝到 DatagramPacket對象byte[] data1 = "好的,明天見".getBytes();//說明: 封裝的 DatagramPacket 對象 data 內容字節數組 ,data.length , 主機(IP), 端口DatagramPacket packet1 = new DatagramPacket(data1, data1.length, InetAddress.getByName("113.54.254.61"), 9998);socket.send(packet1);socket.close();System.out.println("A端退出");}
}
3.3發送端代碼如下:
import java.io.IOException;
import java.net.*;public class UDPSenderB {public static void main(String[] args) throws IOException {//1.創建 DatagramSocket 對象,準備在9998端口 接收數據DatagramSocket socket = new DatagramSocket(9998); //端口不一樣是要理解沒有連接的概念,每次通過端口來接收數據//2. 將需要發送的數據,封裝到 DatagramPacket對象byte[] data = "hello 明天吃火鍋~".getBytes();//說明: 封裝的 DatagramPacket 對象 data 內容字節數組 ,data.length , 主機(IP), 端口DatagramPacket packet = new DatagramPacket(data, data.length, InetAddress.getByName("113.54.254.61"), 9999);socket.send(packet);==============收到回復======================//UDP 協議數據包最大 64k//2. 構建一個 DatagramPacket 對象,準備接收數據byte[] buf = new byte[1024];// 在前面講解UDP 協議時,老師說過一個數據包最大 64kDatagramPacket packet1 = new DatagramPacket(buf, buf.length);//3. 調用 接收方法, 將通過網絡傳輸的 DatagramPacket 對象// 填充到 packet對象// 當有數據包發送到 本機的9999端口時,就會接收到數據//如果沒有數據包發送到 本機的9999端口, 就會阻塞等待.System.out.println("接收端 B等待回復..");socket.receive(packet1);//4. 可以把packet 進行拆包,取出數據,并顯示.int length = packet1.getLength();//實際接收到的數據字節長度byte[] data1 = packet1.getData();//接收到數據String s = new String(data1, 0, length);System.out.println(s);//關閉資源socket.close();System.out.println("B端退出");}
}