JAVA學(xué)習(xí)筆記06——網(wǎng)絡(luò)編程基礎(chǔ)
網(wǎng)絡(luò)相關(guān)概念
-
網(wǎng)絡(luò)通信
- 概念:兩臺(tái)設(shè)備之間通過網(wǎng)絡(luò)實(shí)現(xiàn)數(shù)據(jù)傳輸
- 網(wǎng)絡(luò)通信:將數(shù)據(jù)通過網(wǎng)絡(luò)從一臺(tái)設(shè)備傳輸?shù)搅硪慌_(tái)設(shè)備
- Java.net包下提供了一系列的類或接口,供程序員使用崇棠,完成網(wǎng)絡(luò)通信
-
網(wǎng)絡(luò):
- 概念:兩臺(tái)或多臺(tái)設(shè)備通過一定物理設(shè)備連接起來構(gòu)成了網(wǎng)絡(luò)
- 根據(jù)網(wǎng)絡(luò)的覆蓋范圍不同毡咏,對(duì)網(wǎng)絡(luò)進(jìn)行分類:
- 局域網(wǎng)
- 城域網(wǎng)
- 廣域網(wǎng)
-
ip地址:
概念:用于唯一標(biāo)識(shí)網(wǎng)絡(luò)中的每臺(tái)計(jì)算機(jī)/主機(jī)
查看ip地址:ipconfig
-
ip表示:
點(diǎn)分十進(jìn)制
對(duì)于IPv4用4個(gè)字節(jié)(32位)表示
0~255 0~255 0~255 0~255 ip地址的組成=網(wǎng)絡(luò)地址+主機(jī)地址锭吨,比如:192.168.1.1
IPv6是互聯(lián)網(wǎng)工程任務(wù)組設(shè)計(jì)的用于替代IPv4的下一代IP協(xié)議
-
IPv4地址分類:
- A類:0.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
- D類:224.0.0.0到239.255.255.255
- E類:240.0.0.0到247.255.255.255
域名和端口
域名
- 例如:www.baidu.com
- 好處:為了方便記憶离赫,解決記IP地址困難的問題
- 概念:將IP地址映射成域名事富,HTTP協(xié)議
端口號(hào)
- 概念:用于標(biāo)識(shí)計(jì)算機(jī)上某個(gè)特定的網(wǎng)絡(luò)程序
- 表示形式:以整數(shù)形式梨与,范圍0~65535
- 0~1024已經(jīng)被占用捡硅,比如ssh 22秉继,ftp 21祈噪,smtp 25,http 80
- 常見的網(wǎng)絡(luò)程序端口號(hào):
- tomcat 8080
- mysql 3306
- oracle 1521
- sqlserver:1433
網(wǎng)絡(luò)協(xié)議
協(xié)議是網(wǎng)絡(luò)編程中數(shù)據(jù)的組織形式
-
OSI模型(理論) TCP/IP模型 TCP/IP模型各層對(duì)應(yīng)協(xié)議 應(yīng)用層 應(yīng)用層 HTTP尚辑、ftp辑鲤、telnet、DNS…… 表示層 會(huì)話層 傳輸層 傳輸層(TCP) TCP杠茬、UDP…… 網(wǎng)絡(luò)層 網(wǎng)絡(luò)層(IP) IP月褥、ICMP、ARP…… 數(shù)據(jù)鏈路層 物理+數(shù)據(jù)鏈路層 Link 物理層
TCP和UDP
- TCP傳輸控制協(xié)議
- TCP/IP(Transmission Control Protocol/Internet Protocol)的簡寫澈蝙。
- 中文譯名為傳輸控制協(xié)議/因特網(wǎng)互聯(lián)協(xié)議吓坚,又叫網(wǎng)絡(luò)通訊協(xié)議,這個(gè)協(xié)議是Internet最基本的協(xié)議灯荧,簡單地說礁击,就是由網(wǎng)絡(luò)層的IP協(xié)議和傳輸層的TCP協(xié)議組成的
- 使用TCP協(xié)議前,須先建立TCP連接逗载,形成傳輸數(shù)據(jù)通道
- 傳輸前哆窿,采用”三次握手“方式,是可靠的
- TCP協(xié)議進(jìn)行通信的兩個(gè)應(yīng)用進(jìn)程:客戶端厉斟、服務(wù)端
- 在連接中可進(jìn)行大數(shù)據(jù)量的傳輸
- 傳輸完畢挚躯,需釋放已建立連接,效率低
- UDP協(xié)議
- 將數(shù)據(jù)擦秽、源码荔、目的封裝成數(shù)據(jù)包漩勤,不需要建立連接
- 每個(gè)數(shù)據(jù)包的大小限制在64K以內(nèi),不適合傳輸大量數(shù)據(jù)
- 因無需連接缩搅,所以是不可靠的
- 發(fā)送數(shù)據(jù)結(jié)束時(shí)無需釋放資源(因?yàn)椴皇敲嫦蜻B接的)越败,速度快
InetAddress類
相關(guān)方法
- 獲取本機(jī)InetAddress對(duì)象getLocalHost
- 根據(jù)指定主機(jī)名、域名獲取ip地址對(duì)象getByName
- 獲取InetAddress對(duì)象的主機(jī)名getHostName
- 獲取InetAddress對(duì)象的地址getHostAddress
import java.net.InetAddress;
import java.net.UnknownHostException;
public class API {
public static void main(String[] args) throws UnknownHostException {
// 獲取本機(jī)的InetAddress對(duì)象
InetAddress localHost = InetAddress.getLocalHost();
System.out.println(localHost);
// 根據(jù)指定主機(jī)名獲取InetAddress對(duì)象
InetAddress host1 = InetAddress.getByName("DESKTOP-CQHA3I8");
System.out.println("host1 = " + localHost);
// 根據(jù)域名返回InetAddress對(duì)象
InetAddress host2 = InetAddress.getByName("www.baidu.com");
System.out.println("host2 = " + host2);
// 通過InetAddress對(duì)象硼瓣,獲取對(duì)應(yīng)的地址
String host2Address = host2.getHostAddress();
System.out.println("host2地址:" + host2Address);
// 通過InetAddress對(duì)象究飞,獲得主機(jī)名或域名
String host2Name = host2.getHostName();
System.out.println("host2主機(jī)名/域名:" + host2Name);
}
}
Socket
- 基本介紹:
- 套接字(Socket)開發(fā)網(wǎng)絡(luò)應(yīng)用程序被廣泛采用,以至于成為事實(shí)上的標(biāo)準(zhǔn)
- 通信的兩端都要由Socket堂鲤,是兩臺(tái)機(jī)器間通信的端點(diǎn)
- 網(wǎng)絡(luò)通信其實(shí)就是Socket間的通信
- Socket允許把網(wǎng)絡(luò)連接當(dāng)成一個(gè)流亿傅,數(shù)據(jù)在兩個(gè)Socket間通過IO傳輸。
- 一般主動(dòng)發(fā)起通信的應(yīng)用程序?qū)倏蛻舳宋疗埽却ㄐ耪?qǐng)求的為服務(wù)端
- 當(dāng)我們需要通訊時(shí)(讀寫數(shù)據(jù))
- socket.getOutputStream()
- socket.getInputStream()
- Socket有TCP編程和UDP編程
TCP網(wǎng)絡(luò)通信編程
-
基本介紹
- 基于客戶端—服務(wù)端的網(wǎng)絡(luò)通信
- 底層使用的時(shí)TCP/IP協(xié)議
- 應(yīng)用場景舉例:客戶端發(fā)送數(shù)據(jù)葵擎,服務(wù)端接受并顯示
- 基于Socket的TCP編程
-
案例:
// 服務(wù)端 import java.io.IOException; import java.io.InputStream; import java.net.ServerSocket; import java.net.Socket; public class SocketServer { public static void main(String[] args) throws IOException { // 在9999接口監(jiān)聽,等待連接 ServerSocket serverSocket = new ServerSocket(9999); System.out.println("等待連接……"); // 當(dāng)沒有客戶端連接時(shí)慢宗,程序阻塞坪蚁,等待連接 Socket socket = serverSocket.accept(); System.out.println("服務(wù)端 socket = " + socket.getClass()); // 讀取客戶端寫入數(shù)據(jù)通道的數(shù)據(jù) InputStream inputStream = socket.getInputStream(); byte[] buf = new byte[1024]; int readLen = 0; while ((readLen = inputStream.read(buf)) != -1) { System.out.println(new String(buf, 0, readLen)); } // 關(guān)閉流和socket inputStream.close(); socket.close(); } }
// 客戶端 import java.io.IOException; import java.io.OutputStream; import java.net.InetAddress; import java.net.Socket; import java.nio.charset.StandardCharsets; public class SocketTCPClient { public static void main(String[] args) throws IOException { // 連接服務(wù)器,如果連接成功镜沽,返回Socket對(duì)象 Socket socket = new Socket(InetAddress.getLocalHost(),9999); System.out.println("客戶端 socket = " + socket.getClass()); // 連接上后,生成Socket,通過socket.getOutputStream()得到和Socket對(duì)象關(guān)聯(lián)的輸出流對(duì)象 OutputStream outputStream = socket.getOutputStream(); outputStream.write("hello server".getBytes(StandardCharsets.UTF_8)); socket.shutdownOutput(); // 關(guān)閉流和Socket對(duì)象贱田,必須關(guān)閉 outputStream.close(); socket.close(); System.out.println("Socket關(guān)閉"); } }
應(yīng)該設(shè)置一個(gè)結(jié)束標(biāo)記缅茉,說明結(jié)束發(fā)送數(shù)據(jù)。socket.shutdownOutput()
-
案例男摧,網(wǎng)絡(luò)上傳文件
// 服務(wù)端 import java.io.*; import java.net.ServerSocket; import java.net.Socket; public class TCPFileCopyServer { public static void main(String[] args) throws IOException { // 1.服務(wù)端在本機(jī)8888端口監(jiān)聽 ServerSocket serverSocket = new ServerSocket(8888); System.out.println("服務(wù)端在8888"); // 2.等待連接 Socket socket = serverSocket.accept(); // 3.讀取客戶端發(fā)送的數(shù)據(jù) // 通過socket得到輸入流 BufferedInputStream bufferedInputStream = new BufferedInputStream(socket.getInputStream()); ByteArrayOutputStream bos = new ByteArrayOutputStream();// 創(chuàng)建輸出流對(duì)象 byte[] b = new byte[1024];// 字節(jié)數(shù)組 int len; while ((len = bufferedInputStream.read(b)) != -1) {// 循環(huán)讀取 bos.write(b, 0, len);// 把讀取到的數(shù)據(jù)寫入bos } byte[] array = bos.toByteArray();// 然后將bos 轉(zhuǎn)成字節(jié)數(shù)組 bos.close(); BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream("C:\\Users\\46429\\Pictures\\qie233.GIF")); bufferedOutputStream.write(array); bufferedOutputStream.close(); bufferedInputStream.close(); socket.close(); serverSocket.close(); } }
// 客戶端 import java.io.*; import java.net.InetAddress; import java.net.Socket; public class TCPFileCopyClient { public static void main(String[] args) throws IOException { // 客戶端連接服務(wù)端蔬墩,得到Socket對(duì)象 Socket socket = new Socket(InetAddress.getLocalHost(), 8888); // 創(chuàng)建讀取磁盤文件的輸入流 String filePath = "C:\\Users\\46429\\Pictures\\qie.GIF"; BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(filePath)); ByteArrayOutputStream bos = new ByteArrayOutputStream();// 創(chuàng)建輸出流對(duì)象 byte[] b = new byte[1024];// 字節(jié)數(shù)組 int len; while ((len = bufferedInputStream.read(b)) != -1) {// 循環(huán)讀取 bos.write(b, 0, len);// 把讀取到的數(shù)據(jù)寫入bos } byte[] array = bos.toByteArray();// 然后將bos 轉(zhuǎn)成字節(jié)數(shù)組 bos.close(); BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(socket.getOutputStream()); bufferedOutputStream.write(array); bufferedInputStream.close(); bufferedOutputStream.close(); socket.shutdownOutput(); } }
netstat指令
netstat -an 可以查看當(dāng)前主機(jī)網(wǎng)絡(luò)情況,包括端口監(jiān)聽情況和網(wǎng)絡(luò)連接情況
netstat -an|more可以分頁顯示
要求在dos控制臺(tái)下執(zhí)行win + r
-
說明:
- Listening表示某個(gè)端口在監(jiān)聽
- 如果有一個(gè)外部程序(客戶端)連接到該端口耗拓,就會(huì)顯示一條連接信息
- 可以輸入ctrl+c退出指令
netstat -anb 查看使用端口的程序拇颅,需要使用管理員權(quán)限
TCP注意點(diǎn)
- 客戶端連接到服務(wù)器端后,實(shí)際上客戶端也是通過一個(gè)端口和服務(wù)端進(jìn)行通訊的乔询,這個(gè)端口時(shí)TCP/IP來分配的樟插,是隨機(jī)的。
UDP網(wǎng)絡(luò)編程
基本介紹
- 類DatagramSocket和DatagramPacket(數(shù)據(jù)包/數(shù)據(jù)報(bào))實(shí)現(xiàn)了基于UDP協(xié)議網(wǎng)絡(luò)程序
- UDP數(shù)據(jù)報(bào)通過數(shù)據(jù)報(bào)(數(shù)據(jù)包)套接字DatagramSocket發(fā)送和接收竿刁,系統(tǒng)不保證UDP數(shù)據(jù)報(bào)一定能夠安全送達(dá)目的地黄锤,也不能確定什么時(shí)候可以抵達(dá)。
- DatagramPacket對(duì)象封裝了UDP數(shù)據(jù)報(bào)食拜,在數(shù)據(jù)報(bào)中包含了發(fā)送端的IP地址和端口號(hào)以及接受端的IP地址和端口號(hào)
- UDP協(xié)議中每個(gè)數(shù)據(jù)報(bào)都給出了完整的地址信息鸵熟,因此無需建立發(fā)送方和接收方的連接
UDP網(wǎng)絡(luò)編程基礎(chǔ)流程
- 核心的兩個(gè)類/對(duì)象DatagramSocket與DatagramPacket
- 建立發(fā)送端,接收端
- 建立數(shù)據(jù)包
- 調(diào)用DatagramSocket的發(fā)送负甸、接受方法
- 關(guān)閉DatagramSocket
UDP說明
- 沒有明確的服務(wù)端和客戶端流强,演變成數(shù)據(jù)的發(fā)送端和接收端
- 接收數(shù)據(jù)和發(fā)送數(shù)據(jù)是通過DatagramSocket對(duì)象完成
- 將數(shù)據(jù)封裝到DatagramPacket對(duì)象/裝包
- 當(dāng)接受到DatagramPacket對(duì)象痹届,需要進(jìn)行拆包,取出數(shù)據(jù)
- DatagramSocket可以指定在哪個(gè)端口接收數(shù)據(jù)
應(yīng)用案例
- 編寫一個(gè)接收端A打月,和一個(gè)發(fā)送端B
- 接收端A在9999端口等待接受數(shù)據(jù)(receive)
- 發(fā)送端B向接收端A發(fā)送數(shù)據(jù)“hello队腐,明天吃火鍋”
- 接收端A接收到發(fā)送端B發(fā)送的數(shù)據(jù),回復(fù)“好的僵控,明天見”再退出
- 發(fā)送端接收回復(fù)的數(shù)據(jù)香到,再退出
// 接收端A
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.nio.charset.StandardCharsets;
public class UDPReceiverA {
public static void main(String[] args) throws IOException {
// 創(chuàng)建一個(gè)DatagramSocket對(duì)象,準(zhǔn)備接受數(shù)據(jù)
DatagramSocket socket = new DatagramSocket(9999);
byte[] buf = new byte[1024];// 一個(gè)數(shù)據(jù)包最大64k
DatagramPacket packet = new DatagramPacket(buf, buf.length);
// 調(diào)用接收方法
System.out.println("接收端A接受數(shù)據(jù)报破。悠就。。");
socket.receive(packet);
int length = packet.getLength();
byte[] data = packet.getData();
String s = new String(data, 0, length);
System.out.println(s);
byte[] response = "彳亍".getBytes(StandardCharsets.UTF_8);
DatagramPacket rPacket = new DatagramPacket(response, response.length, InetAddress.getByName("172.25.225.69"), 9998);
socket.send(rPacket);
// 關(guān)閉資源
socket.close();
System.out.println("A端退出");
}
}
// 發(fā)送端B
import java.io.IOException;
import java.net.*;
import java.nio.charset.StandardCharsets;
public class UDPSenderB {
public static void main(String[] args) throws IOException {
DatagramSocket socket = new DatagramSocket(9998);
// 將發(fā)送的數(shù)據(jù)封裝到packet對(duì)象
byte[] data = "明天吃火鍋3湟住9Fⅰ!".getBytes(StandardCharsets.UTF_8);
DatagramPacket packet = new DatagramPacket(data, data.length, InetAddress.getByName("172.25.225.69"), 9999);
socket.send(packet);
byte[] response = new byte[1024];
DatagramPacket rPacket = new DatagramPacket(response,response.length);
System.out.println("接收A端數(shù)據(jù)盹靴。炸茧。。");
socket.receive(rPacket);
byte[] bRe = rPacket.getData();
String re = new String(bRe, 0,rPacket.getLength());
System.out.println(re);
System.out.println("ok");
socket.close();
System.out.println("B端退出");
}
}
個(gè)人總結(jié)
- 很重要稿静,很實(shí)用
- 細(xì)節(jié)和難理解的地方較多梭冠,如果不明白一定要回頭看視頻
- https://www.bilibili.com/video/BV1fh411y7R8?p=684