计算机网络


计算机网络_网络通讯协议关系图2020版

计算机网络_TCP-IP协议关系图.png

计算机网络_数据格式.png

TCP与UDP

TCP

特点:

  • 面向连接的、可靠的、基于字节流的传输层通信协议
  • 将应用层的数据流分割成报文段并发送给目标节点的TCP层
  • 数据包都有序号,对方收到则发送ACK确认,未收到则重传
  • 使用校验和来校验数据在传输过程中是否有误

无论是TCP还是UDP都是不包含IP地址的(由TCP/IP负责),包含双方的端口号(标识进程)。

计算机网络_TCP报头.jpg

  • 16位源端口号和16位目的端口号;
  • 32位序号:一次TCP通信过程中某一个传输方向上的字节流的每个字节的编号,通过这个来确认发送的数据有序,比如现在序列号为500,发送了200,下一个序列号就是700;
  • 32位确认号:用来响应TCP报文段,给收到的TCP报文段的序号加1,三握时还要携带自己的序号;
  • 4位头部长度:标识该TCP头部有多少个4字节,共表示最长15*4=60字节。同IP头部;
  • 6位保留。6位标志。URG(紧急指针是否有效)ACK(表示确认号是否有效)PSH(提示接收端应用程序应该立即从TCP接收缓冲区读走数据)RST(表示要求对方重新建立连接)SYN(同步序号,表示请求建立一个连接)FIN(表示通知对方本端要关闭连接,用于释放连接);
  • 16位窗口大小:TCP流量控制的一个手段,用来告诉对端TCP缓冲区还能容纳多少字节;
  • 16位校验和:由发送端填充,接收端对报文段执行CRC算法以检验TCP报文段在传输中是否损坏;
  • 16位紧急指针:一个正的偏移量,它和序号段的值相加表示最后一个紧急数据的下一字节的序号;
端口是否被服用

tcp链接可以被简化为对应的四元组或者五元组、七元组.完全一样的无法复用同一个端口.

客户端在分配请求的端口的时候会先看这个端口是否被占用,占用且四元组一致时,遍历下一个端口,直到找到对应的端口.不然报错.端口范围为net.ipv4.ip_local_port_range.

三次握手

三次握手连接.png

三次握手的必要性:

  • 为了初始化Seq,用于之后的传输;

SYN Flood攻击:在首次握手时SYN超时,此时,Server不断重试直到超时,Linux默认重试五次,每次时间翻倍,起始时间从1秒开始,等待1+2+4+8+16+32=63秒才断开连接。使得服务器可能遭到SYN Flood攻击。针对这种情况,SYN队列满了,通过tcp_syncookies参数回发SYN cookie。若为正常连接则Client会回发SYN cookie,直接建立连接。

在建立连接之后,Client故障,采用保活机制。此时向对方发送保活机制探测报文,如果未收到响应则继续发送,直至尝试次数达到保活探测数的上限。此时认定该Client不可达,中断连接。

计算机网络_TCP三次握手中连接队列情况.png

在内核中,使用链表管理全连接队列,使用哈希表管理半连接队列.

服务器绑定服务端口的时候申请并初始化接受队列(包含:半连接队列与全连接队列).在服务端接受到客户端的SYN包会创建socket在半连接队列.在收到客户端的ACK包后创建新的socket在全连接队列.应用程序accept之后会从全连接队列中取走socket.

四次挥手

四次回收关闭.png

TIME_WAIT状态的含义:

  • 确保有足够的时间让对方收到ACK包,避免发生重传;
  • 避免新旧连接混淆;

服务端大量出现CLOSE_WAIT状态的原因:对方关闭socket连接,我方忙于读写,没有及时关闭连接。此时,检查代码,特别是释放资源的代码。检查配置,特别是处理请求的线程配置。

Linux查看CLOSE_WAIT命令:netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'

滑动窗口

RTT:发送一个数据包到收到对应的ACK所花费的时间

RTO:重传时间间隔

TCP使用滑动窗口做流量控制与乱序重排,保证TCP的可靠性与流控特性。

计算机网络_TCP发送窗口.jpg

滑动窗口的数据由两部分构成:已发送但是没有收到ACK的和允许发送还没发送的。

计算机网络_TCP接收窗口.png

接收窗口:已接受到没发ACK的

UDP

无论是TCP还是UDP都是不包含IP地址的(有TCP/IP负责),包含双方的端口号(标识进程)。

