signed

QiShunwang

“诚信为本、客户至上”

网络编程相关笔记

2021/3/20 23:39:57   来源:

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)的功能所取代
      • ……

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 三次握手的过程
  1. A机器(LISTENING状态)发出一个数据包,并将SYN置于1,表示希望建立连接。这个包的序列号假设为x,发送后A为SYN_SENT状态;
  2. B机器(LISTENING)接收到A机器发送的数据包,通过SYN得知这是一个建立连接的请求,于是发送一个相应包,并置SYN和ACK为1,假设这个响应包的序列号为y,而确认序列号必须为x+1,表示收到了A发送过来的SYN,发送后B状态变成了SYN_RCVD;
  3. A收到B响应包后(ESTABLISHED状态)需要确认,确认包中ACK为1并将确认序列号设置为y+1,表示收到了B的SYN,发送给B,B收到后变成ESTABLISHED状态。
1.3.2.3 为什么需要第三次握手?
  1. 保证信息对等和防止超时,三次握手改成仅需要两次握手,死锁是可能发生。

    举例:

    ​ 考虑计算机A和B之间的通信,假定A给B发送一个连接请求分组,B收到了这个分组,并发送了确认应答分组。按照两次握手的协定,B认为连接已经成功地建立了,可以开始发送数据分组。可是,A在B的应答分组在传输中被丢失的情况下,将不知道B是否已准备好,不知道B建立什么样的序列号,A甚至怀疑B是否收到自己的连接请求分组。在这种情况下,A认为连接还未建立成功,将忽略B发来的任何数据分组,只等待连接确认应答分组。而B在发出的分组超时后,重复发送同样的分组。这样就形成了死锁

  2. 防止请求超时而导致脏连接,因为TTL网络报文的生存时间往往都会超过TCP请求超时的时间。

    举例:

    ​ 如果是两次握手连接的话,比如是A机要连到B机,结果发送的连接信息由于某种原因没有到达B机。于是,A机又发了一次,结果这次B收到了,于是就发信息回来,两机就连接。传完东西后,断开。结果这时候,原先没有到达的连接信息突然又传到了B机,于是B机发信息给A,然后B机就以为和A连上了,这个时候B机就在等待A传东西过去。

    ​ 如果是三次握手连接的话,B机器在收到连接请求后,同样会向A机器确认创建连接,但因为A机器不是SYN_SENT状态,所以会直接丢弃,B机器长期收不到确认信息,最终导致连接创建超时,不会出现脏连接。

1.3.3 四次挥手

  1. A机器发送数据完毕后,发送FIN信号给B,序列号假设为u,通知它数据发送完了,发送后A机器变成了FIN_WAIT_1状态;
  2. B机器应答ACK,应答序列号为u+1,告诉A机器可以断开,但是要等B机器处理完数据(因为此时可能有一部分数据还在传输中,这个时候A处于(FIN_WAIT_2)半关闭状态,不可以再发送数据),此后B机器进入CLOSE_WAIT状态;
  3. B机器处理完之后,给A机器发送FIN信号,序列号为w,应答序列号为u+1,表示可以断开了(这个时候B机器也进入了(LAST_ACK)半关闭状态,不能再接收数据);
  4. 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地址。