网络编程
1 定义
1.1 网络编程的基本概述
-
计算机网络:是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统,网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递的计算机系统。
-
网络编程
在网络通信协议下,实现网络互联,使得不同计算机上运行的程序间可以进行数据交换
1.2 网络编程的三要素
-
IP 地址
要想让网络中的计算机能够互相通信,必须为每台计算机指定一个标识号,通过这个标识号来指定要接收数据的计算机和识别发送的计算机,而IP地址就是这个标识号。也就是设备的标识 -
端口
网络的通信,本质上是两个应用程序的通信。每台计算机都有很多的应用程序,那么在网络通信时,如何区分这些应用程序呢?如果说IP地址可以唯一标识网络中的设备,那么端口号就可以唯一标识设备中的应用程序了。也就是应用程序的标识 -
协议
通过计算机网络可以使多台计算机实现连接,位于同一个网络中的计算机在进行连接和通信时需要遵守一定的规则,这就好比在道路中行驶的汽车一定要遵守交通规则一样。在计算机网络中,这些连接和通信的规则被称为网络通信协议,它对数据的传输格式、传输速率、传输步骤等做了统一规定,通信双方必须同时遵守才能完成数据交换。常见的协议有UDP协议和TCP协议
1.3 IP地址
是网络设备中设备的唯一标识
IP地址分为两大类:
- IPv4:是给每个连接在网络上的主机分配一个32bit地址。按照TCP/IP规定,IP地址用二进制来表示,每个IP地址长32bit,也就是4个字节。例如一个采用二进制形式的IP地址是“11000000 10101000 00000001 01000010”,这么长的地址,处理起来也太费劲了。为了方便使用,IP地址经常被写成十进制的形式,中间使用符号“.”分隔不同的字节。于是,上面的IP地址可以表示为“192.168.1.66”。IP地址的这种表示法叫做“点分十进制表示法”,这显然比1和0容易记忆得多
- IPv6:由于互联网的蓬勃发展,IP地址的需求量愈来愈大,但是网络地址资源有限,使得IP的分配越发紧张。为了扩大地址空间,通过IPv6重新定义地址空间,采用128位地址长度,每16个字节一组,分成8组十六进制数,这样就解决了网络地址资源数量不够的问题
常用命令:(win+R 运行cmd使用)
- ipconfig:查看本机IP地址
- ping IP 地址:检查网络是否连通
- ping ip地址
- ping ip地址 -t :表示持续发送ping指令
- ping www.baidu.com (域名)
- hostname:返回计算机名
特殊的IP地址:(ping 使用)
- 127.0.0.1 :回送地址,可以代表本机地址,一般用来测试使用
localhost :表示本机地址
1.4 InetAddress 类
该类表示InetAddress 协议(IP)地址
类型 | 方法 |
---|---|
static InetAddress | getByName(String host) 确定主机名称的IP地址。 |
String | getHostAddress() 返回文本显示中的IP地址字符串。 |
String | getHostName() 获取此IP地址的主机名。 |
static InetAddress | getLocalHost() 返回本地主机的地址。 |
byte[] | getAddress() 返回此 InetAddress对象的原始IP地址。 |
static InetAddress[] | getAllByName(String host) 给定主机的名称,根据系统上配置的名称服务返回其IP地址数组。 |
实例:
import java.net.InetAddress;
import java.net.UnknownHostException;
public class InetAddressDemo {
public static void main(String[] args) throws UnknownHostException {
//获取对象
//返回主机名称的IP地址
InetAddress address = InetAddress.getByName("192.168.1.4"); //此处为计算机IP地址或计算机名称
//返回文本显示的IP地址字符串
String ip1 = address.getHostAddress();
System.out.println("主机名称的IP地址:" + ip1);
//返回此IP地址的主机名
String name = address.getHostName();
System.out.println("主机名称:" + name);
//返回此InetSddress对象的原始IP地址
byte[] ip2 = address.getAddress();
for (byte b : ip2) {
System.out.print(b + " ");
}
System.out.println();
//返回IP地址数组
InetAddress[] inetAddress = InetAddress.getAllByName("192.168.1.4");
for (InetAddress i : inetAddress){
System.out.println(i);
}
}
}
1.5 端口
端口:设备上应用程序的唯一标识
端口号:用两个字节表示的整数,它的取值范围是0~ 65535。其中,0~1023之间的端口号用于一些知名的网络服务和应用,普通的应用程序需要使用1024以上的端口号。如果端口号被另外一个服务或应用所占用,会导致当前程序启动失败
1.6 协议
1.6.1 概念
-
协议:计算机网络中,连接和通信的规则被称为网络通信协议。
-
UDP 协议
- 用户数据报协议(User Datagram Protocol)
- UDP是无连接通信协议,即在数据传输时,数据的发送端和接收端不建立逻辑连接。简单来说,当一台计算机向另外一台计算机发送数据时,发送端不会确认接收端是否存在,就会发出数据,同样接收端在收到数据时,也不会向发送端反馈是否收到数据。
- 由于使用UDP协议消耗资源小,通信效率高,所以通常都会用于音频、视频和普通数据的传输
- 例如视频会议通常采用UDP协议,因为这种情况即使偶尔丢失一两个数据包,也不会对接收结果产生太大影响。但是在使用UDP协议传送数据时,由于UDP的面向无连接性,不能保证数据的完整性,因此在传输重要数据时不建议使用UDP协议
-
TCP 协议
- 传输控制协议 (Transmission Control Protocol)
- TCP协议是面向连接的通信协议,即传输数据之前,在发送端和接收端建立逻辑连接,然后再传输数据,它提供了两台计算机之间可靠无差错的数据传输。在TCP连接中必须要明确客户端与服务器端,由客户端向服务端发出连接请求,每次连接的创建都需要经过“三次握手”
- 三次握手:TCP 协议中,在发送数据的准备阶段,客户端与服务器之间的三次交互,以保证连接的可靠
- 第一次握手,客户端向服务器端发出连接请求,等待服务器确认
- 第二次握手,服务器端向客户端会送一个响应,通知客户端收到了连接请求
- 第三次握手,客户端再次向服务器端发送确认信息,确认连接
- 完成三次握手,连接建立后,客户端和服务器就可以开始进行数据传输了。由于这种面向连接的特性,TCP协议可以保证传输数据的安全,所以应用十分广泛。例如上传文件、下载文件、浏览网页等
序列号seq:占4个字节,用来标记数据段的顺序,TCP把连接中发送的所有数据字节都编上一个序号,第一个字节的编号由本地随机产生;给字节编上序号后,就给每一个报文段指派一个序号;序列号seq就是这个报文段中的第一个字节的数据编号。
确认号ack:占4个字节,期待收到对方下一个报文段的第一个数据字节的序号;序列号表示报文段携带数据的第一个字节的编号;而确认号指的是期望接收到下一个字节的编号;因此当前报文段最后一个字节的编号+1即为确认号。
确认ACK:占1位,仅当ACK=1时,确认号字段才有效。ACK=0时,确认号无效
同步SYN:连接建立时用于同步序号。当SYN=1,ACK=0时表示:这是一个连接请求报文段。若同意连接,则在响应报文段中使得SYN=1,ACK=1。因此,SYN=1表示这是一个连接请求,或连接接受报文。SYN这个标志位只有在TCP建产连接时才会被置1,握手完成后SYN标志位被置0。
1.6.2 UDP 通信
Socket 网络套接字 该类实现客户端套接字(也称为“套接字”)。 套接字是两台机器之间通讯的端点。
Java中的UDP 通信:
- UDP协议是一种不可靠的网络协议,它在通信的两端各建立一个Socket对象,但是这两个Socket只是发送、接收数据的对象。
- DatagramSocket 此类表示用于发送和接收数据报数据包的套接字。
方法名 | 说明 |
---|---|
DatagramSocket() | 构造数据报套接字并将其绑定到本地主机上的任何可用端口。 |
DatagramSocket(int port) | 构造数据报套接字并将其绑定到本地主机上的指定端口。 |
DatagramSocket(int port, InetAddress laddr) | 创建一个数据报套接字,绑定到指定的本地地址。 |
- DatagramPacket 该类表示数据报包。
方法名 | 说明 |
---|---|
DatagramPacket(byte[] buf, int length) | 构造一个 DatagramPacket用于接收长度的数据包 length 。 |
DatagramPacket(byte[] buf, int length, InetAddress address, int port) | 构造用于发送长度的分组的数据报包 length指定主机上到指定的端口号。 |
DatagramPacket(byte[] buf, int offset, int length) | 构造一个 DatagramPacket用于接收长度的分组 length ,指定偏移到缓冲器中。 |
返回值类型 | 方法 |
---|---|
byte[] | getData() 返回数据缓冲区。 |
int | getLength() 返回要发送的数据的长度或接收到的数据的长度。 |
实例:
- 实现发送数据
- 创建Socket对象 DatagramSocket
- 打包数据 DatagramSorket
- 调用DatagramSocket 的sent 方法发送数据(DatagramPacket)
- 关闭套接字,结束数据的发送
实现:
import java.io.IOException;
import java.net.*;
//UDP通信的使用
public class SentData {
public static void main(String[] args) throws IOException {
DatagramSocket sendSocket = new DatagramSocket();
byte[] b = "你好 world".getBytes();
// 数据打包 DatagramPacket(byte[] buf, int length, InetAddress address, int port)
DatagramPacket dp = new DatagramPacket(b,b.length, InetAddress.getByName("DESKTOP-IFB7SN5"),10086);
//发送数据
sendSocket.send(dp);
sendSocket.close(); //关闭发送端
}
}
接收端:
- 创建DatagramSocket对象 DatagramSocket(int port)
构造数据报套接字并将其绑定到本地主机上的指定端口。 - 调用DatagramSocket的recive方法 接收数据报包(DatagramPacket )
- 解析数据报包
- 关闭接收端
实现:
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class reciveData{
public static void main(String[] args) throws IOException {
//建立Socket对象
DatagramSocket reciveSocket = new DatagramSocket(10086);
//接收数据(使得接收端一直处于开启状态)
while (true){
byte[] buf = new byte[1024];
DatagramPacket dp = new DatagramPacket(buf,buf.length);
reciveSocket.receive(dp);
//从接收到的数据报包中获取数据
byte[] bytes = dp.getData(); //返回数据缓冲区
//将字节数组转换为字符串
String str = new String(bytes,0,dp.getLength()); //此处为接收到的包的长度
System.out.println(str);
//接收端一般不需要关闭
}
}
}
注:
1.数据发送时,数据的目标接口必须一致
2.在指定发送数据的目的地的IP的时候,可以使用IP地址或者主机名
- 需求:发送端可以多次向接收端发送数据,并且数据是可以由我们自己手动输入的。包括发送的终止也是可以由自己控制的
- 数据可以来自于键盘录入
- 当用户输入特定的字符的时候就结束发送(exit)
实现:
发送端:
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.nio.charset.StandardCharsets;
//需求:发送端可以多次向接收端发送数据,
// 并数据是可以由我们自己手动输入的。
// 包括发送的终止也是可以由自己控制的
public class SentData {
public static void main(String[] args) throws IOException {
//创建DatagramSocket对象
DatagramSocket sendSocket = new DatagramSocket();
//封装键盘数据的录入
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String line;
while ((line = br.readLine()) != null){
//如果输入exit 就退出
if ("exit".equals(line)) {
break;
}
//把String类型转换为byte类型
byte[] bytes = line.getBytes(StandardCharsets.UTF_8);
//将byte类型的数据打包
DatagramPacket sentPacket = new DatagramPacket(bytes,bytes.length,InetAddress.getByName("127.0.0.1"),10086);
sendSocket.send(sentPacket);
System.out.println("发送端发送了数据:" + line);
}
sendSocket.close(); //关闭发送端
}
}
输出端不变
运行结果:
1.6.3 TCP 通信
-
TCP的特点:
- 面向链接: 三次握手 四次挥手
- 传输可靠
- 区分客户端和服务端
-
TCP 协议的基础客户端 Socket
方法 | 说明 |
---|---|
Socket(InetAddress address, int port) | 创建流套接字并将其连接到指定IP地址的指定端口号。 |
Socket(String host, int port) | 创建流套接字并将其连接到指定主机上的指定端口号。 |
基本方法:
返回值类型 | 方法 |
---|---|
void | close() 关闭此套接字。 |
InputStream | getInputStream() 返回此套接字的输入流。 |
OutputStream | getOutputStream() 返回此套接字的输出流。 |
- 客户端的实现:
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
//客户端
public class Client {
public static void main(String[] args) throws IOException {
//创建客户端的Socket
Socket client = new Socket(InetAddress.getByName("172.0.0.1"),10086);
//输出流
OutputStream os = client.getOutputStream();
os.write("Hello 你好,我是客户端".getBytes());
//释放资源
os.close();
client.close();
}
}
- 服务端
ServerSocket 实现了服务器套接字,服务器套接字等待通过网络进入的请求。
方法 | 说明 |
---|---|
ServerSocket() | 创建未绑定的服务器套接字。 |
ServerSocket(int port) | 创建绑定到指定端口的服务器套接字。 |
常用方法:
Socket | accept() 侦听要连接到此套接字并接受它。 |
---|
- 服务端的实现
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
//服务端
public class Server {
public static void main(String[] args) throws IOException {
//创建服务端的Socket
ServerSocket serverSocket = new ServerSocket(10010);
//接收到客户端的Socket
Socket socket = serverSocket.accept();
//解析数据
InputStream is = socket.getInputStream();
//输出数据
byte[] bytes = new byte[1024];
int len = is.read(bytes);
String str = new String(bytes,0,len);
System.out.println("接收到了客户的数据:" + str);
socket.close();
serverSocket.close();
}
}
- 练习1
需求:当客户端发送信息到服务端,服务端收到信息之后,需要给客户端回应。
客户端:
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
//客户端
public class Client {
public static void main(String[] args) throws IOException {
//创建客户端的Socket
Socket client = new Socket("192.168.1.4",10010);
//输出流
OutputStream os = client.getOutputStream();
os.write("来自客户端的数据:Hello,你好".getBytes(StandardCharsets.UTF_8));
InputStream is = client.getInputStream();
//输出反馈的数据
byte[] bytes = new byte[1024];
int len = is.read(bytes);
System.out.println("收到反馈:" + new String(bytes,0,len));
//释放资源
is.close();
os.close();
client.close();
}
}
服务端:
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
//服务端
//当客户端发送信息到服务端,服务端收到信息之后 需要给客户端回应。
public class Server {
public static void main(String[] args) throws IOException {
//创建服务端的Socket
ServerSocket serverSocket = new ServerSocket(10010);
//接收到客户端的Socket
Socket socket = serverSocket.accept();
//解析数据
InputStream is = socket.getInputStream();
//输出数据
byte[] bytes = new byte[1024];
int len = is.read(bytes);
String str = new String(bytes,0,len);
System.out.println("接收到了客户的数据:" + str);
//向客户端发送反馈数据
OutputStream os = socket.getOutputStream();
os.write("数据已收到".getBytes(StandardCharsets.UTF_8));
serverSocket.close();
}
}
运行结果:
- 练习二
需求:客户端发送的数据是由客户通过键盘持续输入,直到用户输入exit 发送数据结束
客户端:
import java.io.*;
import java.net.Socket;
//客户端
//需求:客户端发送的数据是由客户通过键盘输入,知道用户输入exit 发送数据结束
public class Client {
public static void main(String[] args) throws IOException {
//创建客户端的Socket
Socket client = new Socket("192.168.1.4",12345);
//通过键盘封装输入
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
//通过输入端向服务端写出数据
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
String line;
while ((line = br.readLine()) != null){
if ("exit".equals(line)){
break;
}
bw.write(line);
//空行
bw.newLine();
//刷新
bw.flush();
}
//释放资源
bw.close();
br.close();
client.close();
}
}
服务端:
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
//服务端
public class Server {
public static void main(String[] args) throws IOException {
//创建服务端的Socket
ServerSocket serverSocket = new ServerSocket(12345);
//accept() 侦听要连接到此套接字并接受它。
Socket server = serverSocket.accept();
//输入流,读取客户端发送来的数据
BufferedReader br = new BufferedReader(new InputStreamReader(server.getInputStream()));
//将读的数据写出来
String line;
while ((line = br.readLine()) != null){
System.out.println(line);
}
//释放资源
serverSocket.close();
}
}
运行结果:
- 练习三
需求:客户端发送的数据是由客户通过键盘输入,直到用户输入exit 发送数据结束,当服务端再接受到客户端的数据的时候 ,服务端也可以通过键盘输入给出响应。直到接受到客户端发送的 exit,则服务端停止接收数据
实现:
客户端:
import java.io.*;
import java.net.Socket;
//客户端
// 需求:客户端发送的数据是由客户通过键盘输入,
// 直到用户输入exit 发送数据结束,
// 当服务端再接受到客户端的数据的时候 ,
// 服务端也可以通过键盘输入给出响应。
// 直到接受到客户端发送的 exit,则服务端停止接收数据
public class Client {
public static void main(String[] args) throws IOException {
//创建客户端的Socket
Socket client = new Socket("192.168.1.4",12580);
//通过键盘封装输入
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
//通过输入端向服务端写出数据
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
BufferedReader serveResp = new BufferedReader(new InputStreamReader(client.getInputStream()));
String line;
while ((line = br.readLine()) != null){
bw.write(line);
//空行
bw.newLine();
//刷新
bw.flush();
//当输入exit时,先传输数据,再停止
if ("exit".equals(line)){
break;
}
String str = serveResp.readLine();
System.out.println("服务端响应数据:" + str);
}
//释放资源
bw.close();
br.close();
client.close();
}
}
服务端:
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
//服务端
public class Server {
public static void main(String[] args) throws IOException {
//创建服务端的Socket
ServerSocket serverSocket = new ServerSocket(12580);
//accept() 侦听要连接到此 套接字并接受它
Socket server = serverSocket.accept();
//输入流,读取客户端发送来的数据
BufferedReader br = new BufferedReader(new InputStreamReader(server.getInputStream()));
PrintWriter pw = new PrintWriter(server.getOutputStream());
//将读的数据写出来
String line;
Scanner sc = new Scanner(System.in);
while ((line = br.readLine()) != null){
System.out.println(line);
if ("exit".equals(line)){ //如果传来的数据为exit,则停止
break;
}
System.out.println("请做出回应:");
String resp = sc.nextLine();
pw.println(resp);
pw.flush();
}
//释放资源
serverSocket.close();
}
}
- 练习四
需求:实现客户端和服务端的文件传输
实现:
import java.io.*;
import java.net.Socket;
public class Client {
public static void main(String[] args) throws IOException {
//实现客户端和服务端的文件传输
Socket client = new Socket("192.168.1.4",12980);
//读取文件
InputStream in = new FileInputStream("work100\\Output\\奶牛.jpg");
//写文件
OutputStream out = client.getOutputStream();
byte[] bytes = new byte[1024];
int len;
while ((len = in.read(bytes)) != -1){
out.write(bytes,0,len);
}
//释放资源
in.close();
client.close();
}
}
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(12980);
Socket socket = server.accept();
//创建输入输出流
InputStream is = socket.getInputStream();
OutputStream os = new FileOutputStream("work100\\Output\\奶牛_副本.jpg");
byte[] bytes = new byte[1024];
int len;
while ((len = is.read()) != -1){
os.write(bytes,0,len);
}
//释放资源
os.close();
server.close();
}
}
- 练习五
需求:一个服务端对多个客户端提供服务,此时的服务端将面临的 高并发问题,解决高并发,则必然需要使用多线程,因此此时的服务端必须是多线程的。
import java.io.*;
import java.net.Socket;
public class Client {
public static void main(String[] args) throws IOException {
Socket client = new Socket("192.168.1.4",10086);
//封装键盘输入
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
//使用输出流向服务端写出数据
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
BufferedReader serverResp = new BufferedReader(new InputStreamReader(client.getInputStream()));
//将数据写出到服务端
String line;
while ((line = br.readLine()) != null){
bw.write(line);
bw.newLine();
bw.flush();
if ("exit".equals(line)){
break;
}
String str = serverResp.readLine();
System.out.println("服务器响应数据:" + str);
}
//释放资源
client.close();
}
}
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(10086);
while (true){
Socket socket = serverSocket.accept();
new Thread(new ServerThread(socket)).start();
}
}
}
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;
public class ServerThread implements Runnable{
private Socket socket;
public ServerThread(Socket socket){
this.socket = socket;
}
@Override
public void run() {
try {
//输入流,读取客户端发送来的数据
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter pw = new PrintWriter(socket.getOutputStream());
String line;
Scanner sc = new Scanner(System.in);
while ((line = br.readLine()) != null){
System.out.println(line);
if ("exit".equals(line)){
break;
}
System.out.println("请做出回应:");
String resp = sc.nextLine();
pw.println(Thread.currentThread().getName() + " " + resp);
pw.flush();
}
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
1.6.4 UDP 与 TCP 的区别
-
UDP的特点如下:
- 无链接
- UDP使用尽最大努力交付,不保证可靠性
- UDP是面向报文的,UDP对应用层交付下来的报文,既不合并,也不拆分,而是保留这些报文的边界。应用层交给UDP多长的报文,UDP就照样发送,即一次发送一个报文
- UDP没有拥塞控制
- UDP支持一对一、一对多、多对一和多对多的交互通信
- UDP的首部开销小,只有8字节
-
TCP的特点:
- TCP是面向连接的
- 每条TCP连接只能用于两个断点,一对—
- TCP提供可靠交付的服务∶连接传输数据、无差错、不丢失、不重复、并且按序到达
- TCP提供全双工通信
- 面向字节流。TCP根据对方给出的窗口和当前网络拥塞的程度来决定一个报文应该包含多少个字节
-
TCP如何提供可靠性的连接:
- 数据被分割成TCP认为最合适发送的数据块
- 重传机制:TCP发出一个段后,启动定时器,如果不能及时收到报文段,则重发一个报文段
- 当TCP收到一个段后,会发送一个确认
- TCP将保持它首部和数据的校验和
- TCP对收到的数据进行重新排序,保证数据的有序
- TCP会丢弃重复的数据
- TCP提供流量控制
2 网络分层
- 为了减少网络设计的复杂性,绝大多数网络采用分层设计方法。
- 所谓分层设计方法,就是按照信息的流动过程将网络的整体功能分解为一个个的功能层,不同机器上的同等功能层之间采用相同的协议,同一机器上的相邻功能层之间通过接口进行信息传递。
-
其他:
URI 代表统一资源标识符
路由器是根据网络层的信息为数据包选择路由
-
URL(Uniform Resource Locator)中文名为统一资源定位符,有时也被俗称为网页地址。表示为互联网上的资源,如网页或者FTP地址。
URL 解析:
- 协议为(protocol):http
- 主机为(host:port):www.runoob.com
- 端口号为(port): 80 ,以上URL实例并未指定端口,因为 HTTP 协议默认的端口号为 80。
- 文件路径为(path):/index.html
- 请求参数(query):language=cn
- 定位位置(fragment):j2se,定位到网页中 id 属性为 j2se 的 HTML 元素位置 。
URL 构成函数将决定作为参数的字符串是不是合法的统一资源定位器。如果合法,则初
始化包含统一资源定位器的 URL 对象,否则将产生MalformedURLException