网络编程
概述
网络编程是可以让设备中的程序与网络上其他设备中的程序实现数据交互的编程技术(实现网络通信的)。
Java提供了哪些网络编程的包
java.net.*包下提供了网络编程的解决方案。
基本的通信架构
基本的通信架构有2种形式:CS架构( Client客户端/Server服务端 ) 、 BS架构(Browser浏览器/Server服务端)。
Client-Server(CS)的特点
- Client客户端:需要程序员开发实现,用户需要安装客户端。
- Server服务端:需要程序员开发实现。
Browser-Server(BS)的特点
- Browser浏览器:不需要程序员开发实现,用户只需要安装浏览器。
- Server服务端:需要程序员开发实现。
总结
无论是CS架构,还是BS架构的软件都必须依赖网络编程。
网络通信三要素
IP地址
- IP(Internet Protocol):全称”互联网协议地址”,是分配给上网设备的唯一标志。
- IP地址有两种形式:IPv4、IPv6。
背景知识
IPv4
由32位二进制组成,采用点分十进制表示法,即将32位二进制分成四段,每段8位,再将每段二进制转换为十进制,并用符号“.”分隔。
11000000 10101000 00000001 01000010 → 192.168.1.66
IPv6
-
由于IPv4的数量不足为全球所有设备分配,所以就又提出了IPv6。
-
IPv6:共128位,号称可以为地球每一粒沙子编号。
-
IPv6采用冒分十六进制表示法,即分成8段表示,每段每四位编码成一个十六进制位表示, 段之间用冒号(:)分开。
0010 0000 0000 0001|0000 1101 1011 1000|0000 0000 0000 0000|0000 0000 0010 0011|
0000 0000 0000 1000|0000 1000 0000 0000|0010 0000 0000 1100|0100 0001 0111 1010
→
2001:0db8:0000:0023:0008:0800:200c:417a
IP域名
容易记忆的网址,可以自动通过DNS服务器转换成相应的IP地址。
公网IP, 内网IP
- 公网IP:是可以连接互联网的IP地址。
- 内网IP:也叫局域网IP,只能由组织机构内部使用。
- 192.168. 开头的就是常见的局域网地址,范围即为192.168.0.0--192.168.255.255,专门为组织机构内部使用。
特殊IP地址
- 127.0.0.1、localhost:代表本机IP,只会寻找当前所在的主机。
IP常用命令
- ipconfig:查看本机IP地址。
- ping IP地址:检查网络是否连通。
InetAddress
InetAddress是Java中代表IP地址的类。
InetAddress的常用方法
名称 | 说明 |
---|---|
public static InetAddress getLocalHost() | 获取本机IP,会以一个inetAddress的对象返回 |
public static InetAddress getByName(String host) | 根据ip地址或者域名,返回一个inetAdress对象 |
public String getHostName() | 获取该ip地址对象对应的主机名 |
public String getHostAddress() | 获取该ip地址对象中的ip地址信息 |
public boolean isReachable(int timeout) | 在指定毫秒内,判断主机与该ip对应的主机是否能连通 |
端口
标记正在计算机设备上运行的应用程序的,被规定为一个 16 位的二进制,范围是 0~65535。
分类
- 周知端口:0~1023,被预先定义的知名应用占用(如:HTTP占用 80,FTP占用21)
- 注册端口:1024~49151,分配给用户进程或某些应用程序。
- 动态端口:49152到65535,之所以称为动态端口,是因为它 一般不固定分配某种进程,而是动态分配。
注意:我们自己开发的程序一般选择使用注册端口,且一个设备中不能出现两个程序的端口号一样,否则会出错。
协议
网络上通信的设备,事先规定的连接规则,以及传输数据的规则被称为网络通信协议。
开放式网络互联标准:OSI网络参考模型
-
OSI网络参考模型:全球网络互联标准。
-
TCP/IP网络模型:事实上的国际标准。
传输层的2个通信协议
- UDP(User Datagram Protocol):用户数据报协议。
- TCP(Transmission Control Protocol) :传输控制协议。
UDP协议
- 特点:无连接、不可靠通信。
- 不事先建立连接,数据按照包发,一包数据包含:自己的IP、程序端口,目的地IP、程序端口和数据(限制在64KB内)等。
- 发送方不管对方是否在线,数据在中间丢失也不管,如果接收方收到数据也不返回确认,故是不可靠的 。
- 通信效率高,适合语音通话和视频直播等业务。
TCP协议
- 特点:面向连接、可靠通信。
- TCP的最终目的:要保证在不可靠的信道上实现可靠的传输。
- TCP主要有三个步骤实现可靠传输:三次握手建立可靠连接,传输数据进行确认,四次挥手断开连接。
- 在连接中可进行大数据量的传输。
- 通信效率相对不高,适合网页、文件下载和支付等业务。
三次握手建立可靠连接
可靠连接:确定通信双方,收发消息都是正常无问题的!(全双工)
三次握手的步骤:
- 客户端发出连接请求。(说明客户端能正常发数据)
- 服务器端返回一个响应。(说明服务器端能正常收、发数据)
- 客户端再次发出确认信息,连接建立。(说明客户端能正常收数据)
传输数据进行确认
传输数据会进行确认(确认消息以及重传),以保证数据传输的可靠性。
四次挥手断开连接
目的:确保双方数据的收发都已经完成。
四次挥手的步骤:
- 客户端发出断开连接请求。(说明客户端数据发送已完成)
- 服务器端返回一个响应:稍等。(等待服务器端数据接收完成)
- 服务器将最后的数据处理完毕后,返回一个响应:确认断开。(说明服务器端数据发送和接收都已完成)
- 客户端发出正式确认并断开连接。(说明客户端数据接收已完成)
UDP通信-单次收发
UDP通信
- 特点:无连接、不可靠通信。
- 不事先建立连接;发送端每次把要发送的数据(限制在64KB内)、接收端IP、等信息封装成一个数据包,发出去就不管了。
- Java提供了一个java.net.DatagramSocket类来实现UDP通信。
DatagramSocket: 用于创建客户端、服务端
构造器 | 说明 |
---|---|
public DatagramSocket() | 创建客户端的Socket对象, 系统会随机分配一个端口号。 |
public DatagramSocket(int port) | 创建服务端的Socket对象, 并指定端口号 |
方法 | 说明 |
---|---|
public void send(DatagramPacket dp) | 发送数据包dp |
public void **receive(DatagramPacket dp) ** | 使用数据包dp接收数据 |
注意:Socket对象使用完毕之后要调用close()方法释放资源。
DatagramPacket:用于创建数据包
构造器 | 说明 |
---|---|
public DatagramPacket(byte[] buf, int length, InetAddress address, int port) | 创建发出去的数据包对象 |
public DatagramPacket(byte[] buf, int length) | 创建用来接收数据的数据包 |
方法 | 说明 |
---|---|
public int getLength() | 获取数据包实际接收到的字节个数 |
public InetAddress getAddress() | 返回发送此数据报或从中接收数据报的计算机的IP地址 |
public int getPort() | 返回发送此数据报或从中接收数据报的远程主机上的端口号 |
客户端实现步骤
- 创建DatagramSocket对象(客户端对象)。
- 创建DatagramPacket对象封装需要发送的数据(数据包对象)。
- 使用DatagramSocket对象的send方法,传入DatagramPacket对象。
- 释放资源。
服务端实现步骤
- 创建DatagramSocket对象并指定端口(服务端对象)。
- 创建DatagramPacket对象接收数据(数据包对象)。
- 使用DatagramSocket对象的receive方法,传入DatagramPacket对象。
- 释放资源。
UDP通信-多次收发
客户端实现步骤
- 创建DatagramSocket对象(发送端对象)。
- 使用while死循环不断的接收用户的数据输入,如果用户输入的exit则退出程序。
- 如果用户输入的不是exit, 把数据封装成DatagramPacket。
- 使用DatagramSocket对象的send方法将数据包对象进行发送。
- 释放资源。
接收端实现步骤
- 创建DatagramSocket对象并指定端口(接收端对象)。
- 创建DatagramPacket对象接收数据(数据包对象)。
- 使用DatagramSocket对象的receive方法传入DatagramPacket对象。
- 使用while死循环不断的进行第3步。
注意:此时接收端可以接收多个不同的客户端发送的消息,因为接收端只负责接收数据包,无所谓是哪个客户端的数据包。
TCP通信-单次收发
TCP通信
- 特点:面向连接、可靠通信。
- 通信双方事先会采用“三次握手”方式建立可靠连接,实现端到端的通信;底层能保证数据成功传给服务端。
- Java提供了一个java.net.Socket类来实现TCP通信。
客户端开发
- 客户端程序就是通过java.net包下的Socket类来实现的。
构造器 | 说明 |
---|---|
public Socket(String host , int port) | 根据指定的服务器ip、端口号请求与服务端建立连接,连接通过,就获得了客户端socket |
方法 | 说明 |
---|---|
public OutputStream getOutputStream() | 获得字节输出流对象 |
public InputStream getInputStream() | 获得字节输入流对象 |
客户端实现步骤
- 创建客户端的Socket对象,请求与服务端的连接。
- 使用socket对象调用getOutputStream()方法得到字节输出流。
- 使用字节输出流完成数据的发送。
- 释放资源:关闭socket管道。
服务端开发
服务端是通过java.net包下的ServerSocket类来实现的。
构造器 | 说明 |
---|---|
public ServerSocket(int port) | 为服务端程序注册端口 |
方法 | 说明 |
---|---|
public Socket accept() | 阻塞等待客户端的连接请求,一旦与某个客户端成功连接,则返回服务端这边的Socket对象 |
服务端实现步骤
- 创建ServerSocket对象,注册服务端端口。
- 调用ServerSocket对象的accept()方法,等待客户端的连接,并得到Socket管道对象。
- 通过Socket对象调用getInputStream()方法得到字节输入流、完成数据的接收。
- 释放资源:关闭socket管道。
TCP通信-多次收发
- 客户端使用死循环,让用户不断输入消息。
- 服务端也使用死循环,控制服务端收完消息,继续等待接收下一个消息。
- 服务端要捕获客户端离线的异常并进行处理。
TCP通信-支持与多个客户端同时通信
- 主线程负责循环接收客户端Socket管道连接。
- 每接收到一个Socket通信管道后分配一个独立的线程负责处理它。
TCP通信-群聊
- 群聊是指一个客户端把消息发出去,其他在线的全部客户端都可以收到消息。
- 需要用到端口转发的设计思想。
- 服务端需要把在线的Socket管道存储到一个集合中,一旦收到一个消息就要推送给其他所有管道。
- 同时客户端也要多开一个线程用来接收服务端推送的消息。
BS架构的基本原理
- 服务端的主线程负责接收浏览器连接,接收到连接之后把连接交给子线程处理。
- 服务器必须给浏览器响应HTTP协议规定的数据格式,否则浏览器不识别返回的数据。
补充:使用线程池进行优化
- 每次请求都开一个新线程并不好,因为在高并发时,服务器会同时打开很多线程,导致系统宕机。
- 此时可以使用线程池进行优化。