一、协议与划分层次
二、OSI参考模型
三、TCP/IP模型
四、五层协议数据传输过程
六、TCP协议:传输控制协议
传输控制协议(Transmission Control Protocol,TCP)是一种面向连接的、可靠的、基于字节流的传输层通信协议。数据大小无限制。建立连接的过程需要三次握手,断开连接的过程需要四次挥手。
三次握手
- 客户端发送请求——【在吗】
- 服务端回传确认——【在】
- 客户端回传确认——【好的】
握手过程中传送的包里不包含数据,三次握手完毕后,客户端与服务器才正式开始传送数据。
四次挥手
- 客户端发送关闭连接请求——【我要关闭连接了】
- 服务端收到后回传确认——【知道了,等我发完包着】
- 服务端发送关闭连接请求——【我也要关闭连接了】
- 客户端收到后回传确认——【好的,我知道了】
七、UDP协议:用户数据报协议
用户数据报协议(User Datagram Protocol,UDP)是一种无连接的传输层协议,提供面向事务的简单,点对点的,不可靠信息传送服务,每个包的大小64KB。
八、IP协议:互联网协议/网际协议
互联网协议/网际协议(Internet Protocol,IP)负责数据从一台机器发送到另一台机器。给互联网每台设备分配一个唯一标识(IP地址)。
- IP地址分为两种:
- IPV4: 4字节32位整数,并分成4段8位的二进制数,每8位之间用圆点隔开,每8位整数可以转换为一个0~255的十进制整数。
格式:D.D.D.D 例如:255.255.255.255 - IPV6: 16字节128位整数,并分成8段十六进制数,每16位之间用圆点隔开,每16位整数可以转换为一个0~65535的十进制数。
格式:X.X.X.X.X.X.X.X 例如:FFFF.FFFF.FFFF.FFFF.FFFF.FFFF.FFFF.FFFF
- IPV4: 4字节32位整数,并分成4段8位的二进制数,每8位之间用圆点隔开,每8位整数可以转换为一个0~255的十进制整数。
九、IPV4的应用分类
- A类:政府机构,1.0.0.1 ~ 126.255.255.254
- B类:中型企业,128.0.0.1 ~ 191.255.255.254
- C类:个人用户,192.0.0.1 ~ 223.255.255.254
- D类:用于组播,224.0.0.1 ~ 239.255.255.254
- E类:用于实验,240.0.0.1 ~ 255.255.255.254
- 回环地址:127.0.0.1,本机地址
- 测试IP命令:ping D.D.D.D
- 查看IP命令:ipconfig(windows);ifconfig(Linux)
十、Port
端口号:在通信实体上进行网络通讯程序的唯一标识。
- 端口分类:
- 公认端口:0 ~ 1023
- 注册端口:1024 ~ 49151
- 动态或私有端口:49152 ~ 65535
- 常用端口:
- MySql:3306
- Oracle:1521
- Tomcat:8080
- SMTP:25
- Web服务器:80
- FTP服务器:21
十一、InetAddress类
InetAddress类用来封装数字式的IP地址和该地址的域名。InetAddress类内部隐藏了地址数字。
静态方法:
static InetAddress[] getAllByName(String host);
// 返回给定主机名的所有 IP 地址所组成的数组static InetAddress getByName(String host);
// 返回给定主机名的 IP 地址static InetAddress getByAddress(byte[] addr);
// 在给定原始 IP 地址的情况下,返回 InetAddress 对象static InetAddress getByAddress(String host, byte[] addr);
// 根据提供的主机名和 IP 地址创建 InetAddressstatic InetAddress getLocalHost();
// 返回本地主机的 IP 地址
InetAddress[] localhosts = InetAddress.getAllByName("www.baidu.com"); //返回给定主机名的所有 IP 地址所组成的数组
for (int i = 0; i < localhosts.length; i++) {
System.out.println(localhosts[i]); //www.baidu.com/14.215.177.38 www.baidu.com/14.215.177.39
}
InetAddress byName = InetAddress.getByName("www.baidu.com"); // 返回给定主机名的 IP 地址
System.out.println(byName); //www.baidu.com/14.215.177.39
InetAddress localHost = InetAddress.getLocalHost(); //返回本地主机的 IP 地址
System.out.println(localHost); // DESKTOP-LVG3SCR/192.168.1.4
InetAddress loopbackAddress = InetAddress.getLoopbackAddress(); //返回本地的 IP 地址。
System.out.println(loopbackAddress); // localhost/127.0.0.1
非静态方法:
- boolean equals(Object other) 将此对象与指定对象比较。
- byte[ ] getAddress( ) 返回此 InetAddress 对象的原始 IP 地址。
- String getHostAddress( ) 返回 IP 地址字符串(以文本表现形式)。
- String getHostName( ) 获取此 IP 地址的主机名。
- int hashCode( ) 返回此 IP 地址的哈希码。
- boolean isMulticastAddress( ) 如果Internet地址是一个多播地址返回true;否则返回false。
- String toString( ) 将此 IP 地址转换为 String。
InetAddress byName = InetAddress.getByName("www.baidu.com"); //给定主机名的 IP 地址
System.out.println(byName); //www.baidu.com/14.215.177.39
String hostName = byName.getHostName(); // 获取此 IP 地址的主机名
System.out.println(hostName); // www.baidu.com
byte[] address = byName.getAddress(); // 返回此 InetAddress 对象的原始 IP 地址
for (byte b : address) {
System.out.print(b + " "); // 14 -41 -79 39
}
boolean multicastAddress = byName.isMulticastAddress(); // 判断Internet地址是否为一个多播地址
System.out.println(multicastAddress); // false
十二、TCP/IP套接字
- 服务器端: ServerSocket类设计成在等待客户建立连接之前不做任何事的“监听器”
- ServerSocket() 创建非绑定服务器套接字。
- ServerSocket(int port) 创建绑定到特定端口的服务器套接字。
- ServerSocket(int port, int backlog) 利用指定的 backlog 创建服务器套接字并将其绑定到指定的本地端口号。
- ServerSocket(int port, int backlog, InetAddress bindAddr) 使用指定的端口、侦听 backlog 和要绑定到的本地 IP 地址创建服务器。
- void setSoTimeout(int timeout) 通过指定超时值启用/禁用 SO_TIMEOUT,以毫秒为单位。
- Socket accept() 侦听并接受到此套接字的连接。
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
/**
* 服务端
* @Author Nigori
* @Create 2020/8/30
*/
public class ServerSocketTest {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(12101);
final Socket socket = serverSocket.accept();
InputStream inputStream = socket.getInputStream();
Thread thread = new Thread() {
OutputStream outputStream = socket.getOutputStream();
Scanner scanner = new Scanner(System.in);
@Override
public void run() {
while (true) {
try {
//服务端发送信息
System.out.print("服务端:");
outputStream.write(scanner.next().getBytes());
outputStream.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
};
thread.start();
try {
while (true) {
//服务端接受信息
byte[] bytes = new byte[1024];
int index = inputStream.read(bytes);
System.out.println("\t\t\t"+new String(bytes,0,index)+":客户端");
}
} catch (Exception e) {
e.printStackTrace();
}
inputStream.close();
socket.close();
serverSocket.close();
}
}
- 客户端: Socket类为建立连向服务器套接字以及启动协议交换而设计
- Socket(String host, int port) 创建一个流套接字并将其连接到指定主机上的指定端口号。可以 引发UnknownHostException异常或IOException异常。
- Socket(InetAddress address, int port) 创建一个流套接字并将其连接到指定 IP 地址的指定端口号。可以引发IOException异常。
- InetAddress getInetAddress() 返回套接字连接的地址。
- int getPort() 返回此套接字连接到的远程端口。
- int getLocalPort() 返回此套接字绑定到的本地端口。
- InputStream getInputStream() 返回此套接字的输入流。
- OutputStream getOutputStream() 返回此套接字的输出流。
- void close() 关闭此套接字。
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;
/**
* 客户端
* @Author Nigori
* @Create 2020/8/30
*/
public class ClientSocketTest {
public static void main(String[] args) throws IOException {
final Socket socket = new Socket("localhost",12101);
OutputStream outputStream = socket.getOutputStream();
Scanner scanner = new Scanner(System.in);
Thread thread = new Thread() {
InputStream inputStream = socket.getInputStream();
@Override
public void run() {
while (true) {
try {
//客户端接收信息
byte[] bytes = new byte[1024];
int index = inputStream.read(bytes);
System.out.println("\t\t\t"+new String(bytes,0,index)+":服务器");
} catch (IOException e) {
e.printStackTrace();
}
}
}
};
thread.start();
try {
while (true) {
//客户端发送信息
System.out.print("客户端:");
String info = scanner.next();
outputStream.write(info.getBytes());
outputStream.flush();
}
} catch (Exception e) {
e.printStackTrace();
}
outputStream.close();
socket.close();
}
}
十三、URL类
import java.net.MalformedURLException;
import java.net.URL;
/**
* @Author Nigori
* @Create 2020/8/29
*/
public class URLTest {
public static void main(String[] args) throws MalformedURLException {
URL hp = new URL("http://www.osborne.com/download");
System.out.println("Protocol: " + hp.getProtocol()); // Protocol: http 【获取此 URL 的协议名称】
System.out.println("Port: " + hp.getPort()); // Port: -1 【获取此 URL 的端口号,-1表示该端口没有被明确设置】
System.out.println("Host: " + hp.getHost()); // Host: www.osborne.com 【获取此 URL 的主机名】
System.out.println("File: " + hp.getFile()); // File: /download 【获取此 URL 的文件名】
System.out.println("Ext:" + hp.toExternalForm()); // Ext:http://www.osborne.com/download 【构造此 URL 的字符串表示形式】
}
}
十四、URLConnection类
构造方法: protected URLConnection(URL url)
构造一个到指定 url 的 URL 连接
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.Date;
/**
* @Author Nigori
* @Create 2020/8/29
*/
public class URlConllectionTest {
public static void main(String[] args) throws IOException {
int c;
URL hp = new URL("http://www.baidu.com");
URLConnection hpCon = hp.openConnection(); //返回一个 URLConnection 对象,它表示到 URL 所引用的远程对象的连接
System.out.println("Date: " + new Date(hpCon.getDate())); //返回 date 头字段的值
System.out.println("Content-Type: " + hpCon.getContentType()); //返回 content-type 头字段的值
System.out.println("Expires: " + hpCon.getExpiration()); //返回 expires 头字段的值
System.out.println("Last-Modified: " + new Date(hpCon.getLastModified())); //返回 last-modified 头字段的值
int len = hpCon.getContentLength(); //返回 content-length 头字段的值
System.out.println("Content-Length: " + len);
if (len > 0) {
System.out.println("=== Content ===");
InputStream input = hpCon.getInputStream();
int i = len;
while (((c = input.read()) != -1) && (--i > 0)) {
System.out.print((char) c);
}
input.close();
} else {
System.out.println("No Content Available");
}
}
}
运行结果:
Date: Sat Aug 29 22:40:16 CST 2020
Content-Type: text/html
Expires: 0
Last-Modified: Thu Jan 01 08:00:00 CST 1970
Content-Length: 2381
=== Content ===
<!DOCTYPE html>
<!--STATUS OK--><html> <head> ... </div> </body> </html> //【省略了一部分】
十五、DatagramPacket类
数据报包用来实现无连接包投递服务。每条报文仅根据该包中包含的信息从一台机器路由到另一台机器。从一台机器发送到另一台机器的多个包可能选择不同的路由,也可能按不同的顺序到达。
十六、DatagramSocket类
数据报套接字是包投递服务的发送或接收点。每个在数据报套接字上发送或接收的包都是单独编址和路由的。从一台机器发送到另一台机器的多个包可能选择不同的路由,也可能按不同的顺序到达。
在 DatagramSocket 上总是启用 UDP 广播发送。为了接收广播包,应该将 DatagramSocket 绑定到通配符地址。在某些实现中,将 DatagramSocket 绑定到一个更加具体的地址时广播包也可以被接收。
示例:DatagramSocket s = new DatagramSocket(null); s.bind(new InetSocketAddress(8888)); 这等价于:DatagramSocket s = new DatagramSocket(8888); 两个例子都能创建能够在 UDP 8888 端口上接收广播的 DatagramSocket。