1.网络编程
1.1 网络常识
1.1.1 计算机网络的定义
分布在不同地域的计算机, 通过硬件等网络设备使用通信线路互相连接形成的一个网格系统。计算机网络, 可以很方便的进行信息的传递, 资源的共享 !
1.1.2 计算机的IP地址
IP地址是计算机在互联网中的唯一标识(一般指公网IP)。本机IP: 127.0.0.1。
IP地址的分类:
-
根据是否局域网分类
- 内网IP
- 公网IP
-
根据Internet协议版本分类
- IPv4
- IPv4协议具有32位(4字节)地址长度;
- IPv4地址是以小数表示的二进制数;//192.168.1.104
- 不提供身份验证和加密;
- 地址解析协议(ARP)可用于将IPv4地址映射到MAC地址;
- ……
- IPv6
- IPv6协议具有128位(16字节)地址长度;
- IPv6地址是以十六进制表示的二进制数;//ADBC:EFDC:6789:ABCD:EF01:2345:6789:2345
- 提供身份验证和加密;
- 地址解析协议(ARP)被邻居发现协议(NDP)的功能所取代
- ……
- IPv4
1.1.3 网络中网站的域名
域名可以简单的理解为, IP地址的别名。更方便记忆, 当输入域名后(例如www.baidu.com) , 计算机会访问域名解析商 , 然后得到ip地址, 再进行访问。
1.1.4 计算机的端口号
与ip地址很相似,IP地址是计算机在网络中的唯一标识 ,端口号是计算机中程序的标识。用于在一台计算机中区分不同的应用程序。
端口号的范围 0-65535 之间。 端口号在使用时 , 应尽量避免0-1024之间的端口号, 因为已经被一些知名的软件和 Windows操作系统所占用了。
1.1.5 计算机之间的通信协议
是计算机与计算机之间交流的标准。是对数据的传输速率、传入接口、步骤控制、出错控制等等制定的一套标准 !
常用的通信协议:
-
http协议 :
超文本传输协议 . 80端口号。
-
https协议:
安全的超文本传输协议 443端口号。
-
ftp协议:
文件传输协议 21端口号。
-
TCP协议:
传输控制协议,面向连接,全双工通信(双方都可以作为数据的发送方和接收方),可以保证传输数据的安全。
-
UDP协议:
数据报协议,面向无连接协议,不可靠,传输速度快,但是容易丢失数据,通常应用于视频会议、QQ聊天(现在是UDP+TCP)等。
1.2 网络编程程序的分类
-
**B/S 程序 **
浏览器与服务器程序 。
-
C/S 程序
客户端与服务器程序。
1.3 TCP协议
从一台计算机的软件中, 将数据发送到另一台计算机的软件中的过程。
1.3.1 OSI模型
- 第七层:应用层
- 第六层:表现层
- 第五层:会话层
- 第四层:传输层
- 第三层:网络层
- 第二层:数据链路层
- 第一层:物理层
1.3.2 三次握手
1.3.2.1 需要重点关注的信号量
TCP的FLAG位由6个bit组成,分别代表SYN、ACK、FIN、URG、PSH、RST,需要重点注意:
-
SYN
用作建立连接时的同步信号。
-
ACK
用于对收到数据进行确认,所确认的数据由确认序列号表示。
-
FIN
表示后面没有数据需要发送了,通常意味着所建立的连接需要关闭了。
1.3.2.2 三次握手的过程
- A机器(LISTENING状态)发出一个数据包,并将SYN置于1,表示希望建立连接。这个包的序列号假设为x,发送后A为SYN_SENT状态;
- B机器(LISTENING)接收到A机器发送的数据包,通过SYN得知这是一个建立连接的请求,于是发送一个相应包,并置SYN和ACK为1,假设这个响应包的序列号为y,而确认序列号必须为x+1,表示收到了A发送过来的SYN,发送后B状态变成了SYN_RCVD;
- A收到B响应包后(ESTABLISHED状态)需要确认,确认包中ACK为1,并将确认序列号设置为y+1,表示收到了B的SYN,发送给B,B收到后变成ESTABLISHED状态。
1.3.2.3 为什么需要第三次握手?
-
保证信息对等和防止超时,三次握手改成仅需要两次握手,死锁是可能发生。
举例:
考虑计算机A和B之间的通信,假定A给B发送一个连接请求分组,B收到了这个分组,并发送了确认应答分组。按照两次握手的协定,B认为连接已经成功地建立了,可以开始发送数据分组。可是,A在B的应答分组在传输中被丢失的情况下,将不知道B是否已准备好,不知道B建立什么样的序列号,A甚至怀疑B是否收到自己的连接请求分组。在这种情况下,A认为连接还未建立成功,将忽略B发来的任何数据分组,只等待连接确认应答分组。而B在发出的分组超时后,重复发送同样的分组。这样就形成了死锁。
-
防止请求超时而导致脏连接,因为TTL网络报文的生存时间往往都会超过TCP请求超时的时间。
举例:
如果是两次握手连接的话,比如是A机要连到B机,结果发送的连接信息由于某种原因没有到达B机。于是,A机又发了一次,结果这次B收到了,于是就发信息回来,两机就连接。传完东西后,断开。结果这时候,原先没有到达的连接信息突然又传到了B机,于是B机发信息给A,然后B机就以为和A连上了,这个时候B机就在等待A传东西过去。
如果是三次握手连接的话,B机器在收到连接请求后,同样会向A机器确认创建连接,但因为A机器不是SYN_SENT状态,所以会直接丢弃,B机器长期收不到确认信息,最终导致连接创建超时,不会出现脏连接。
1.3.3 四次挥手
- A机器发送数据完毕后,发送FIN信号给B,序列号假设为u,通知它数据发送完了,发送后A机器变成了FIN_WAIT_1状态;
- B机器应答ACK,应答序列号为u+1,告诉A机器可以断开,但是要等B机器处理完数据(因为此时可能有一部分数据还在传输中,这个时候A处于(FIN_WAIT_2)半关闭状态,不可以再发送数据),此后B机器进入CLOSE_WAIT状态;
- B机器处理完之后,给A机器发送FIN信号,序列号为w,应答序列号为u+1,表示可以断开了(这个时候B机器也进入了(LAST_ACK)半关闭状态,不能再接收数据);
- A针对B机器的FIN信号发送ACK后(序列号为u+1,应答序列号为w+1)进入TIME_WAIT状态,经过**2MSL(报文在网络中存活的最长时间)**后没有收到B机器的报文,则确定B机器已经收到了A机器的ACK指令,此时连接正式断开。
1.4 C/S程序
需要用到两个类,来编写TCP协议的 CS程序,其中ServerSocket类用以搭建服务器,Socket 用以搭建客户端,两方使用socket(套接字 , 通信端点) 进行交流。
1.4.1 java.net.ServerSocket类
用于创建服务器 ,创建完毕后, 会绑定一个端口号。然后此服务器可以等待客户端连接 . 每连接一个客户端 , 服务器就会得到一个新的Socket对象, 用于跟客户端进行通信。
1.4.1.1 ServerSocket的常用构造方法
ServerSocket(int port);
//创建一个基于TCP/IP协议的服务器 , 并绑定指定的端口号.
//注意: 参数port的范围是: 0-65535 (建议1025-65535)
1.4.1.2 ServerSocket的常用方法
-
Socket accept();
等待客户端连接.此方法会导致线程的阻塞! 直到一个新的客户端连接成功, return Socket对象后, 线程在继续执行.
-
void close();
释放占用的端口号 , 关闭服务器。
1.4.2 java.net.Socket类
是两台计算机之间通信的端点 , 是网络驱动提供给应用程序编程的一种接口 一套标准, 一种机制.
1.4.1.1 Socket的常用构造方法
Socket(String ip,int port) ****
//创建一个套接字, 并连接指定ip和端口号的 服务器.
//参数1. 服务器的ip地址
//参数2. 服务器软件的端口号..
1.4.1.2 Socket的常用方法
-
OutputStream getOutputStream();
返回的是 , 指向通信的另一端点的输出流。
-
InputStream getInputStream();
返回的是 , 指向通信的另一端点的输入流。
-
void close();
关闭套接字。
注意:
在网络编程时, 获取输入输出流的操作 ,对于客户端与服务器来说是相对的 :
- 客户端的输入流, 输入的是服务器的输出流 输出的内容;
- 客户端的输出流, 输出到了服务器的输入流中。
所以 在使用时, 需要注意以下一点规则:
客户端与服务器获取流的顺序必须是相反的: 例如: 客户端先得到了输入流 , 那服务器必须先获取输出流。
1.4.3 DatagramSocket类
用户数据报协议, 与TCP协议不同,UDP的连接是不可信的。数据发送的成功与失败与数据报是无关的。DatagramSocket类用于创建发送 与接收数据包的Socket。
1.4.3.1 DatagramSocket的常用构造方法
-
DatagramSocket(int port);
创建一个发送与接收数据包的Socket,参数: 端口号,
1.4.3.2 DatagramSocket的常用方法
-
close()
关闭套接字。
-
send(DatagramPacket dp)
将一个数据包dp 发送出去。
-
receive(DatagramPacket dp)
接收一个数据包, 并存储到参数dp中。
1.4.4 DatagramPacket类
数据包,用于发送或接收数据时, 盛放数据的对象。
1.4.4.1 DatagramPacket的常用构造方法
-
DatagramPacket(byte[] bytes,int startIndex,int len, InetAddress ip, int port);
- bytes: 要发送的数据, 是字节数组的形式
- startIndex: 有效数据 在数组中的起始位置
- len: 有效数据 在数组中的长度
- ip: 当前这个数据包, 准备发送到的IP地址, InetAddress 这个类的对象, 用于描述 IP
用于发送数据时, 组装数据的构造方法.
-
DatagramPacket(byte[] bytes,int len)
-
bytes: 用于存储数据的数组
-
len: 允许存储的最大长度
用于接收数据时, 存储数据的构造方法. 创建的是不包含数据的数据包, 用于在接收到数据后, 存储数据 !
1.4.4.2 DatagramSocket的常用方法
-
byte[] getData()
用于获取数据包中的有效字节数组。
-
int getLength
用于获取数据包中的有效数据的长度。
1.4.5 InetAddress类
InetAddress 这个类的对象, 用于描述IP。
1.4.5.1 InetAddress的静态构造
- InetAddress.getByName(String ip);
注意:
在UDP协议中. 通过数据包DatagramPacket的getAddress方法, 可以得到数据包来自哪个ip。
在TCP协议中, 通过套接字Socket的getInetAddress方法, 可以得到套接字连接的ip地址。
1.4.5.2 InetAddress的常用方法
-
String getHostAddress()
ip地址字符串。
-
String getHostName()
计算机名称, 当名称无法获取时, 获取的为ip地址。