在网络通信协议下,不同计算机上运行的程序,可以进行数据传输
只需要一个浏览器,用户通过不同的网址,客户访问不同的服务器。
例如:京东,淘宝
在用户本地需要下载并安装客户端程序,在远程有一个服务器程序。
例如:QQ
- B/S
- 不需要开发客户端,只需要页面+服务器
- 用户不需要下载,打开浏览器就能使用
- 如果应用过大,用户体验受到影响
- C/S
- 画面可以做的非常精美,用户体验好
- 需要开发客户端,也需要开发服务器
- 用户需要下载和更新的时候太麻烦
全称:Iinternet Protocol,是互联网协议地址,也称IP地址。是分配给上网设备的数字标签
IP是设备在网络中的地址,是唯一标识
是给每个连接在网络上的主机分配一个32bit地址。按照TCP/IP规定,IP地址用二进制来表示,每个IP地址长32bit,也就是4个字节。例如一个采用二进制形式的IP地址是“11000000 10101000 00000001 01000010”,这么长的地址,处理起来也太费劲了。为了方便使用,IP地址经常被写成十进制的形式,中间使用符号“.”分隔不同的字节。于是,上面的IP地址可以表示为“192.168.1.66”。IP地址的这种表示法叫做“点分十进制表示法”,这显然比1和0容易记忆得多
由于互联网的蓬勃发展,IP地址的需求量愈来愈大,但是网络地址资源有限,使得IP的分配越发紧张。为了扩大地址空间,通过IPv6重新定义地址空间,采用128位地址长度,每16个字节一组,分成8组十六进制数,这样就解决了网络地址资源数量不够的问题
?此类表示互联网(IP)地址
static InetAddress getByName(String host) | 确定主机名称的IP地址。主机名称可以是机器名称,也可以是IP地址 |
String getHostName()??? | 获取此IP地址的主机名 |
String getHostAddress() | 返回文本显示中的IP地址字符串 |
public class Demo {
public static void main(String[] args) throws UnknownHostException {
// 获取InetAddress的对象,属性可以是ip地址,也可以是机器名称
// InetAddress address= InetAddress.getByName("192.168.16.100");
InetAddress address= InetAddress.getByName("DESKTOP-LED4SES");
System.out.println(address);
// 获取此IP地址的主机名
String hostName = address.getHostName();
System.out.println(hostName);
// 返回文本显示中的IP地址字符串
String ip = address.getHostAddress();
System.out.println(ip);
}
}
应用程序在设备中唯一的标识
用两个字节表示的整数,它的取值范围是0~65535。其中,0~1023之间的端口号用于一些知名的网络服务和应用,普通的应用程序需要使用1024以上的端口号。如果端口号被另外一个服务或应用所占用,会导致当前程序启动失败。
数据在网络中传输的规则,常见的协议有UDP、TCP、http、https、ftp。
- OSI参考模型:世界互联协议标准,全球通信规范,单模型过于理想化,未能在因特网上进行广泛推荐
- TCP/IP参考模型(TCP/IP协议):事实上的国际标准
- 用户数据报协议(User Datagram Protocol)
- UDP是面向无连接通信协议,即在数据传输时,数据的发送端和接收端不建立逻辑连接。简单来说,当一台计算机向另外一台计算机发送数据时,发送端不会确认接收端是否存在,就会发出数据,同样接收端在收到数据时,也不会向发送端反馈是否收到数据。
- 由于使用UDP协议消耗系统资源小,通信效率高,所以通常都会用于音频、视频和普通数据的传输
- 有大小限制,一次最多发送64KB,数据不安全,易丢失数据
- 传输控制协议 (Transmission Control Protocol)
- TCP协议是面向连接的通信协议,即传输数据之前,在发送端和接收端建立逻辑连接,然后再传输数据,它提供了两台计算机之间可靠无差错的数据传输。在TCP连接中必须要明确客户端与服务器端,由客户端向服务端发出连接请求,每次连接的创建都需要经过“三次握手”
- 三次握手:TCP协议中,在发送数据的准备阶段,客户端与服务器之间的三次交互,以保证连接的可靠
- 第一次握手,客户端向服务器端发出连接请求,等待服务器确认
- 第二次握手,服务器端向客户端回送一个响应,通知客户端收到了连接请求
- 第三次握手,客户端再次向服务器端发送确认信息,确认连接
- 完成三次握手,连接建立后,客户端和服务器就可以开始进行数据传输了。由于这种面向连接的特性,TCP协议可以保证传输数据的安全,所以应用十分广泛。例如上传文件、下载文件、浏览网页等
UDP协议是一种不可靠的网络协议,它在通信的两端各建立一个Socket对象,但是这两个Socket只是发送,接收数据的对象,因此对于基于UDP协议的通信双方而言,没有所谓的客户端和服务器的概念
Java提供了DatagramSocket类作为基于UDP协议的Socket
- DatagramSocket():创建数据报套接字并将其绑定到本机地址上的任何可用端口 |
- DatagramPacket(byte[] buf,int len,InetAddress add,int port):创建数据包,发送长度为len的数据包到指定主机的指定端口?
- void send(DatagramPacket p):发送数据报包
- void close():关闭数据报套接字
- void receive(DatagramPacket p):从此套接字接受数据报包
- 创建发送端的Socket对象(DatagramSocket)
- 创建数据,并把数据打包
- 调用DatagramSocket对象的方法发送数据
- 关闭发送端?
public class SendMessageDemo {
public static void main(String[] args) throws IOException {
// 创建对象
// 绑定对应端口
// 空参:所有可用的端口中随机一个进行使用
// 有参:指定端口号进行绑定
DatagramSocket ds = new DatagramSocket();
// 创建数据,并把数据打包
byte[] bytes = "hello world".getBytes(StandardCharsets.UTF_8);
InetAddress address = InetAddress.getByName("127.0.0.1");
int port = 12345;
DatagramPacket dp = new DatagramPacket(bytes,bytes.length,address,port);
// 发送数据
ds.send(dp);
// 释放资源
ds.close();
}
}
- 创建接收端的Socket对象(DatagramSocket)
- 创建一个数据包,用于接收数据
- 调用DatagramSocket对象的方法接收数据
- 解析数据包,并把数据在控制台显示
- 关闭接收端
public class ReceiveMessageDemo {
public static void main(String[] args) throws IOException {
//创建接收端的Socket对象(DatagramSocket)
// 在接受数据的时候,一定要绑定端口
// 而且绑定的端口一定要跟发送的端口保持一致
DatagramSocket ds = new DatagramSocket(12345);
//创建一个数据包,用于接收数据
byte[] bytes = new byte[1024];
DatagramPacket dp = new DatagramPacket(bytes, bytes.length);
//调用DatagramSocket对象的方法接收数据
// 该方法是阻塞的
// 运行到这一步时,会等发送端发送消息
ds.receive(dp);
//解析数据包,并把数据在控制台显示
byte[] data = dp.getData();
int len = dp.getLength();
InetAddress address = dp.getAddress();
int port = dp.getPort();
System.out.println("接收到的数据:" + new String(data, 0, len));
System.out.println("address = " + address);
System.out.println("port = " + port);
//关闭接收端
ds.close();
}
}
注意:先启动接收端,再启动发送端
单播用于两个主机之间的端对端通信
上面写的代码都是单播形式,不再演示
组播用于对一组特定的主机进行通信
组播地址:224.0.0.0 ~ 239.255.255.255,其中224.0.0.0 ~ 224.0.0.255为预留的组播地址
发送端
????1.?创建发送端的Socket对象(DatagramSocket)
????2.?创建数据,并把数据打包(DatagramPacket)
????3.?调用DatagramSocket对象的方法发送数据(在单播中,这里是发给指定IP的电脑但是在组播当中,这里是发给组播地址)
????4.?释放资源
接收端
????1.?创建接收端Socket对象(MulticastSocket)
????2.?创建一个箱子,用于接收数据
????3.?把当前计算机绑定一个组播地址
????4.?将数据接收到箱子中
????5.?解析数据包,并打印数据
????6.?释放资源?
public class SendMessageDemo {
public static void main(String[] args) throws IOException {
// 1. 创建接收端Socket对象(MulticastSocket)
MulticastSocket ms = new MulticastSocket();
// 2. 创建DatagramPacket对象
String str = "hello啊";
byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
InetAddress address = InetAddress.getByName("224.0.1.0");
int port = 10000;
DatagramPacket dp = new DatagramPacket(bytes, bytes.length, address, port);
// 3. 发送数据
ms.send(dp);
// 4. 释放资源
ms.close();
}
}
public class ReceiveMessageDemo1 {
public static void main(String[] args) throws IOException {
// 1. 创建发送端的Socket对象(DatagramSocket)
MulticastSocket ms = new MulticastSocket(10000);
// 2. 将当前本机,添加到224.0.0.1这一组中
InetAddress address = InetAddress.getByName("224.0.1.0");
ms.joinGroup(address);
// 3. 创建数据包对象
byte[] bytes = new byte[1024];
DatagramPacket dp = new DatagramPacket(bytes, bytes.length);
// 4. 接收数据
ms.receive(dp);
// 5. 解析数据
byte[] data = dp.getData();
int len = dp.getLength();
String ip = dp.getAddress().getHostAddress();
String name = dp.getAddress().getHostName();
System.out.println("ip为:" + ip + ",主机名为:" + name + "的人,发送了数据:" + new String(data, 0, len));
// 6. 释放资源
ms.close();
}
}
广播用于一个主机对整个局域网上所有主机上的数据通信
广播地址:255.255.255.255
发送端
????1.?创建发送端Socket对象(DatagramSocket)
????2.?创建存储数据的箱子,将广播地址封装进去
????3.?发送数据
????4.?释放资源
接收端
????1.?创建接收端的Socket对象(DatagramSocket)
????2.?创建一个数据包,用于接收数据
????3.?调用DatagramSocket对象的方法接收数据
????4.?解析数据包,并把数据在控制台显示
????5.?关闭接收端
// 发送端
public class ClientDemo {
public static void main(String[] args) throws IOException {
// 1. 创建发送端Socket对象(DatagramSocket)
DatagramSocket ds = new DatagramSocket();
// 2. 创建存储数据的箱子,将广播地址封装进去
String s = "广播 hello";
byte[] bytes = s.getBytes();
InetAddress address = InetAddress.getByName("255.255.255.255");
int port = 10000;
DatagramPacket dp = new DatagramPacket(bytes,bytes.length,address,port);
// 3. 发送数据
ds.send(dp);
// 4. 释放资源
ds.close();
}
}
// 接收端
public class ServerDemo {
public static void main(String[] args) throws IOException {
// 1. 创建接收端的Socket对象(DatagramSocket)
DatagramSocket ds = new DatagramSocket(10000);
// 2. 创建一个数据包,用于接收数据
DatagramPacket dp = new DatagramPacket(new byte[1024],1024);
// 3. 调用DatagramSocket对象的方法接收数据
ds.receive(dp);
// 4. 解析数据包,并把数据在控制台显示
byte[] data = dp.getData();
int length = dp.getLength();
System.out.println(new String(data,0,length));
// 5. 关闭接收端
ds.close();
}
}
Java对基于TCP协议的的网络提供了良好的封装,使用Socket对象来代表两端的通信端口,并通过Socket产生IO流来进行网络通信。
Java为客户端提供了Socket类,为服务器端提供了ServerSocket类
- Socket(InetAddress address,int port):创建流套接字并将其连接到指定IP指定端口号? ? ?
- Socket(String host, int port)?:创建流套接字并将其连接到指定主机上的指定端口号?
- InputStream??getInputStream():返回此套接字的输入流?
- OutputStream getOutputStream():返回此套接字的输出流?
public class Client {
public static void main(String[] args) throws IOException {
//1. 创建客户端Socket对象
// 在创建对象的同时会连接服务端
// 如果连接不上,代码会报错
Socket socket = new Socket("localhost", 12345);
//2. 从连接通道中获取输出流
OutputStream os = socket.getOutputStream();
//3. 写出数据
os.write("hello".getBytes());
//4. 释放资源
os.close();
socket.close();
}
}
- ServletSocket(int port):创建绑定到指定端口的服务器套接字
- Socket accept():监听要连接到此的套接字并接受它?
??1.?accept方法是阻塞的,作用就是等待客户端连接
??2.?客户端创建对象并连接服务器,此时是通过三次握手协议,保证跟服务器之间的连接
??3.?针对客户端来讲,是往外写的,所以是输出流。针对服务器来讲,是往里读的,所以是输入流
??4.?read方法也是阻塞的
??5.?客户端在关流的时候,还多了一个往服务器写结束标记的动作
??6.?最后一步断开连接,通过四次挥手协议保证连接终止?
public class Server {
public static void main(String[] args) throws IOException {
//1. 创建对象ServerSocket
ServerSocket serverSocket = new ServerSocket(12345);
//2. 监听客户端的连接
Socket socket = serverSocket.accept();
//3. 从连接通道中获取输入流
InputStream is = socket.getInputStream();
//4. 读取数据
byte[] bytes = new byte[1024];
int len;
while ((len = is.read(bytes)) != -1) {
System.out.println(new String(bytes, 0, len));
}
//5. 释放资源
is.close();
socket.close();
}
}
三次握手是指在TCP/IP协议中,在建立一个TCP连接时,需要进行三次握手的过程。
- 客户端向服务器发送一个SYN(同步)包,表示请求建立连接。
- 服务器收到客户端的SYN包后,回复一个SYN+ACK(同步+确认)包,表示接受连接请求。
- 客户端收到服务器的SYN+ACK包后,再发送一个ACK(确认)包,表示确认连接。
?
四次挥手是指在TCP/IP协议中,在断开一个TCP连接时,需要进行四次挥手的过程。
- 当一个应用程序或操作系统要关闭TCP连接时,发送一个FIN包,表示不再发送数据。
- 接收方收到FIN包后,发送一个ACK包,表示收到了关闭请求。
- 接收方等待一段时间(即等待应用程序处理完所有数据),然后发送一个FIN包,表示自己也准备关闭连接。
- 发送方收到FIN包后,发送一个ACK包,表示接受关闭请求。此时连接关闭。