特点:

  • 面向非连接
  • 不维护连接状态,支持同时向多个客户端传输相同的信息
  • 数据包报头只有8字节,额外开销小
  • 吞吐量只受限于数据生成速率、传输速率与机器性能
  • 尽最大努力交付,不保证可靠交付,不需要维护复杂的链接状态表
  • 面向报文,不对应用程序提交的报文信息进行拆分或者合并

计算机网络_UDP报文.png

二者区别

tcp udp
连接 无连接
可靠 不可靠
有序 无序
速度慢 速度快
重量 轻量

HTTP

特点:

  • 支持客户端/服务器模式
  • 简单灵活快速
  • 灵活
  • 无连接,长连接是由下层实现的对HTTP透明
  • 无状态

HTTP1.1相较于HTTP1.0最大的区别就是引入长连接。

HTTP请求结构.png

在浏览器输入url后经历的流程:

  1. DNS解析url对应的IP地址,由近到远的DNS解析为浏览器缓存、系统缓存、路由器缓存、ISP缓存、域名服务器缓存、顶级域名服务器缓存;
  2. TCP连接
  3. 发送HTTP请求
  4. 服务器处理请求并返回HTTP报文
  5. 浏览器解析渲染页面
  6. 连接结束

状态码

五种可能的取值:

  • 1xx:只是信息——表示请求已接收,继续处理
  • 2xx:成功——表示请求已经被成功接收、理解
  • 3xx:重定向——要完成请求必须进行进一步的操作
  • 4xx:客户端错误——请求有语法错误或请求无法实现
  • 5XX:服务端错误——服务器未能实现合法的请求
常见HTTP请求头
请求头 说明
Accept-Charset 用于指定客户端接受的字符集
Accept-Encoding 用于指定可接受的内容编码,如Accept-Encoding:gzip.deflate
Accept-Language 用于指定一种自然语言,如Accept-Language:zh-cn
Host 用于指定被请求资源的Internet主机和端口号,如Host:buerlog.top
User-Agent 客户端的操作系统、浏览器、等其他属性
Connection 当前连接是否保持,如Connection:Keep-Alive
常见HTTP响应头
响应头 说明
Server 使用的服务器名称:如Server:nginx/1.10.3 (Ubuntu)
Content-Type 用来指明发送给客户端的实体正文的媒体类型,如text/html; charset=utf-8
Content-Encoding 与请求抱头Accept-Encoding对应,告诉浏览器服务端采用什么压缩格式
Content-Language 描述了资源所用的自然语言
Content-length 指明实体正文的长度,用以字节方式存储的十进制数字来表示
Keep-Alive 保持连接的时间,如Keep-Alive:timeout:5,max=120
常见状态码
状态码 英文名称 中文描述
200 OK 请求成功。一般用于GET与POST请求
302 临时跳转,跳转地址通过location指定
400 Bad Request 客户端请求的语法错误,服务器无法理解
401 Unauthorized 请求要求用户的身份认证
403 Forbidden 服务器理解请求客户端的请求,但是拒绝执行此请求
404 Not Found 服务器无法根据客户端的请求找到资源(网页)。通过此代码,网站设计人员可设置"您所请求的资源无法找到"的个性页面
500 Internal Server Error 服务器内部错误,无法完成请求
503 Service Unavailable 由于超载或系统维护,服务器暂时的无法处理客户端的请求。延时的长度可包含在服务器的Retry-After头信息中

GET与POST区别

  • Http报文层面:GET将请求信息放在URL,有长度限制,相对不安全。POST放报文体中,无长度限制,相对安全,但是也是明文,还是要依靠HTTPS。
  • 数据库层面:GET符合幂等性和安全性,POST不符合。
  • 其他层面:GET可以被缓存、被存储,而POST不行。

Cookie与Session区别

HTTP是无状态的。

Cookie:是由服务器发送给客户端的特殊信息。以文本的形式存放在客户端,通过响应头传输。客户端再次发送的时候会将cookie回发。服务端收到后,会解析cookie生成与客户端相对应的内容。

Session:服务器端的机制,在服务器上保存信息。解析客户端请求并操作session id,按需保存状态信息。两种实现方式:使用cookie或使用url回写。

Tomcat同时使用两种实现方式,如果客户端支持使用cookie的方式,则使用cookie。否则使用url回写的方式。

HTTPS

计算机网络_HTTPS.png

SSL

Security Sockets Layer,安全套接层。为网络通信提供安全及数据完整性的一种安全协议。对操作系统对外的API,SSL3.0后更名为TLS。采用身份验证和数据加密保证网络通信的安全和数据的完整性。

加密

对称加密

加密解密使用同一个密钥。

非对称加密

