JAVA学习打卡第十二天
什么是网络编程
-
在网络通信协议下,不同计算机上运行的程序,进行的数据传输
-
应用场景:即时通信、网游对战、金融证券、国际贸易、邮件等等
不管是什么场景,都是计算机跟计算机之间通过网络进行数据传输
-
Java中可以使用java.net包下的技术轻松开发出常见的网络应用程序
-
常见的软件架构:
- CS:C/S —> Client/Server —> 客户端/服务器 —> 在用户本地需要下载并安装客户端程序,在远程有一个服务器端程序
- BS:B/S —> Browser/Server —> 浏览器/服务器 —> 只需要一个浏览器,用户通过不同的网址。用户访问不同的服务器
- 两种架构的对比:
- BS架构优缺点:
- 不需要开发客户端,只需要页面+服务端
- 用户无需下载,打开浏览器就能使用
- 如果应用过大,用户体验受到影响
- CS架构优缺点:
- 画面可以做的非常精美,用户体验好
- 需要开发客户端,也需要开发服务端
- 用户需要下载和更新的时候太麻烦
- BS架构优缺点:
网络编程三要素
-
网络编程三要素:
-
IP:设备在网络中的地址,是唯一的标识
-
端口号:应用程序在设备中唯一的标识
-
协议:数据在网络中传输的规则,常见的协议有UDP、TCP、http、https、ftp
-
IP
-
全称:Internet Protocol,是互联网协议地址,也称IP地址。是分配给上网设备的数字标签
通俗理解:上网设备在网络中的地址,是唯一的
-
常见的IP分类为:IPv4、IPv6
-
IPv4
- 全称:Internet Protocol version 4,互联网通信协议第四版
- 采用32位地址长度,分成4组
- IPv4采用点分十进制表示法
- 一共只有不到43亿个地址,不够用。2019年11月26日全部分配完毕
- IPv4的地址分类形式
- 公网地址(万维网使用)和私有地址(局域网使用)
- 192.168.开头的就是私有地址,范围即为192.168.0.0 – 192.168.255.255,专门为组织机构内部使用,以此节省IP
- 特殊IP地址:127.0.0.1,也可以是localhost,是回送地址,也称本地回环地址,也称本机IP,永远只会寻找当前所在本机
- 常用CMD命令:
- ipconfig:查看本机IP地址
- ping:检查网络是否连通
-
IPv6
-
全称:Internet Protocol version 6,互联网通信协议第六版
-
由于互联网的蓬勃发展,IP地址的需求量愈来愈大,而IPv4的模式下IP的总数是有限的
-
采用128位地址长度,分成8组
-
IPv6采用冒分十六进制表示法
如果计算出的16进制表示形式中间有多个连续的0,则用0位压缩表示法:FF01:0:0:0:0:0:0:1101 —> FF01::1101
-
-
InetAddress的使用【查看API】
import java.net.InetAddress; import java.net.UnknownHostException; public class MyInetAddressDemo_01 { public static void main(String[] args) throws UnknownHostException { /* static Ineraddress getByName(String host) 确定主机名称的IP地址。主机名可以是机器名称,也可以是IP地址 String getHostName 获取此IP地址的主机名 String getHostAddress() 返回文本显示中的IP地址字符串 */ //获取InetAddress的对象 InetAddress address = InetAddress.getByName("狝狁");//address可以看成是电脑的对象 System.out.println(address); String name = address.getHostName(); System.out.println("主机名:" + name); String ip = address.getHostAddress(); System.out.println("ip:" + ip); } }
端口号
- 应用程序在设备中唯一的标识
- 由两个字节表示的整数,取值范围:0~65535
- 其中0~1023之间的端口号用于一些知名的网络服务或者应用
- 我们自己使用1024以上的端口号就可以
- 一个端口号只能被一个应用程序使用
协议
-
计算机网络中,连接和通信的规则被称为网络通信协议
-
OSI参考模型:世界互联协议标准,全球通信规范,单模型过于理想化,未能在因特网上进行广泛推广
-
TCP/IP参考模型(或TCP/IP协议):事实上的国际标准
-
UDP协议
- 用户数据报协议(User Datagram Protocol)
- UDP是面向无连接通信协议
- 速度快,有大小限制,以此最多发送64k,数据不安全,易丢失数据
-
TCP协议
- 传输控制协议TCP(Transmission Control Protocol)
- TCP协议是面向连接的通信协议
- 速度慢,没有大小限制,数据安全
UDP通信程序
发送数据
-
创建发送端的DatagramSocket对象
-
数据打包(DatagramPacket)
-
发送数据
-
释放资源
-
示例
import java.io.IOException; import java.net.*; public class SendMessageDemo { public static void main(String[] args) throws IOException { //创建DatagramSocket对象 /* 细节: 绑定端口,以后我们就是通过这个端口往外发送 空参:所有可用的端口中随机选择一个进行使用 有参:指定端口号进行绑定 */ DatagramSocket ds = new DatagramSocket(); //打包数据 String str = "hello world"; byte[] bytes = str.getBytes(); InetAddress address = InetAddress.getByName("127.0.0.1"); int port = 10086; DatagramPacket dp = new DatagramPacket(bytes, bytes.length, address, port); //发送数据 ds.send(dp); //释放资源 ds.close(); } }
接收数据
-
创建接收端的DatagramSocket对象
-
接收打包好的数据
-
解析数据包
-
释放资源
-
示例
import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; public class ReceiveMessageDemo { public static void main(String[] args) throws IOException { // //创建DatagramSocket对象 /* 细节: 在接收的时候,一定要绑定端口 绑定的端口必须跟发送的端口保持一致 */ DatagramSocket ds = new DatagramSocket(10086); //接收数据包 byte[] bytes = new byte[1024]; DatagramPacket dp = new DatagramPacket(bytes, bytes.length); ds.receive(dp);//该方法是阻塞的,程序执行到这里时,会在这里死等,等待发送端发送消息 //解析数据包 byte[] data = dp.getData(); int length = dp.getLength(); InetAddress address = dp.getAddress(); int port = dp.getPort(); System.out.println("接收到数据" + new String(data, 0, length)); System.out.println("数据是从" + address + "这个电脑中的" + port + "端口中发出的"); //释放资源 ds.close(); } }
注意,要先运行接收端,再运行发送端
-
练习(聊天室)
- 按照以下要求实现程序:
- UPD发送数据:数据来自于键盘录入,直到输入886,发送数据结束
- UDP接收数据:因为接收端不知道发送端什么时候停止发送,故采用死循环接收
- 按照以下要求实现程序:
-
示例
import java.io.IOException; import java.net.*; import java.util.Scanner; public class SendMessage { public static void main(String[] args) throws IOException { //创建对象 DatagramSocket ds = new DatagramSocket(); //打包数据 Scanner sc = new Scanner(System.in); while (true) { System.out.println("请输入你要说的话:"); String s = sc.nextLine(); if (s.equals("886")) { break; } byte[] bt = s.getBytes(); InetAddress address = InetAddress.getByName("127.0.0.1"); int port = 10086; DatagramPacket packet = new DatagramPacket(bt, bt.length, address, port); //发送数据 ds.send(packet); } //释放资源 ds.close(); } }
import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; public class RecieveMessage { public static void main(String[] args) throws IOException { //创建对象 DatagramSocket ds = new DatagramSocket(10086); //接受数据包 byte[] bytes = new byte[1024]; DatagramPacket dp = new DatagramPacket(bytes, bytes.length); while (true) { ds.receive(dp); //解析数据包 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)); } } }
UDP三种通信方式
-
单播
-
组播:组播地址—>224.0.0.0 ~ 239.255.255.255—>其中224.0.0.0 ~ 224.0.0.255为预留的组播地址
-
广播:广播地址—>255.255.255.255
-
示例(组播)
import java.io.IOException; import java.net.*; public class SendMessageDemo { public static void main(String[] args) throws IOException { //创建对象 MulticastSocket ms = new MulticastSocket(); //打包数据 String str = "hello world"; byte[] bytes = str.getBytes(); InetAddress address = InetAddress.getByName("224.0.0.1"); int port = 10086; DatagramPacket dp = new DatagramPacket(bytes, bytes.length, address, port); //发送数据 ms.send(dp); //释放资源 ms.close(); } }
import java.io.IOException; import java.net.DatagramPacket; import java.net.InetAddress; import java.net.MulticastSocket; public class ReceiveMessageDemo_01 { public static void main(String[] args) throws IOException { //创建对象 MulticastSocket ms = new MulticastSocket(10086); //将当前本机,添加到224.0.0.1的这一组当中 InetAddress address = InetAddress.getByName("224.0.0.1"); ms.joinGroup(address); //接收数据包 byte[] bytes = new byte[1024]; DatagramPacket dp = new DatagramPacket(bytes, bytes.length); ms.receive(dp); //解析数据包 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)); //释放资源 ms.close(); } }
import java.io.IOException; import java.net.DatagramPacket; import java.net.InetAddress; import java.net.MulticastSocket; public class ReceiveMessageDemo_02 { public static void main(String[] args) throws IOException { //创建对象 MulticastSocket ms = new MulticastSocket(10086); //将当前本机,添加到224.0.0.1的这一组当中 InetAddress address = InetAddress.getByName("224.0.0.1"); ms.joinGroup(address); //接收数据包 byte[] bytes = new byte[1024]; DatagramPacket dp = new DatagramPacket(bytes, bytes.length); ms.receive(dp); //解析数据包 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)); //释放资源 ms.close(); } }
import java.io.IOException; import java.net.DatagramPacket; import java.net.InetAddress; import java.net.MulticastSocket; public class ReceiveMessageDemo_03 { public static void main(String[] args) throws IOException { //创建对象 MulticastSocket ms = new MulticastSocket(10086); //将当前本机,添加到224.0.0.1的这一组当中 InetAddress address = InetAddress.getByName("224.0.0.2"); ms.joinGroup(address); //接收数据包 byte[] bytes = new byte[1024]; DatagramPacket dp = new DatagramPacket(bytes, bytes.length); ms.receive(dp); //解析数据包 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)); //释放资源 ms.close(); } }
-
示例(广播)
只需要将单播中的发送地址改为“255.255.255.255”即可
TCP通信程序
-
TCP通信协议是一种可靠的网络协议,它在通信的两端各建立一个Socket对象
-
通信之前要保证连接已建立
-
通过Socket产生IO流来进行网络通信
-
客户端:
-
创建客户端的Socket对象(Socket)与指定服务端连接
Socket(String host, int port)
-
获取输出流,写数据
OutputStream getOutputStream()
-
释放资源
viod close
-
-
服务器
-
创建服务器端的Socket对象(ServerSocket)
ServerSocket(int port)
-
监听客户端连接,返回一个Socket对象
Socket accept()
-
获取输入流,读数据,并将数据显示在控制台
InputStream getInputStream()
-
释放资源
void close()
-
-
注意:要先启动服务端,再启动客户端
-
示例
import java.io.IOException; import java.io.OutputStream; import java.net.Socket; public class Client { public static void main(String[] args) throws IOException { //创建对象 /* 细节: 在创建对象的同时会连接服务端, 如果连接不上,代码会报错 */ Socket socket = new Socket("127.0.0.1", 10086); //可以从连接通道中,获取输出流 OutputStream os = socket.getOutputStream(); //写数据 os.write("aaa".getBytes()); //释放资源 os.close(); socket.close(); }
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 { //创建对象 ServerSocket ss = new ServerSocket(10086); //监听客户端连接 Socket socket = ss.accept(); //从连接通道中获取输入流 InputStream is = socket.getInputStream(); int b; while ((b = is.read()) != -1) { System.out.print((char) b); } //释放资源 socket.close(); ss.close(); is.close();//IO流在Socket通道内部,关闭通道时,IO流会自动关闭 } }
-
三次握手
- 作用:确保连接建立
- 过程:
- 客户端向服务器发出连接请求,等待服务器确认
- 服务器向客户端返回一个响应,告诉客户端收到了请求
- 客户端向服务器再次发出确认信息,连接建立
-
四次挥手
- 作用:确保连接断开,且数据处理完毕
- 过程:
- 客户端向服务器发出取消连接请求
- 服务器向客户端返回一个响应,表示收到客户端取消请求
- 服务器将最后的数据处理完毕,向客户端发出确认取消信息
- 客户端再次发送确认消息,连接取消