目录
web通信的简单结构
网络通信基础TCP/IP
TCP/IP 通信传输流
HTTP中的三剑客
负责传输的IP协议
确保可靠性的TCP协议
SYN攻击(SYN Flood Attack)
四次挥手
负责域名解析的DNS服务
基于 TCP 协议实现通信
TCP 协议的通信过程
Web 使用一种名为 HTTP(HyperText Transfer Protocol,超文本传输协议)的协议作为规范,完成从客户端到服务器端等一系列运作流程。举个例子,我们使用浏览器访问百度:www.baidu.com(Ip:220.181.38.150)。
DNS域名解析:
DNS(Domain Name System)服务是和HTTP协议一样位于应用层的协议。它提供域名到IP之间的解析服务。
http访问web
通常使用的网络(包括互联网)是在TCP/IP协议族的基础上运作的。TCP/IP协议族四层结构分为:应用层、传输层、网络层和数据链路层。
应用层:决定了向用户提供应用服务时通信的活动。
传输层:提供处于网络连接中的两台计算机之间的数据传输。常见的是TCP和UDP两种性质不同的协议。
TCP(Transmission Control Protocol)
UDP(User Data Protocol)
网络层:用来处理在网络上流动的数据包。
链路层(数据链路层、网络接口层):用来处理连接网络的硬件部分。
当然也存在OSI七层机构和TCP/IP五层结构的划分方式。
发送端在层与层之间传输数据时,每经过一层时必定会被打上一个该层所属的首部信息。反之,接收端在层与层传输数据时,每经过一层时会把对应的首部消去。
在TCP/IP协议族中与HTTP密不可分的3个协议:IP协议、TCP协议和DNS协议
IP 协议的作用是把各种数据包传送给对方。其中两个重要的条件是 IP 地址和 MAC 地址(Media Access Control Address)。IP 地址可以和 MAC 地址进行配对。IP 地址可变换,但 MAC 地址基本上不会更改。
使用ARP协议凭借MAC地址进行通信,这个过程像快递公司的送货过程。寄件人将货物送到集散中心,快递公司根据收件地址就能确定下一站该送往哪个区域的集散中心。这种机制也叫路由选择、
为了准确无误地将数据送达目的地,TCP协议采用了三次握手(three-way handshaking)策略。握手过程中使用了TCP的标志(flag)-SYN(synchronize)和ACK(acknowledgement)。只有三次握手,Client和Server才能相互确认双相连接,实现双工数据传输。
第一次握手(SYN=1,seq=x):客户端发送一个TCP的SYN标志位置1的包,指明要连接的服务器端口以及初始序号x,保存在包头的序列号(Sequence-Number)字段中,发送完毕后,客户端进入SYN-SEND状态。
第二次握手(SYN=1,ACK=1,seq=y,ack=x+1):服务器发回确认包(ACK)应答,即SYN和ACK标志位均为1。服务器将自己ISN(初始序列号)放入Seq中,同时将ack设置为客户端的ISN+1即x+1.发送完毕后,服务器进入SYN-RCVD状态。
第三次握手(ACK=1,seq=x+1,ack=y+1):客户端再次发送确认包(ACK),SYN为0,ACK为1,并且把ack设为服务器的ISN+1即y+1发送给对方,数据发送完毕,客户端进入ESTABLISHED状态,当服务器接收到这个包时,也进入ESTABLISHED状态,TCP握手结束。
SYN攻击(SYN Flood Attack)
是一种网络攻击,通常针对TCP协议的三次握手过程中的漏洞进行攻击。SYN攻击旨在使目标服务器耗尽资源,导致其无法正常处理新的连接请求,从而使服务不可用。以下是SYN攻击的工作原理和防御方法:
工作原理:
攻击者发送大量伪造的TCP连接请求(SYN请求)到目标服务器。
目标服务器收到这些伪造的连接请求后,会为每个请求分配一些资源,如内存和连接表项,然后回复一个SYN-ACK响应,等待客户端的确认。
攻击者不回复服务器的SYN-ACK响应,或者回复得很慢,从而使服务器一直等待确认。
由于服务器需要等待确认,它不断累积未完成的连接请求,消耗了系统资源,最终可能无法再接受新的合法连接请求,导致拒绝服务(DoS)。
防御方法:
SYN Cookies:一种常见的防御方法是使用SYN Cookies。在使用SYN Cookies的情况下,服务器不会为每个连接请求分配资源,而是根据客户端的请求生成一个特殊的标识符(SYN Cookie)。只有在客户端回复ACK时,服务器才会分配资源。这可以减轻攻击对服务器资源的影响。
调整连接资源限制:可以调整服务器的TCP连接资源限制,限制每个IP地址的并发连接数,以减轻攻击的影响。这可以通过操作系统的设置来实现。
使用防火墙和入侵检测系统(IDS/IPS):防火墙和IDS/IPS可以用于检测和过滤恶意的SYN请求流量。它们可以识别和拦截大规模的SYN攻击尝试。
网络流量分析:监控和分析网络流量,及时检测异常流量模式,可以帮助发现SYN攻击。
升级硬件和网络带宽:增加服务器的硬件资源和网络带宽可以增加其抵御SYN攻击的能力,但这并不是解决问题的根本方法。
使用CDN:使用内容分发网络(CDN)可以分担攻击流量,减轻服务器的负担,提高服务的可用性。
四次挥手
四次挥手的目的是关闭一个连接,连接存在时,客户端和服务器均可主动发起挥手动作(TCP是一个全双工协议),在socket编程中,任何一方执行close()操作即可产生挥手操作。
第一次挥手(FIN=1,seq=u):假设客户端想要关闭连接,客户端发送一个 FIN 标志位置为 1 的包,表示自己已经没有数据可以发送了,但是仍然可以接受数据。发送完毕后,客户端进入 FIN_WAIT_1 状态。
第二次挥手(ACK=1,ack=u+1):服务器端确认客户端的 FIN 包,发送一个确认包,表明自己接受到了客户端关闭连接的请求, 但还没有准备好关闭连接。发送完毕后,服务器端进入 CLOSE_WAIT 状态,客户端接收到这个确认包之后,进入 FIN_WAIT_2 状态,等待服务器端关闭连接。
第三次挥手(FIN=1,seq=w):服务器端准备好关闭连接时,向客户端发送结束连接请求,FIN 置为 1。发送完毕后,服务器端进入 LAST_ACK 状态,等待来自客户端的最后一个 ACK。
第四次挥手(ACK=1,ACKnum=w+1):客户端接收到来自服务器端的关闭请求,发送一个确认包,并进入 TIME_WAIT 状态,等待 可能出现的要求重传的 ACK 包。 服务器端接收到这个确认包之后,关闭连接,进入 CLOSED 状态。 客户端等待了某个固定时间(两个最大段生命周期,2MSL,2 Maximum Segment Lifetime) 之后,没有收到服务器端的 ACK,认为服务器端已经正常关闭连接,于是自己也关闭连接, 进入 CLOSED 状态。
为什么连接的时候是三次握手,关闭的时候却是四次握手?
三次握手是因为因为当 Server 端收到 Client 端的 SYN 连接请求报文后,可以直接发送 SYN+ACK 报文。其中 ACK 报文是用来应答的,SYN 报文是用来同步的。
但是关闭连接时, 当 Server 端收到 FIN 报文时,很可能并不会立即关闭 SOCKET(因为可能还有消息没处理 完),所以只能先回复一个 ACK 报文,告诉 Client 端,"你发的 FIN 报文我收到了"。只有等到 我 Server 端所有的报文都发送完了,我才能发送 FIN 报文,因此不能一起发送。故需要四步握手。
DNS(Domain Name System)服务是和 HTTP 协议一样位于应用层的协议。它提供域名到 IP 地址之间的解析服务。
TCP是一个全双工协议,数据通信允许数据同时在两个方向上传输,因此全双工是两个单工通信方式的结合,它要求发送设备和接收设备都有独立的接收和发送能力。通过Socket简单地模拟下双工通信。
server端实现:
public class ServerSocketDemo {
public static void main(String[] args) throws IOException {
try {
ServerSocket server = null;
// 创建一个serverSocket在端口8080监听客户端请求
server = new ServerSocket(8080);
Socket socket = null;
try {
socket = server.accept(); // 使用accept()阻塞等待客户请求
} catch (IOException e) {
e.printStackTrace();
}
String line;
// 由Socket对象得到输入流,并构造响应的BufferedReader对象
BufferedReader is = new BufferedReader(new InputStreamReader(socket.getInputStream()));
// 由Socket对象得到输出流,并构造PrintWriter对象
PrintWriter os = new PrintWriter(socket.getOutputStream());
// 由系统标准输入设备构造BufferedReader对象
BufferedReader sin = new BufferedReader(new InputStreamReader(System.in));
// 在标准输出上打印从客户端读入的字符串
System.out.println("Client:" + is.readLine());
// 从标准输入读入字符串
line = sin.readLine();
// 读到“bye”停止循环
while (!line.equals("bye")) {
// 向客户端输出该字符串
os.println(line);
// 刷新输出流,使Client马上收到该字符串
os.flush();
// 在系统标准输出上打印读入的字符串
System.out.println("Server:" + line);
// 从Client读入字符串,并打印到标准输出上
System.out.println("Client:" + is.readLine());
// 从系统标准输入读入字符串
line = sin.readLine();
}
os.close();
is.close();
socket.close();
server.close();
} catch (IOException e) {
System.out.println("Error:" + e);
}
}
}
client端实现:
public class ClientSocketDemo {
public static void main(String[] args) {
try {
// 找到目标serverSocket的地址和端口
Socket socket = new Socket("localhost", 8080);
// 控制台的输入流
BufferedReader sin = new BufferedReader(new InputStreamReader(System.in));
// 在当前连接上写入数据
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
// 拿到输入流
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String readline = sin.readLine();
while (!readline.equals("bye")) {
out.println(readline);
out.flush();
System.out.println("Client:"+readline);
System.out.println("Server:"+in.readLine());
readline = sin.readLine(); // 重新获取
}
out.close();
in.close();
socket.close();
} catch (IOException e) {
System.out.println("Error" + e);
}
}
}
首先,对于 TCP 通信来说,每个 TCP Socket 的内核中都有一个发送缓冲区和一个接收缓冲 区,TCP 的全双工的工作模式及 TCP 的滑动窗口就是依赖于这两个独立的 Buffer 和该 Buffer 的填充状态。
接收缓冲区把数据缓存到内核,若应用进程一直没有调用 Socket 的 read 方法进行读取,那么该数据会一直被缓存在接收缓冲区内。不管进程是否读取 Socket,对端发来的数据都会经 过内核接收并缓存到 Socket 的内核接收缓冲区。 read 所要做的工作,就是把内核接收缓冲区中的数据复制到应用层用户的 Buffer 里。 进程调用 Socket 的 send 发送数据的时候,一般情况下是将数据从应用层用户的 Buffer 里复 制到 Socket 的内核发送缓冲区,然后 send 就会在上层返回。换句话说,send 返回时,数据不一定会被发送到对端。
Socket 的接收缓冲区被 TCP 用来缓存网络上收到的数据,一直保存到应用进 程读走为止。如果应用进程一直没有读取,那么 Buffer 满了以后,出现的情况是:通知对端 TCP 协议中的窗口关闭,保证 TCP 接收缓冲区不会移除,保证了 TCP 是可靠传输的。如果对方无视窗口大小发出了超过窗口大小的数据,那么接收方会把这些数据丢弃。
这个过程中涉及到了 TCP 的滑动窗口协议,滑动窗口(Sliding window)是一种流量控制技术。早期的网络通信中,通信双方不会考虑网络的拥挤情况直接发送数据。由于大家不知道 网络拥塞状况,同时发送数据,导致中间节点阻塞掉包,谁也发不了数据,所以就有了滑动窗口机制来解决此问题;发送和接受方都会维护一个数据帧的序列,这个序列被称作窗口。
就是发送端允许连续发送的帧的序号表。 发送端可以不等待应答而连续发送的最大帧数称为发送窗口的尺寸。
接收方允许接收的帧的序号表,凡落在接收窗口内的帧,接收方都必须处理,落在接收窗口外的帧被丢弃。 接收方每次允许接收的帧数称为接收窗口的尺寸。
接收窗口 接收方允许接收的帧的序号表,凡落在接收窗口内的幀,接收方都必须处理,落在接收窗口外的帧被丢弃。 接收方每次允许接收的帧数称为接收窗口的尺寸。