加密使用的密钥和解密使用的密钥是不相同的。

哈希算法

将任意长度的信息转换为固定长度的值,算法不可逆,比如md5算法。

数字签名

证明某个信息或者文件是某人发出或认同的。

HTTPS数据传输流程

  1. 浏览器将支持的加密算法信息发送给服务器
  2. 服务器选择一套浏览器支持的加密算法,已证书的形式回发浏览器
  3. 浏览器验证证书合法性,并结合证书公钥加密信息发送给浏览器
  4. 服务器使用私钥解密信息,验证哈希,加密响应信息回发浏览器
  5. 浏览器解密响应信息,并对消息进行验证,之后进行加密交互数据

区别

  • HTTPS需要CA申请证书,HTTP不需要
  • HTTPS密文传输,HTTP明文传输
  • HTTPS默认443,HTTP默认80
  • HTTPS=HTTP+加密+认证+完整性保护,较HTTP安全

用户还有使用HTTP的,网站大多进行跳转。但在跳转过程中可能出现劫持。可以使用HSTS优化。

Socket

本地中每个进程用PID进行唯一标识。

IP地址+协议+端口号标识网络中的进程。

Socket是对TCP/IP的抽象,是操作系统对外开放的接口。

计算机网络_Socket.png

Socket通信流程

计算机网络_Socket通信.png

以下是JAVA实现分别基于TCP和UDP的Socket

//TCPClient.java
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

public class TCPClient {
    public static void main(String[] args) throws Exception {
        //创建socket,并指定连接的是本机的端口号为65000的服务器socket
        Socket socket = new Socket("127.0.0.1", 65000);
        //获取输出流
        OutputStream os = socket.getOutputStream();
        //获取输入流
        InputStream is = socket.getInputStream();
        //将要传递给server的字符串参数转换成byte数组,并将数组写入到输出流中
        os.write(new String("hello world").getBytes());
        int ch = 0;
        byte[] buff = new byte[1024];
        //buff主要用来读取输入的内容,存成byte数组,ch主要用来获取读取数组的长度
        ch = is.read(buff);
        //将接收流的byte数组转换成字符串,这里是从服务端回发回来的字符串参数的长度
        String content = new String(buff, 0, ch);
        System.out.println(content);
        //不要忘记关闭输入输出流以及socket
        is.close();
        os.close();
        socket.close();
    }
}

//TCPServer.java
import java.net.ServerSocket;
import java.net.Socket;

public class TCPServer {
    public static void main(String[] args) throws Exception {
        //创建socket,并将socket绑定到65000端口
        ServerSocket ss = new ServerSocket(65000);
        //死循环,使得socket一直等待并处理客户端发送过来的请求
        while (true) {
            //监听65000端口,直到客户端返回连接信息后才返回
            Socket socket = ss.accept();
            //获取客户端的请求信息后,执行相关业务逻辑
            new LengthCalculator(socket).start();
        }
    }
}

//UDPClient.java
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

public class UDPClient {
    public static void main(String[] args) throws Exception {
        // 客户端发数据报给服务端
        DatagramSocket socket = new DatagramSocket();
        // 要发送给服务端的数据
        byte[] buf = "Hello World".getBytes();
        // 将IP地址封装成InetAddress对象
        InetAddress address = InetAddress.getByName("127.0.0.1");
        // 将要发送给服务端的数据封装成DatagramPacket对象 需要填写上ip地址与端口号
        DatagramPacket packet = new DatagramPacket(buf, buf.length, address,
                65001);
        // 发送数据给服务端
        socket.send(packet);

        // 客户端接受服务端发送过来的数据报
        byte[] data = new byte[100];
        // 创建DatagramPacket对象用来存储服务端发送过来的数据
        DatagramPacket receivedPacket = new DatagramPacket(data, data.length);
        // 将接受到的数据存储到DatagramPacket对象中
        socket.receive(receivedPacket);
        // 将服务器端发送过来的数据取出来并打印到控制台
        String content = new String(receivedPacket.getData(), 0,
                receivedPacket.getLength());
        System.out.println(content);

    }

}

//UDPServer.java
import java.net.DatagramPacket;
import java.net.DatagramSocket;

public class UDPServer {
    public static void main(String[] args) throws Exception {
        // 服务端接受客户端发送的数据报
        DatagramSocket socket = new DatagramSocket(65001); //监听的端口号
        byte[] buff = new byte[100]; //存储从客户端接受到的内容
        DatagramPacket packet = new DatagramPacket(buff, buff.length);
        //接受客户端发送过来的内容,并将内容封装进DatagramPacket对象中
        socket.receive(packet);

        byte[] data = packet.getData(); //从DatagramPacket对象中获取到真正存储的数据
        //将数据从二进制转换成字符串形式
        String content = new String(data, 0, packet.getLength());
        System.out.println(content);
        //将要发送给客户端的数据转换成二进制
        byte[] sendedContent = String.valueOf(content.length()).getBytes();
        // 服务端给客户端发送数据报
        //从DatagramPacket对象中获取到数据的来源地址与端口号
        DatagramPacket packetToClient = new DatagramPacket(sendedContent,
                sendedContent.length, packet.getAddress(), packet.getPort());
        socket.send(packetToClient); //发送数据给客户端
    }

}

//LengthCalculator.java
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

public class LengthCalculator extends Thread {
    //以socket为成员变量
    private Socket socket;

    public LengthCalculator(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        try {
            //获取socket的输出流
            OutputStream os = socket.getOutputStream();
            //获取socket的输入流
            InputStream is = socket.getInputStream();
            int ch = 0;
            byte[] buff = new byte[1024];
            //buff主要用来读取输入的内容,存成byte数组,ch主要用来获取读取数组的长度
            ch = is.read(buff);
            //将接收流的byte数组转换成字符串,这里获取的内容是客户端发送过来的字符串参数
            String content = new String(buff, 0, ch);
            System.out.println(content);
            //往输出流里写入获得的字符串的长度,回发给客户端
            os.write(String.valueOf(content.length()).getBytes());
            //不要忘记关闭输入输出流以及socket
            is.close();
            os.close();
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Tip

Websocket

127.0.0.1&0.0.0.0.0

众所周知,。IP地址一共分为5位。

大致分类如下:

  1. A类地址:网络号占1个字节,网络号的第一位固定为0;
  2. B类地址:网络号占2个字节,网络号的前两位固定为10;
  3. C类地址:网络号占3个字节,网络号的前三位固定位110;
  4. D类地址:前四位是1110,用于多播(multicast),即一对多通信;
  5. E类地址:前四位是1111,保留为以后使用。

计算机网络_IP地址分类.png

其中,ABC三类地址为单播地址(unicast),用于一对一通信,是最常用的。

计算机网络_IP地址划分.jpg

netstat

命令参数:

  • -a或–all 显示所有连线中的Socket。
  • -A<网络类型>或–<网络类型> 列出该网络类型连线中的相关地址。
  • -c或–continuous 持续列出网络状态。
  • -C或–cache 显示路由器配置的快取信息。
  • -e或–extend 显示网络其他相关信息。
  • -F或–fib 显示FIB。
  • -g或–groups 显示多重广播功能群组组员名单。
  • -h或–help 在线帮助。
  • -i或–interfaces 显示网络界面信息表单。
  • -l或–listening 显示监控中的服务器的Socket。
  • -M或–masquerade 显示伪装的网络连线。
  • -n或–numeric 直接使用IP地址,而不通过域名服务器。
  • -N或–netlink或–symbolic 显示网络硬件外围设备的符号连接名称。
  • -o或–timers 显示计时器。
  • -p或–programs 显示正在使用Socket的程序识别码和程序名称。
  • -r或–route 显示Routing Table。
  • -s或–statistice 显示网络工作信息统计表。
  • -t或–tcp 显示TCP传输协议的连线状况。
  • -u或–udp 显示UDP传输协议的连线状况。
  • -v或–verbose 显示指令执行过程。
  • -V或–version 显示版本信息。
  • -w或–raw 显示RAW传输协议的连线状况。
  • -x或–unix 此参数的效果和指定”-A unix”参数相同。
  • –ip或–inet 此参数的效果和指定”-A inet”参数相同。

ESTABLISHED 表示正在通信,TIME_WAIT 表示主动关闭,CLOSE_WAIT 表示被动关闭。

awk

行匹配语句 awk ‘’ 只能用单引号。

log.txt文本内容如下:

2 this is a test
3 Are you like awk
This's a test
10 There are orange,apple,mongo
# 每行按空格或TAB分割,输出文本中的1、4项,每项之间用空格分开
 $ awk '{print $1,$4}' log.txt
 ---------------------------------------------
 2 a
 3 like
 This's
 10 orange,apple,mongo
 # 格式化输出
 $ awk '{printf "%-8s %-10s\n",$1,$4}' log.txt
 ---------------------------------------------
 2        a
 3        like
 This's
 10       orange,apple,mongo

-F <可以指定标识符>


文章作者: 不二
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 不二 !
  目录