命令

  readelf 命令用来显示一个或者多个elf格式的目标文件的信息,可以通过它的选项来控制显示哪些信息。这里的elf-file(s)就表示那些被检查的文件。可以支持32位,64位的elf格式文件,也支持包含elf文件的文档(这里一般指的是使用ar命令将一些elf文件打包之后生成的例如lib*.a之类的 “静态库” 文件)。

  常见的文件如在Linux上的可执行文件,动态库(.so)或者静态库(.a) 等包含ELF格式的文件。以下命令的使用是基于android编译出来的so文件上面去运行。

运行 readelf 的时候,除了-v 和 -H 之外,其它的选项必须有一个被指定。

选项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
-a 
--all 显示全部信息,等价于 -h -l -S -s -r -d -V -A -I.

-h
--file-header 显示elf文件开始的文件头信息.

-l
--program-headers
--segments 显示程序头(段头)信息(如果有的话)。

-S
--section-headers
--sections 显示节头信息(如果有的话)。

-g
--section-groups 显示节组信息(如果有的话)。

-t
--section-details 显示节的详细信息(-S的)。

-s
--syms
--symbols 显示符号表段中的项(如果有的话)。

-e
--headers 显示全部头信息,等价于: -h -l -S

-n
--notes 显示note段(内核注释)的信息。

-r
--relocs 显示可重定位段的信息。

-u
--unwind 显示unwind段信息。当前只支持IA64 ELF的unwind段信息。

-d
--dynamic 显示动态段的信息。

-V
--version-info 显示版本段的信息。

-A
--arch-specific 显示CPU构架信息。

-D
--use-dynamic 使用动态段中的符号表显示符号,而不是使用符号段。

-x <number or name>
--hex-dump=<number or name> 以16进制方式显示指定段内内容。number指定段表中段的索引,或字符串指定文件中的段名。

-w[liaprmfFsoR] or
--debug-dump[=line,=info,=abbrev,=pubnames,=aranges,=macro,=frames,=frames-interp,=str,=loc,=Ranges] 显示调试段中指定的内容。

-I
--histogram 显示符号的时候,显示bucket list长度的柱状图。

-v
--version 显示readelf的版本信息。

-H
--help 显示readelf所支持的命令行选项。

-W
--wide 宽行输出。

@file 可以将选项集中到一个文件中,然后使用这个@file选项载入。

实例

  • 读取可执行文件形式的elf文件头信息:
1
readelf -h main 
  • 读取目标文件形式的elf文件头信息:
1
readelf -h myfile.o 
  • 读取静态库文件形式的elf文件头信息:
1
readelf -h libmy.a 
  • 读取动态库文件形式的elf文件头信息:
1
readelf -h libmy.so 
  • 查看可执行的elf文件程序头表信息:
1
readelf -l main 
  • 查看目标文件的elf文件程序头表信息:
1
readelf -l myfile.o 
  • 查看静态库文件的elf文件程序头表信息:
1
readelf -l libmy.a 
  • 查看动态库文件的elf文件程序头表信息:
1
readelf -l libmy.so 
  • 查看一个可执行的elf文件的节信息:
1
readelf -S main
  • 查看一个包含调试信息的可执行的elf文件的节信息:
1
readelf -S main.debug 
  • 查看一个目标文件的elf文件的节信息:
1
readelf -S myfile.o
  • 查看一个静态库文件的elf文件的节信息:
1
readelf -S libmy.a 
  • 查看一个动态库文件的elf文件的节信息:
1
readelf -S libmy.so 

参考:

readelf命令

在设置中添加:

微信截图_20210322145045.png

微信截图_20210322144935.png

模版内容:

1
2
3
4
5
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="">

</mapper>

微信截图_20210322145748.png

检验:

微信截图_20210322145835.png

使用注解的优势:
1.采用纯java代码,不在需要配置繁杂的xml文件
2.在配置中也可享受面向对象带来的好处
3.类型安全对重构可以提供良好的支持
4.减少复杂配置文件的同时亦能享受到springIoC容器提供的功能

启动注解@SpringBootApplication

  @SpringBootApplication 是一个复合注解,包含了 @SpringBootConfiguration@EnableAutoConfiguration@ComponentScan 这三个注解。

@SpringBootConfiguration注解,继承@Configuration注解,主要用于加载配置文件

  @SpringBootConfiguration@Configuration 二者功能一致,标注当前类是配置类, 并会将当前类内声明的一个或多个以 @Bean 注解标记的方法的实例纳入到 Spring 容器中,并且实例名就是方法名。

@Configuration:等同于 Spring 的XML配置文件;使用Java代码可以检查类型安全。

@EnableAutoConfiguration注解,开启自动配置功能

  @EnableAutoConfiguration可以帮助 SpringBoot 应用将所有符合条件的 @Configuration 配置都加载到当前 SpringBoot 创建并使用的IoC容器。借助于 Spring 框架原有的一个工具类:SpringFactoriesLoader 的支持,@EnableAutoConfiguration 可以智能的自动配置功效才得以大功告成

@ComponentScan注解,主要用于组件扫描和自动装配

  @ComponentScan 的功能其实就是自动扫描并加载符合条件的组件或bean定义,最终将这些bean定义加载到容器中。我们可以通过 basePackages 等属性指定 @ComponentScan 自动扫描的范围,如果不指定,则默认 Spring 框架实现从声明 @ComponentScan 所在类的 package 进行扫描,默认情况下是不指定的,所以 SpringBoot 的启动类最好放在 root package下。

Controller 相关注解

@Controller

用于定义控制器类,在spring项目中由控制器负责将用户发来的URL请求转发到对应的服务接口(service层),一般这个注解在类中,通常方法需要配合注解 @RequestMapping

@ResponseBody

@ResponseBody:表示该方法的返回结果直接写入 HTTP response body 中,一般在异步获取数据时使用,用于构建 RESTfulapi。在使用 @RequestMapping 后,返回值通常解析为跳转路径,加上 @Responsebody 后返回结果不会被解析为跳转路径,而是直接写入 HTTP response body 中。比如异步获取json数据,加上 @Responsebody 后,会直接返回json数据。该注解一般会配合@RequestMapping一起使用。

@RestController 复合注解

用于标注控制层组件(如struts中的action),@ResponseBody@Controller 的合集,@RestController 效果是将方法返回的对象直接在浏览器上展示成json格式。

@RequestBody

通过 HttpMessageConverter 读取 Request Body 并反序列化为 Object 对象。

使用 @RequestBody 接收数据时,前端不能使用GET方式提交数据,而是用POST方式进行提交。

@RequestMapping

@RequestMapping 提供路由信息,负责URL到Controller中的具体函数的映射,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。@RequestMapping 用在类上可以没有,但是用在方法上必须有。

@GetMapping

HTTP Get 请求映射到特定处理程序的方法注解。

1
@RequestMapping(value = "/go",method = RequestMethod.GET) 等价于:@GetMapping(value = "/go")

@PostMapping

HTTP Post 请求映射到特定处理程序的方法注解。

1
@RequestMapping(value = "/go",method = RequestMethod.POST) 等价于:@PostMapping(value = "/go")

请求参数值

@PathVariable

@PathVariable:接收请求路径中占位符的值。

注意:@RequestMapping@PathVariable 中的值必须保持一致。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* 占位符映射
* 语法:@RequestMapping(value=”user/{userId}/{userName}”)
* 请求路径:http://localhost:8080/springboot/show/1/wang
* @param ids
* @param names
* @return
*/
@RequestMapping("show/{id}/{name}")
public ModelAndView test(@PathVariable("id") Long ids ,@PathVariable("name") String names){
ModelAndView mv = new ModelAndView();
mv.addObject("msg","占位符映射:id:"+ids+";name:"+names);
mv.setViewName("hello");
return mv;
}

@RequestParam

@RequestParam:获取请求参数的值

常用来处理简单类型的绑定,通过 Request.getParameter() 获取的 String 可直接转换为简单类型的情况(String–> 简单类型的转换操作由 ConversionService 配置的转换器来完成);因为使用 request.getParameter() 方式获取参数,所以可以处理 get 方式中queryString的值,也可以处理 post方式中 body data 的值;

1
2
3
4
5
6
// 请求示例:/getUser?uid=123
@RequestMapping("/getUser")
public String getUser(@RequestParam("uid")Integer id, Model model) {
System.out.println("id:"+id);
return "user";
}

@RequestHeader

Request 请求 header 部分的值绑定到方法的参数上

1
2
3
4
5

@RequestMapping("/test1")  
public void test1(@RequestHeader("Accept-Encoding") String encoding, 
@RequestHeader("Keep-Alive") long keepAlive)  {  
}

@CookieValue

Request header 中关于 cookie 的值绑定到方法的参数上

1
2
3
@RequestMapping("/test1")  
public void test1(@CookieValue("UserInfo") String cookie) {
}

注入bean

@Repository

@Repository:使用 @Repository 注解可以确保 DAO 或者 repositories 提供异常转译,这个注解修饰的 DAO 或者repositories类会被 ComponetScan 发现并配置,同时也不需要为它们提供XML配置项。

@Service

  • @Service@Component 注解的一个特例,作用在类上
  • @Service 注解作用域默认为单例
  • 使用注解配置和类路径扫描时,被 @Service 注解标注的类会被 Spring 扫描并注册为 Bean
  • @Service 用于标注服务层组件,表示定义一个 bean
  • @Service 使用时没有传参数,Bean 名称默认为当前类的类名,首字母小写
  • @Service("serviceBeanId")@Service(value="serviceBeanId") 使用时传参数,使用 value 作为 Bean 名字

@Scope作用域

@Scope 作用在类上和方法上,用来配置 spring bean 的作用域,它标识 bean 的作用域

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public  Scope {

/**
* Alias for {@link #scopeName}.
* @see #scopeName
*/

String value() default "";


String scopeName() default "";

ScopedProxyMode proxyMode() default ScopedProxyMode.DEFAULT;
}

属性介绍

value

  • singleton 表示该bean是单例的。(默认)
  • prototype 表示该bean是多例的,即每次使用该bean时都会新建一个对象。
  • request 在一次http请求中,一个bean对应一个实例。
  • session 在一个httpSession中,一个bean对应一个实例。

proxyMode

  • DEFAULT 不使用代理。(默认)
  • NO 不使用代理,等价于DEFAULT。
  • INTERFACES 使用基于接口的代理(jdk dynamic proxy)。
  • TARGET_CLASS 使用基于类的代理(cglib)。

@Entity

@Table(name=""):表明这是一个实体类,必须与 @Id 注解 结合使用,否则 No identifier specified for entity:。一般用于jpa这两个注解一般一块使用,但是如果表名和实体类名相同的话,@Table可以省略。
@Table(name ="数据库表名"),这个注解也注释在实体类上,对应数据库中相应的表。
@Id@Column 注解用于标注实体类中的字段,pk字段标注为 @Id,其余 @Column

@Data

导入依赖:lombok.Data ,

1
2
3
4
5
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.10</version>
</dependency>

@Data: 注解在类上, 为类提供读写属性, 此外还提供了 equals()hashCode()toString() 方法。

@Bean产生一个bean的方法

@Bean 明确告诉方法,产生一个 Bean 对象,并且交给 Spring 容器管理。支持别名 @Bean("xx-name"),产生这个 Bean 对象的方法 Spring 只会调用一次,随后这个 Spring 将会将这个 Bean 对象放在自己的IOC容器中。

@Autowired 自动导入

  • @Autowired 注解作用在构造函数、方法、方法参数、类字段以及注解上
  • @Autowired 注解可以实现Bean的自动注入

@Component

泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。

把普通 pojo 实例化到 spring 容器中。

导入配置文件

@PropertySource导入属性

1
2
3
4
5
// 引入单个properties文件:
@PropertySource(value = {"classpath : xxxx/xxx.properties"})

// 引入多个properties文件:
@PropertySource(value = {"classpath : xxxx/xxx.properties","classpath : xxxx.properties"})

@ImportResource导入xml配置文件

可以额外分为两种模式 相对路径classpath绝对路径file
注意:单文件可以不写 valuelocationsvaluelocations都可用

相对路径(classpath)

  • 引入单个xml配置文件:@ImportSource("classpath : xxx/xxxx.xml")
  • 引入多个xml配置文件:@ImportSource(locations={"classpath : xxxx.xml" , "classpath : yyyy.xml"})

绝对路径(file)

  • 引入单个xml配置文件:@ImportSource(locations= {"file : d:/hellxz/dubbo.xml"})
  • 引入多个xml配置文件:@ImportSource(locations= {"file : d:/hellxz/application.xml" , "file : d:/hellxz/dubbo.xml"})

取值:使用 @Value 注解取配置文件中的值

1
2
@Value("${properties中的键}")
private String xxx;`

@Import 导入额外的配置信息

功能类似XML配置的,用来导入配置类,可以导入带有 @Configuration 注解的配置类或实现了 ImportSelector/ImportBeanDefinitionRegistrar

1
2
3
4
5
6
7
@SpringBootApplication
@Import({SysConfig.class})
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}

事务注解 @Transactional

在Spring中,事务有两种实现方式,分别是编程式事务管理和声明式事务管理两种方式

  • 编程式事务管理: 编程式事务管理使用TransactionTemplate或者直接使用底层的PlatformTransactionManager。对于编程式事务管理,spring推荐使用TransactionTemplate。

  • 声明式事务管理: 建立在AOP之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务,通过@Transactional就可以进行事务操作,更快捷而且简单。推荐使用

全局异常处理

@ControllerAdvice 统一处理异常

@ControllerAdvice 注解定义全局异常处理类

1
2
3
@ControllerAdvice
public class GlobalExceptionHandler {
}

@ExceptionHandler 注解声明异常处理方法

1
2
3
4
5
6
7
8
9
@ControllerAdvice
public class GlobalExceptionHandler {

@ExceptionHandler(Exception.class)
@ResponseBody
String handleException(){
return "Exception Deal!";
}
}

参考:

spring boot注解@RequestMapping、@RequestBody的详解

SpringBoot注解最全详解(整合超详细版本)

Spring Boot 常用注解汇总

下载

下载:https://maven.apache.org/download.cgi

微信截图_20210318093326.png

安装和配置环境变量

下载完成,解压 E:\java\apache-maven-3.6.3 (需要选择路径)。

添加 系统变量MAVEN_HOME=E:\java\apache-maven-3.6.3
修改系统变量 PathPath = %MAVEN_HOME%\bin

如图:

MAVEN_HOME:

微信截图_20210318094904.png

Path:

微信截图_20210318093938.png

cmd 输入 mvn -version,输出:

微信截图_20210318094339.png

配置settings文件

找到 E:\java\apache-maven-3.6.3\conf\settings.xml 文件,定位到第52行,这里是maven默认的仓库。

微信截图_20210318095342.png

修改localRepository:

<localRepository>E:/java/maven-repository</localRepository>

微信截图_20210318101139.png

修改成阿里云镜像服务器

微信截图_20210318101320.png

配置jdk

微信截图_20210318101409.png

检测配置结果

cmd 输入:mvn help:system 测试:

微信截图_20210318101541.png

微信截图_20210318101755.png

settings.xml 内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
<?xml version="1.0" encoding="UTF-8"?>

<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
<localRepository>E:/java/maven-repository</localRepository>
<!-- localRepository
| The path to the local repository maven will use to store artifacts.
|
| Default: ${user.home}/.m2/repository
<localRepository>/path/to/local/repo</localRepository>
-->

<!-- pluginGroups
| This is a list of additional group identifiers that will be searched when resolving plugins by their prefix, i.e.
| when invoking a command line like "mvn prefix:goal". Maven will automatically add the group identifiers
| "org.apache.maven.plugins" and "org.codehaus.mojo" if these are not already contained in the list.
|-->
<pluginGroups>
<!-- pluginGroup
| Specifies a further group identifier to use for plugin lookup.
<pluginGroup>com.your.plugins</pluginGroup>
-->
</pluginGroups>

<!-- proxies
| This is a list of proxies which can be used on this machine to connect to the network.
| Unless otherwise specified (by system property or command-line switch), the first proxy
| specification in this list marked as active will be used.
|-->
<proxies>
<!-- proxy
| Specification for one proxy, to be used in connecting to the network.
|
<proxy>
<id>optional</id>
<active>true</active>
<protocol>http</protocol>
<username>proxyuser</username>
<password>proxypass</password>
<host>proxy.host.net</host>
<port>80</port>
<nonProxyHosts>local.net|some.host.com</nonProxyHosts>
</proxy>
-->
</proxies>

<!-- servers
| This is a list of authentication profiles, keyed by the server-id used within the system.
| Authentication profiles can be used whenever maven must make a connection to a remote server.
|-->
<servers>
<!-- server
| Specifies the authentication information to use when connecting to a particular server, identified by
| a unique name within the system (referred to by the 'id' attribute below).
|
| NOTE: You should either specify username/password OR privateKey/passphrase, since these pairings are
| used together.
|
<server>
<id>deploymentRepo</id>
<username>repouser</username>
<password>repopwd</password>
</server>
-->

<!-- Another sample, using keys to authenticate.
<server>
<id>siteServer</id>
<privateKey>/path/to/private/key</privateKey>
<passphrase>optional; leave empty if not used.</passphrase>
</server>
-->
</servers>

<!-- mirrors
| This is a list of mirrors to be used in downloading artifacts from remote repositories.
|
| It works like this: a POM may declare a repository to use in resolving certain artifacts.
| However, this repository may have problems with heavy traffic at times, so people have mirrored
| it to several places.
|
| That repository definition will have a unique id, so we can create a mirror reference for that
| repository, to be used as an alternate download site. The mirror site will be the preferred
| server for that repository.
|-->
<mirrors>
<!-- mirror
| Specifies a repository mirror site to use instead of a given repository. The repository that
| this mirror serves has an ID that matches the mirrorOf element of this mirror. IDs are used
| for inheritance and direct lookup purposes, and must be unique across the set of mirrors.
|
<mirror>
<id>mirrorId</id>
<mirrorOf>repositoryId</mirrorOf>
<name>Human Readable Name for this Mirror.</name>
<url>http://my.repository.com/repo/path</url>
</mirror>
-->
<!-- 阿里云仓库 开始-->
<mirror>
<id>alimaven</id>
<mirrorOf>central</mirrorOf>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/repositories/central/</url>
</mirror>
<!--或者
<mirror>
<id>nexus-aliyun</id>
<mirrorOf>*</mirrorOf>
<name>Nexus aliyun</name>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>
-->
<!-- 阿里云仓库 结束-->
</mirrors>

<!-- profiles
| This is a list of profiles which can be activated in a variety of ways, and which can modify
| the build process. Profiles provided in the settings.xml are intended to provide local machine-
| specific paths and repository locations which allow the build to work in the local environment.
|
| For example, if you have an integration testing plugin - like cactus - that needs to know where
| your Tomcat instance is installed, you can provide a variable here such that the variable is
| dereferenced during the build process to configure the cactus plugin.
|
| As noted above, profiles can be activated in a variety of ways. One way - the activeProfiles
| section of this document (settings.xml) - will be discussed later. Another way essentially
| relies on the detection of a system property, either matching a particular value for the property,
| or merely testing its existence. Profiles can also be activated by JDK version prefix, where a
| value of '1.4' might activate a profile when the build is executed on a JDK version of '1.4.2_07'.
| Finally, the list of active profiles can be specified directly from the command line.
|
| NOTE: For profiles defined in the settings.xml, you are restricted to specifying only artifact
| repositories, plugin repositories, and free-form properties to be used as configuration
| variables for plugins in the POM.
|
|-->
<profiles>
<profile>
<id>jdk-1.8</id>

<activation>
<activeByDefault>true</activeByDefault>
<jdk>1.8</jdk>
</activation>

<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
</properties>
</profile>
</profiles>

<!-- activeProfiles
| List of profiles that are active for all builds.
|
<activeProfiles>
<activeProfile>alwaysActiveProfile</activeProfile>
<activeProfile>anotherAlwaysActiveProfile</activeProfile>
</activeProfiles>
-->
</settings>

IDEA配置Maven

微信截图_20210318102733.png

  网关(Gateway)又称网间连接器、协议转换器。网关在网络层以上实现网络互连,是复杂的网络互连设备,仅用于两个高层协议不同的网络互连。网关既可以用于广域网互连,也可以用于局域网互连。 网关是一种充当转换重任的计算机系统或设备。使用在不同的通信协议、数据格式或语言,甚至体系结构完全不同的两种系统之间,网关是一个翻译器。与网桥只是简单地传达信息不同,网关对收到的信息要重新打包,以适应目的系统的需求。

  由于历史的原因,许多有关TCP/IP的文献曾经把网络层使用的路由器称为网关,在今天很多局域网采用都是路由来接入网络,因此通常指的网关就是路由器的IP。

  在OSI中,网关有两种:一种是面向连接的网关,一种是无连接的网关。当两个子网之间有一定距离时,往往将一个网关分成两半,中间用一条链路连接起来,我们称之为半网关。

  按照不同的分类标准,网关也有很多种。TCP/IP协议里的网关是最常用的,在这里我们所讲的 网关 均指TCP/IP协议下的网关。

  网关实质上是一个网络通向其他网络的IP地址。比如有网络A和网络B,网络A的IP地址范围为 192.168.1.1~192. 168.1.254,子网掩码为 255.255.255.0 ;网络B的IP地址范围为 192.168.2.1~192.168.2.254 ,子网掩码为 255.255.255.0 。在没有路由器的情况下,两个网络之间是不能进行 TCP/IP 通信的,即使是两个网络连接在同一台交换机(或集线器)上,TCP/IP协议也会根据子网掩码(255.255.255.0)与主机的IP 地址作 运算的结果不同判定两个网络中的主机处在不同的网络里。而要实现这两个网络之间的通信,则必须通过网关。如果网络A中的主机发现数据包的目的主机不在本地网络中,就把数据包转发给它自己的网关,再由网关转发给网络B的网关,网络B的网关再转发给网络B的某个主机。网络A向网络B转发数据包的过程。

  只有设置好网关的IP地址,TCP/IP 协议才能实现不同网络之间的相互通信。网关的IP地址是具有路由功能的设备的IP地址,具有路由功能的设备有路由器、启用了路由协议的服务器(实质上相当于一台路由器)、代理服务器(也相当于一台路由器)。

  在和 Novell NetWare 网络交互操作的上下文中,网关在 Windows 网络中使用的服务器信息块 (SMB) 协议以及NetWare网络使用的 NetWare 核心协议 (NCP) 之间起着桥梁的作用。网关也被称为 IP路由器。

192.168.1.53/27,快速计算公式:

  • 1,用32减去掩码长度:32-27 =5
  • 2,计算每个子网段的步长(Step):2^5= 32
  • 3,每个子网段的前缀(Prefix)= 192.168.1
  • 4,每个子网段的起始地址为步长32的整数倍:0、32、64、96、128、160、192、224

看看53落在上述哪两个数中间?显然落在32与64之间,那么这个IP的网络ID = 192.168.1.32
广播ID = 192.168.1.63, 63 =64-1,这里的64是下一个网络ID的起始地址,比它小1即为前一个网段的广播地址。

192.168.129.53/18,问它的网段的起始IP、广播IP

  • 1,用24减去掩码长度:24-18 = 6
  • 2,计算步长:2^6= 64
  • 3,每个子网段的前缀(Prefix)= 192.168
  • 4,每个子网段的起始地址为步长64的整数倍:0、64、128、192

看看129落在上述哪两个数中间?显然落在128与192之间,那么这个IP的网络ID = 192.168.128.0
广播ID = 192.168.191.255

32,24,16 是根据掩码长度确定的。

参考:

如何快速算出192.168.1.53/27的广播地址?

转载:

云网络丢包故障定位全景指南

硬件网卡丢包

Ring Buffer溢出

640.png

如图所示,物理介质上的数据帧到达后首先由NIC(网络适配器)读取,写入设备内部缓冲区 Ring Buffer中,再由中断处理程序触发 Softirq 从中消费,Ring Buffer 的大小因网卡设备而异。当网络数据包到达(生产)的速率快于内核处理(消费)的速率时,Ring Buffer 很快会被填满,新来的数据包将被丢弃;

  1. 查看:

通过 ethtool 或 /proc/net/dev 可以查看因 Ring Buffer 满而丢弃的包统计,在统计项中,以fifo标识:

1
2
3
4
5
6
7
8
$ ethtool -S eth0|grep rx_fifo
rx_fifo_errors: 0

$ cat /proc/net/dev
Inter-| Receive | Transmit
face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed
eth0: 3623955871 24771436 0 0 0 0 0 0 1876696873 11380645 0 0 0 0 0 0
lo: 5324832 115757 0 0 0 0 0 0 5324832 115757 0 0 0 0 0 0
  1. 查看eth0网卡Ring Buffer最大值和当前设置
1
ethtool -g eth0
  1. 解决方案:修改网卡eth0接收与发送硬件缓存区大小
1
ethtool -G eth0 rx 4096 tx 4096

网卡端口协商丢包

  1. 查看网卡丢包统计:ethtool -S eth0

640-1.png

  1. 查看网卡配置状态:ethtool eth0

640.webp

主要查看网卡和上游网络设备协商速率和模式是否符合预期;

解决方案:

  1. 重新自协商:ethtool -r eth0;
  2. 如果上游不支持自协商,可以强制设置端口速率:
1
ethtool -s eth0 speed 1000 duplex full autoneg off

网卡流控丢包

  1. 查看流控统计:
1
ethtool -S eth1 | grep control

640-2.png

rx_flow_control_xon 是在网卡的 RX Buffer 满或其他网卡内部的资源受限时,给交换机端口发送的开启流控的pause帧计数。对应的,tx_flow_control_xoff 是在资源可用之后发送的关闭流控的pause帧计数。

  1. 查看网络流控配置:ethtool -a eth1

640-3.png

  1. 解决方案:关闭网卡流控
1
2
3
ethtool -A ethx autoneg off  # 自协商关闭
ethtool -A ethx tx off # 发送模块关闭
ethtool -A ethx rx off # 接收模块关闭

报文mac地址丢包

一般计算机网卡都工作在非混杂模式下,此时网卡只接受来自网络端口的目的地址指向自己的数据,如果报文的目的mac地址不是对端的接口的mac地址,一般都会丢包,一般这种情况很有可能是源端设置静态arp表项或者动态学习的arp表项没有及时更新,但目的端mac地址已发生变化(换了网卡),没有更新通知到源端(比如更新报文被丢失,中间交换机异常等情况);

查看:

  1. 目的端抓包,tcpdump可以开启混杂模式,可以抓到对应的报文,然后查看mac地址;
  2. 源端查看arp表或者抓包(上一跳设备),看发送的mac地址是否和下一跳目的端的mac地址一致;

解决方案:

  1. 刷新arp表然后发包触发arp重新学习(可能影响其他报文,增加延时,需要小心操作);
  2. 可以在源端手动设置正确的静态的arp表项;

其他网卡异常丢包

这类异常比少见,但如果都不是上面哪些情况,但网卡统计里面仍然有丢包计数,可以试着排查一下:

网卡firmware版本:

排查一下网卡phy芯片firmware是不是有bug,安装的版本是不是符合预期,查看 ethtool -i eth1:

eth1:

640-4.png

和厂家提case询问是不是已知问题,有没有新版本等;

网线接触不良:

如果网卡统计里面存在crc error 计数增长,很可能是网线接触不良,可以通知网管排查一下:

1
ethtool -S eth0

640-1.webp

解决方案:一般试着重新插拔一下网线,或者换一根网线,排查插口是否符合端口规格等;

报文长度丢包

网卡有接收正确报文长度范围,一般正常以太网报文长度范围:64-1518,发送端正常情况会填充或者分片来适配,偶尔会发生一些异常情况导致发送报文不正常丢包;

查看:

1
ethtool -S eth1|grep length_errors

640-2.webp

解决方案:

1 调整接口MTU配置,是否开启支持以太网巨帧;

2 发送端开启PATH MTU进行合理分片;

简单总结一下网卡丢包:

640-3.webp

网卡驱动丢包

查看:ifconfig eth1/eth0 等接口

640-5.png

  1. RX errors: 表示总的收包的错误数量,还包括too-long-frames错误,Ring Buffer 溢出错误,crc 校验错误,帧同步错误,fifo overruns 以及 missed pkg 等等。
  2. RX dropped: 表示数据包已经进入了 Ring Buffer,但是由于内存不够等系统原因,导致在拷贝到内存的过程中被丢弃。
  3. RX overruns: 表示了 fifo 的 overruns,这是由于 Ring Buffer(aka Driver Queue) 传输的 IO 大于 kernel 能够处理的 IO 导致的,而 Ring Buffer 则是指在发起 IRQ 请求之前的那块 buffer。很明显,overruns 的增大意味着数据包没到 Ring Buffer 就被网卡物理层给丢弃了,而 CPU 无法即使的处理中断是造成 Ring Buffer 满的原因之一,上面那台有问题的机器就是因为 interruprs 分布的不均匀(都压在 core0),没有做 affinity 而造成的丢包。
  4. RX frame: 表示 misaligned 的 frames。
  5. 对于 TX 的来说,出现上述 counter 增大的原因主要包括 aborted transmission, errors due to carrirer, fifo error, heartbeat erros 以及 windown error,而 collisions 则表示由于 CSMA/CD 造成的传输中断。

驱动溢出丢包

netdev_max_backlog 是内核从NIC(网卡(Network Interface Card,简称NIC),也称网络适配器)收到包后,交由协议栈(如IP、TCP)处理之前的缓冲队列。每个CPU核都有一个backlog队列,与 Ring Buffer 同理,当接收包的速率大于内核协议栈处理的速率时,CPU的backlog队列不断增长,当达到设定的 netdev_max_backlog 值时,数据包将被丢弃。

查看:

通过查看 /proc/net/softnet_stat 可以确定是否发生了 netdev backlog 队列溢出:

640-6.png

其中:每一行代表每个CPU核的状态统计,从CPU0依次往下;每一列代表一个CPU核的各项统计:第一列代表中断处理程序收到的包总数;第二列即代表由于 netdev_max_backlog 队列溢出而被丢弃的包总数。从上面的输出可以看出,这台服务器统计中,并没有因为 netdev_max_backlog 导致的丢包。

解决方案:

netdev_max_backlog 的默认值是 1000,在高速链路上,可能会出现上述第二统计不为0的情况,可以通过修改内核参数 net.core.netdev_max_backlog 来解决:

1
sysctl -w net.core.netdev_max_backlog=2000

单核负载高导致丢包

单核CPU软中断占有高, 导致应用没有机会收发或者收包比较慢,即使调整 netdev_max_backlog 队列大小仍然会一段时间后丢包,处理速度跟不上网卡接收的速度;

查看:mpstat -P ALL 1

640-7.png

单核软中断占有100%,导致应用没有机会收发或者收包比较慢而丢包;

解决方案:

  1. 调整网卡RSS队列配置:

查看:ethtool -x ethx
调整:ethtool -X ethx xxxx

  1. 看一下网卡中断配置是否均衡 cat /proc/interrupts

调整:

1
2
3
4
5
6
7
8
# 1) irqbalance 调整;
# 查看当前运行情况
service irqbalance status
# 终止服务
service irqbalance stop

# 2) 中断绑CPU核
echo mask > /proc/irq/xxx/smp_affinity
  1. 根据CPU和网卡队列个数调整网卡多队列和RPS配置

-CPU大于网卡队列个数:

查看网卡队列 ethtool -x ethx

协议栈开启RPS并设置RPS;

1
2
echo $mask(CPU配置)> /sys/class/net/$eth/queues/rx-$i/rps_cpus
echo 4096(网卡buff)> /sys/class/net/$eth/queues/rx-$i/rps_flow_cnt

2)CPU小于网卡队列个数,绑中断就可以,可以试着关闭RPS看一下效果:

echo 0 > /sys/class/net/<dev>/queues/rx-<n>/rps_cpus

4.numa CPU 调整,对齐网卡位置,可以提高内核处理速度,从而给更多CPU给应用收包,减缓丢包概率;

查看网卡numa位置:

1
2
ethtool -i eth1|grep bus-info
lspci -s bus-info -vv|grep node

上面中断和RPS设置里面mask需要重新按numa CPU分配重新设置;

5.可以试着开启中断聚合(看网卡是否支持)

查看 :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
ethtool -c ethx
Coalesce parameters for eth1:
Adaptive RX: on TX: on
stats-block-usecs: 0
sample-interval: 0
pkt-rate-low: 0
pkt-rate-high: 0

rx-usecs: 25
rx-frames: 0
rx-usecs-irq: 0
rx-frames-irq: 256

tx-usecs: 25
tx-frames: 0
tx-usecs-irq: 0
tx-frames-irq: 256

rx-usecs-low: 0
rx-frame-low: 0
tx-usecs-low: 0
tx-frame-low: 0

rx-usecs-high: 0
rx-frame-high: 0
tx-usecs-high: 0
tx-frame-high: 0

调整:

1
ethtool -C ethx adaptive-rx on

简单总结一下网卡驱动丢包处理:

640-8.png

内核协议栈丢包

以太网链路层丢包

neighbor 系统arp丢包

arp_ignore 配置丢包

arp_ignore 参数的作用是控制系统在收到外部的arp请求时,是否要返回arp响应。arp_ignore 参数常用的取值主要有 0,1,2,3~8 较少用到;

查看:sysctl -a|grep arp_ignore

640-9.png

解决方案:根据实际场景设置对应值;

  • 0:响应任意网卡上接收到的对本机IP地址的arp请求(包括环回网卡上的地址),而不管该目的IP是否在接收网卡上。
  • 1:只响应目的IP地址为接收网卡上的本地地址的arp请求。
  • 2:只响应目的IP地址为接收网卡上的本地地址的arp请求,并且arp请求的源IP必须和接收网卡同网段。
  • 3:如果ARP请求数据包所请求的IP地址对应的本地地址其作用域(scope)为主机(host),则不回应ARP响应数据包,如果作用域为全局(global)或链路(link),则回应ARP响应数据包。

640-10.png

640-11.png

arp_filter配置丢包

在多接口系统里面(比如腾讯云的弹性网卡场景),这些接口都可以回应arp请求,导致对端有可能学到不同的mac地址,后续报文发送可能由于mac地址和接收报文接口mac地址不一样而导致丢包,arp_filter主要是用来适配这种场景;

查看:sysctl -a | grep arp_filter

640-14.png

解决方案:

根据实际场景设置对应的值,一般默认是关掉此过滤规则,特殊情况可以打开;
0:默认值,表示回应arp请求的时候不检查接口情况;
1:表示回应arp请求时会检查接口是否和接收请求接口一致,不一致就不回应;

arp表满导致丢包

比如下面这种情况,由于突发arp表项很多 超过协议栈默认配置,发送报文的时候部分arp创建失败,导致发送失败,从而丢包:

640-12.png

查看:

  1. 查看arp状态:cat /proc/net/stat/arp_cache ,table_fulls 统计:

640-4.webp

  1. 查看dmesg消息(内核打印):
1
2
dmesg|grep neighbour
neighbour: arp_cache: neighbor table overflow!
  1. 查看当前arp表大小:ip n|wc -l

查看系统配额:

1
2
3
4
5
sysctl -a |grep net.ipv4.neigh.default.gc_thresh
gc_thresh1:存在于ARP高速缓存中的最少层数,如果少于这个数,垃圾收集器将不会运行。缺省值是128。

gc_thresh2 :保存在 ARP 高速缓存中的最多的记录软限制。垃圾收集器在开始收集前,允许记录数超过这个数字 5 秒。缺省值是 512。
gc_thresh3 :保存在 ARP 高速缓存中的最多记录的硬限制,一旦高速缓存中的数目高于此,垃圾收集器将马上运行。缺省值是1024。

一般在内存足够情况下,可以认为 gc_thresh3 值是arp 表总大小;

640-5.webp

解决方案:根据实际arp最大值情况(比如访问其他子机最大个数),调整arp表大小

1
2
3
4
sudo sysctl -w net.ipv4.neigh.default.gc_thresh1=1024
sudo sysctl -w net.ipv4.neigh.default.gc_thresh2=2048
sudo sysctl -w net.ipv4.neigh.default.gc_thresh3=4096
sudo sysctl -p

arp请求缓存队列溢出丢包

查看:

1
2
# unresolved_discards是否有新增计数
cat /proc/net/stat/arp_cache

解决方案:根据客户需求调整缓存队列大小 unres_qlen_bytes

sysctl -a | grep unres_qlen_bytes

640-13.png

网络IP层丢包

接口ip地址配置丢包

  1. 本机服务不通,检查lo接口有没有配置地址是 127.0.0.1;
  2. 本机接收失败, 查看local路由表:ip r show table local | grep 子机ip地址;这种丢包一般会出现在多IP场景,子机底层配置多ip失败,导致对应ip收不到包而丢包;

640-6.webp

解决方案:

  1. 配置正确接口ip地址;比如 ip a add 1.1.1.1 dev eth0
  2. 如果发现接口有地址还丢包,可能是local路由表没有对应条目,紧急情况下,可以用手工补上:
    比如 ip r add local 本机ip地址 dev eth0 table local

路由丢包

路由配置丢包

查看:

  1. 查看配置 路由是否设置正确(是否可达),是否配置策略路由(在弹性网卡场景会出现此配置)ip rule

640-7.webp

然后找到对应路由表。查看路由表:

640-15.png

或者直接用 ip r get x.x.x.x,让系统帮你查找是否存在可达路由,接口是否符合预期;

  1. 查看系统统计信息:
1
netstat -s|grep "dropped because of missing route"

解决方案:重新配置正确的路由;

反向路由过滤丢包

反向路由过滤机制是Linux通过反向路由查询,检查收到的数据包源IP是否可路由(Loose mode)、是否最佳路由(Strict mode),如果没有通过验证,则丢弃数据包,设计的目的是防范IP地址欺骗攻击。

查看:

rp_filter 提供三种模式供配置:

  • 0 - 不验证
  • 1 - RFC3704定义的严格模式:对每个收到的数据包,查询反向路由,如果数据包入口和反向路由出口不一致,则不通过
  • 2 - RFC3704定义的松散模式:对每个收到的数据包,查询反向路由,如果任何接口都不可达,则不通过

查看当前 rp_filter 策略配置:

cat /proc/sys/net/ipv4/conf/eth0/rp_filter

如果这里设置为1,就需要查看主机的网络环境和路由策略是否可能会导致客户端的入包无法通过反向路由验证了。

从原理来看这个机制工作在网络层,因此,如果客户端能够Ping通服务器,就能够排除这个因素了。

解决方案:

根据实际网络环境将rp_filter设置为 0 或 2:

1
2
3
sysctl -w net.ipv4.conf.all.rp_filter=2
# 或
sysctl -w net.ipv4.conf.eth0.rp_filter=2

防火墙丢包

客户设置规则导致丢包

查看:

iptables -nvL |grep DROP

解决方案:修改防火墙规则;

连接跟踪导致丢包

连接跟踪表溢出丢包

kernel 用 ip_conntrack 模块来记录 iptables 网络包的状态,并把每条记录保存到 table 里(这个 table 在内存里,可以通过 /proc/net/ip_conntrack 查看当前已经记录的总数),如果网络状况繁忙,比如高连接,高并发连接等会导致逐步占用这个 table 可用空间,一般这个 table 很大不容易占满并且可以自己清理,table 的记录会一直呆在 table 里占用空间直到源 IP 发一个 RST 包,但是如果出现被攻击、错误的网络配置、有问题的路由/路由器、有问题的网卡等情况的时候,就会导致源 IP 发的这个 RST 包收不到,这样就积累在 table 里,越积累越多直到占满。无论,哪种情况导致table变满,满了以后就会丢包,出现外部无法连接服务器的情况。内核会报如下错误信息:kernel: ip_conntrack: table full, dropping packet

查看当前连接跟踪数 :

cat /proc/sys/net/netfilter/nf_conntrack_max

解决方案:

1
2
3
4
5
6
7
# 增大跟踪的最大条数
net.netfilter.nf_conntrack_max = 3276800

# 减少跟踪连接的最大有效时间
net.netfilter.nf_conntrack_tcp_timeout_established = 1200
net.netfilter.nf_conntrack_udp_timeout_stream = 180
net.netfilter.nf_conntrack_icmp_timeout = 30

ct创建冲突失导致丢包

查看:当前连接跟踪统计:cat /proc/net/stat/nf_conntrack,可以查各种ct异常丢包统计

640-16.png

解决方案:内核热补丁修复或者更新内核版本(合入补丁修改);

传输层UDP/TCP丢包

tcp 连接跟踪安全检查丢包

丢包原因:由于连接没有断开,但服务端或者client之前出现过发包异常等情况(报文没有经过连接跟踪模块更新窗口计数),没有更新合法的 window 范围,导致后续报文安全检查被丢包;协议栈用 nf_conntrack_tcp_be_liberal 来控制这个选项:

  • 1:关闭,只有不在tcp窗口内的rst包被标志为无效;
  • 0:开启; 所有不在tcp窗口中的包都被标志为无效;

查看:

查看配置 :

1
2
sysctl -a|grep nf_conntrack_tcp_be_liberal 
net.netfilter.nf_conntrack_tcp_be_liberal = 1

查看log:
一般情况下 netfiler 模块默认没有加载log,需要手动加载;

1
2
modprobe ipt_LOG11
sysctl -w net.netfilter.nf_log.2=ipt_LOG

然后发包后在查看syslog;

解决方案:根据实际抓包分析情况判断是不是此机制导致的丢包,可以试着关闭试一下;

分片重组丢包

情况总结:超时

查看:

1
2
netstat -s|grep timeout
601 fragments dropped after timeout

解决方法:调整超时时间

1
2
net.ipv4.ipfrag_time = 30
sysctl -w net.ipv4.ipfrag_time=60

frag_high_thresh, 分片的内存超过一定阈值会导致系统安全检查丢包

查看:

1
2
netstat -s|grep reassembles
8094 packet reassembles failed

解决方案:调整大小

1
2
net.ipv4.ipfrag_high_thresh 
net.ipv4.ipfrag_low_thresh

分片安全距检查离丢包

查看:

1
2
netstat -s|grep reassembles
8094 packet reassembles failed

解决方案: 把 ipfrag_max_dist 设置为0,就关掉此安全检查

640-17.png

pfrag_max_dist 特性,在一些场景下其实并不适用:

  1. 有大量的网络报文交互
  2. 发送端的并发度很高,同时SMP架构,导致很容易造成这种乱序情况;

分片 hash bucket 冲突链太长超过系统默认值128

查看:

1
2
dmesg|grep "Dropping fragment"
inet_frag_find: Fragment hash bucket 128 list length grew over limit. Dropping fragment.

解决方案:热补丁调整hash大小;

系统内存不足,创建新分片队列失败

查看方法:

1
2
netstat -s|grep reassembles
8094 packet reassembles failed

dropwatch查看丢包位置 :

640-18.png

解决方案:

  1. 增大系统网络内存:
1
2
3
net.core.rmem_default 
net.core.rmem_max
net.core.wmem_default
  1. 系统回收内存:

紧急情况下,可以用 /proc/sys/vm/drop_caches, 去释放一下虚拟内存;

1
2
3
4
5
6
7
8
# To free pagecache:
echo 1 > /proc/sys/vm/drop_caches

# To free dentries and inodes:
echo 2 > /proc/sys/vm/drop_caches

# To free pagecache, dentries and inodes:
echo 3 > /proc/sys/vm/drop_caches

MTU丢包

640-19.png

查看:

  1. 检查接口MTU配置,ifconfig eth1/eth0,默认是1500;
  2. 进行MTU探测,然后设置接口对应的MTU值;

解决方案:

  1. 根据实际情况,设置正确 MTU 值;
  2. 设置合理的 tcp mss,启用 TCP MTU Probe:
1
2
3
4
5
6
cat /proc/sys/net/ipv4/tcp_mtu_probing
tcp_mtu_probing - INTEGER Controls TCP Packetization-Layer Path MTU Discovery.
Takes three values:
0 - Disabled
1 - Disabled by default, enabled when an ICMP black hole detected
2 - Always enabled, use initial MSS of tcp_base_mss.

tcp层丢包

TIME_WAIT 过多丢包

大量 TIMEWAIT 出现,并且需要解决的场景,在高并发短连接的TCP服务器上,当服务器处理完请求后立刻按照主动正常关闭连接。。。这个场景下,会出现大量socket处于TIMEWAIT状态。如果客户端的并发量持续很高,此时部分客户端就会显示连接不上;

查看:

查看系统log :

1
2
dmsg
TCP: time wait bucket table overflow;

查看系统配置:

1
2
sysctl -a|grep tcp_max_tw_buckets
net.ipv4.tcp_max_tw_buckets = 16384

解决方案:

  1. tw_reuse,tw_recycle 必须在客户端和服务端 timestamps 开启时才管用(默认打开)
  2. tw_reuse 只对客户端起作用,开启后客户端在1s内回收;
  3. tw_recycle 对客户端和服务器同时起作用,开启后在 3.5*RTO 内回收,RTO 200ms~ 120s具体时间视网络状况。内网状况比 tw_reuse 稍快,公网尤其移动网络大多要比 tw_reuse 慢,优点就是能够回收服务端的 TIME_WAIT 数量;在服务端,如果网络路径会经过NAT节点,不要启用 net.ipv4.tcp_tw_recycle,会导致时间戳混乱,引起其他丢包问题;
  4. 调整 tcp_max_tw_buckets 大小,如果内存足够:
1
sysctl -w net.ipv4.tcp_max_tw_buckets=163840;
时间戳异常丢包

当多个客户端处于同一个 NAT 环境时,同时访问服务器,不同客户端的时间可能不一致,此时服务端接收到同一个NAT发送的请求,就会出现时间戳错乱的现象,于是后面的数据包就被丢弃了,具体的表现通常是是客户端明明发送的SYN,但服务端就是不响应ACK。在服务器借助下面的命令可以来确认数据包是否有不断被丢弃的现象。

检查:

1
netstat -s | grep rejects

解决方案:

如果网络路径会经过NAT节点,不要启用 net.ipv4.tcp_tw_recycle

TCP队列问题导致丢包

原理:

tcp状态机(三次握手)

640-20.png

协议处理:

640-8.webp

一个是半连接队列(syn queue):

在三次握手协议中,服务器维护一个半连接队列,该队列为每个客户端的SYN包开设一个条目(服务端在接收到SYN包的时候,就已经创建了 request_sock 结构,存储在半连接队列中),该条目表明服务器已收到SYN包,并向客户发出确认,正在等待客户的确认包(会进行第二次握手发送SYN+ACK的包加以确认)。这些条目所标识的连接在服务器处于Syn_RECV 状态,当服务器收到客户的确认包时,删除该条目,服务器进入 ESTABLISHED 状态。该队列为SYN队列,长度为 max(64,/proc/sys/net/ipv4/tcp_max_syn_backlog), 机器的 tcp_max_syn_backlog 值在 /proc/sys/net/ipv4/tcp_max_syn_backlog 下配置;

一个是全连接队列(accept queue):

第三次握手时,当server接收到ACK 报之后, 会进入一个新的叫 accept 的队列,该队列的长度为 min(backlog, somaxconn),默认情况下,somaxconn 的值为 128,表示最多有 129 的 ESTAB 的连接等待 accept(),而 backlog 的值则应该是由 int listen(int sockfd, int backlog) 中的第二个参数指定,listen 里面的 backlog 可以有我们的应用程序去定义的;

查看:

连接建立失败,syn丢包:

1
2
netstat -s |grep -i listen
SYNs to LISTEN sockets dropped

也会受到连接满丢包影响

解决方案: 增加大小 tcp_max_syn_backlog

连接满丢包

-xxx times the listen queue of a socket overflowed

查看:

  • 查看 accept队列大小 :net.core.somaxconn
  • ss -lnt 查询socket 队列 :LISTEN 状态: Recv-Q 表示的当前等待服务端调用 accept 完成三次握手的 listen backlog 数值,也就是说,当客户端通过 connect() 去连接正在 listen() 的服务端时,这些连接会一直处于这个 queue 里面直到被服务端 accept();Send-Q 表示的则是最大的 listen backlog 数值,这就就是上面提到的 min(backlog, somaxconn) 的值,
  • 看一下是不是应用程序设置限制, int listen(int sockfd, int backlog);

解决方案:

  • Linux内核参进行优化,可以缓解压力 tcp_abort_on_overflow=1
  • 调整 net.core.somaxconn 大小;
  • 应用程序设置问题,通知客户程序修改;
syn flood攻击丢包

目前,Linux 下默认会进行5次重发SYN-ACK包,重试的间隔时间从1s开始,下次的重试间隔时间是前一次的双倍,5次的重试时间间隔为1s, 2s, 4s, 8s, 16s,总共31s,第5次发出后还要等32s都知道第5次也超时了,所以,总共需要 1s + 2s + 4s+ 8s+ 16s + 32s = 63s,TCP才会把断开这个连接。由于,SYN超时需要63秒,那么就给攻击者一个攻击服务器的机会,攻击者在短时间内发送大量的SYN包给Server(俗称 SYN flood 攻击),用于耗尽Server的SYN队列。对于应对SYN 过多的问题;

查看:

查看syslog:

kernel: [3649830.269068] TCP: Possible SYN flooding on port xxx. Sending cookies. Check SNMP counters.

解决方案:

  • 增大tcp_max_syn_backlog
  • 减少tcp_synack_retries
  • 启用tcp_syncookies
  • 启用 tcp_abort_on_overflow, tcp_abort_on_overflow 修改成 1,1表示第三步的时候如果全连接队列满了,server发送一个reset包给client,表示废掉这个握手过程和这个连接(本来在server端这个连接就还没建立起来);
PAWS机制丢包

原理:PAWS(Protect Against Wrapped Sequence numbers),高带宽下,TCP序列号可能在较短的时间内就被重复使用(recycle/wrapped),就可能导致同一条TCP流在短时间内出现序号一样的两个合法的数据包及其确认包。

查看:

1
2
3
4
5
netstat -s |grep -e "passive connections rejected because of time 
stamp" -e "packets rejects in established connections because of
timestamp"
387158 passive connections rejected because of time stamp
825313 packets rejects in established connections because of timestamp

通过 sysctl 查看是否启用了 tcp_tw_recycle 及 tcp_timestamp:

1
2
3
4
5
$ sysctl net.ipv4.tcp_tw_recycle
net.ipv4.tcp_tw_recycle = 1

$ sysctl net.ipv4.tcp_timestamps
net.ipv4.tcp_timestamps = 1
  1. tcp_tw_recycle 参数。它用来快速回收 TIME_WAIT 连接,不过如果在NAT环境下会引发问题;
  2. 当多个客户端通过NAT方式联网并与服务端交互时,服务端看到的是同一个IP,也就是说对服务端而言这些客户端实际上等同于一个,可惜由于这些客户端的时间戳可能存在差异,于是乎从服务端的视角看,便可能出现时间戳错乱的现象,进而直接导致时间戳小的数据包被丢弃。如果发生了此类问题,具体的表现通常是是客户端明明发送的SYN,但服务端就是不响应ACK。

解决方案:

在NAT环境下,清除tcp时间戳选项,或者不开启 tcp_tw_recycle 参数;

TLP问题丢包

TLP主要是为了解决尾丢包重传效率的问题,TLP能够有效的避免较长的RTO超时,进而提高TCP性能,详细参考文章:

http://perthcharles.github.io/2015/10/31/wiki-network-tcp-tlp/

但在低时延场景下(短连接小包量),TLP与延迟ACK组合可能会造成无效重传,导致客户端感发现大量假重传包,加大了响应延迟;

查看:

查看协议栈统计:

netstat -s |grep TCPLossProbes

查看系统配置:

sysctl -a | grep tcp_early_retrans

640-21.png

解决方案:

  1. 关掉延迟ack,打开快速ack;
  2. linux实现nodelay语意不是快速ack,只是关闭nagle算法;
  3. 打开快速ack选项,socket里面有个 TCP_QUICKACK 选项, 需要每次recv后再设置一次。
内存不足导致丢包

查看:

查看log:
dmesg|grep "out of memory"

查看系统配置:

1
2
3
cat /proc/sys/net/ipv4/tcp_mem
cat /proc/sys/net/ipv4/tcp_rmem
cat /proc/sys/net/ipv4/tcp_wmem

解决方案:

根据TCP业务并发流量,调整系统参数,一般试着增大2倍或者其他倍数来看是否缓解;

1
2
3
4
sysclt -w net.ipv4.tcp_mem=
sysclt -w net.ipv4.tcp_wmem=
sysclt -w net.ipv4.tcp_rmem=
sysctl -p
TCP超时丢包

查看:

抓包分析一下网络RTT:

640-9.webp

用其他工具测试一下当前端到端网络质量(hping等);

1
2
3
4
5
6
7
8
9
hping -S 9.199.10.104 -A
HPING 9.199.10.104 (bond1 9.199.10.104): SA set, 40 headers + 0 data bytes
len=46 ip=9.199.10.104 ttl=53 DF id=47617 sport=0 flags=R seq=0 win=0 rtt=38.3 ms
len=46 ip=9.199.10.104 ttl=53 DF id=47658 sport=0 flags=R seq=1 win=0 rtt=38.3 ms
len=46 ip=9.199.10.104 ttl=53 DF id=47739 sport=0 flags=R seq=2 win=0 rtt=30.4 ms
len=46 ip=9.199.10.104 ttl=53 DF id=47842 sport=0 flags=R seq=3 win=0 rtt=30.4 ms
len=46 ip=9.199.10.104 ttl=53 DF id=48485 sport=0 flags=R seq=4 win=0 rtt=38.7 ms
len=46 ip=9.199.10.104 ttl=53 DF id=49274 sport=0 flags=R seq=5 win=0 rtt=34.1 ms
len=46 ip=9.199.10.104 ttl=53 DF id=49491 sport=0 flags=R seq=6 win=0 rtt=30.3 ms

解决方案:

  • 关闭Nagle算法,减少小包延迟;

  • 关闭延迟ack: sysctl -w net.ipv4.tcp_no_delay_ack=1

TCP乱序丢包

此时TCP会无法判断是数据包丢失还是乱序,因为丢包和乱序都会导致接收端收到次序混乱的数据包,造成接收端的数据空洞。TCP会将这种情况暂定为数据包的乱序,因为乱序是时间问题(可能是数据包的迟到),而丢包则意味着重传。当TCP意识到包出现乱序的情况时,会立即ACK,该ACK的TSER部分包含的TSEV值会记录当前接收端收到有序报文段的时刻。这会使得数据包的RTT样本值增大,进一步导致RTO时间延长。这对TCP来说无疑是有益的,因为TCP有充分的时间判断数据包到底是失序还是丢了来防止不必要的数据重传。当然严重的乱序则会让发送端以为是丢包一旦重复的ACK超过TCP的阈值,便会触发超时重传机制,以及时解决这种问题;详细请参考博客:

https://blog.csdn.net/dog250/article/details/78692585

查看:抓包分析是否存在很多乱序报文:

640-10.webp

解决方案:如果在多径传输场景或者网络质量不好,可以通过修改下面值来提供系统对TCP无序传送的容错率:

640-11.webp

拥塞控制丢包

在互联网发展的过程当中,TCP算法也做出了一定改变,先后演进了

Reno、NewReno、Cubic和Vegas,这些改进算法大体可以分为基于丢包和基于延时的拥塞控制算法。基于丢包的拥塞控制算法以Reno、NewReno为代表,它的主要问题有Buffer bloat和长肥管道两种,基于丢包的协议拥塞控制机制是被动式的,其依据网络中的丢包事件来做网络拥塞判断。即使网络中的负载很高,只要没有产生拥塞丢包,协议就不会主动降低自己的发送速度。最初路由器转发出口的Buffer 是比较小的,TCP在利用时容易造成全局同步,降低带宽利用率,随后路由器厂家由于硬件成本下降不断地增加Buffer,基于丢包反馈的协议在不丢包的情况下持续占用路由器buffer,虽然提高了网络带宽的利用率,但同时也意味着发生拥塞丢包后,网络抖动性加大。另外对于带宽和RTT都很高的长肥管道问题来说,管道中随机丢包的可能性很大,TCP的默认buffer设置比较小加上随机丢包造成的cwnd经常下折,导致带宽利用率依旧很低; BBR(Bottleneck Bandwidth and Round-trip propagation time)是一种基于带宽和延迟反馈的拥塞控制算法。目前已经演化到第二版,是一个典型的封闭反馈系统,发送多少报文和用多快的速度发送这些报文都是在每次反馈中不断调节。在BBR提出之前,拥塞控制都是基于事件的算法,需要通过丢包或延时事件驱动;BBR提出之后,拥塞控制是基于反馈的自主自动控制算法,对于速率的控制是由算法决定,而不由网络事件决定,BBR算法的核心是找到最大带宽(Max BW)和最小延时(Min RTT)这两个参数,最大带宽和最小延时的乘积可以得到BDP(Bandwidth Delay Product), 而BDP就是网络链路中可以存放数据的最大容量。BDP驱动Probing State Machine得到Rate quantum和cwnd,分别设置到发送引擎中就可以解决发送速度和数据量的问题。

Linux 4.9内核首次采用BBR拥塞控制算法第一个版本,BBR抗丢包能力比其他算法要强,但这个版本在某些场景下面有问题(缺点),BBR在实时音视频领域存在的问题,深队列竞争不过Cubic。

问题现象就是:在深队列场景,BBR的ProbeRTT阶段只发4个包,发送速率下降太多会引发延迟加大和卡顿问题。

查看:

1
ss -sti //在源端 ss -sti | grep 10.125.42.49:47699 -A 3 #(10.125.42.49:47699 是目的端地址和端口号)

640-12.webp

640-13.webp

解决方案:

  • ProbeRTT并不适用实时音视频领域,因此可以选择直接去除,或者像BBRV2把probe RTT缩短到2.5s一次,使用0.5xBDP发送;
  • 如果没有特殊需求,切换成稳定的cubic算法;

UDP层丢包

收发包失败丢包

查看:netstat 统计

如果有持续的 receive buffer errors/send buffer errors 计数;

640-22.png

解决方案:

  1. CPU负载(多核绑核配置),网络负载(软中断优化,调整驱动队列netdev_max_backlog),内存配置(协议栈内存);
  2. 按峰值在来,增大buffer缓存区大小:
1
2
3
net.ipv4.udp_mem = xxx
net.ipv4.udp_rmem_min = xxx
net.ipv4.udp_wmem_min = xxx
  1. 调整应用设计:
  • UDP本身就是无连接不可靠的协议,适用于报文偶尔丢失也不影响程序状态的场景,比如视频、音频、游戏、监控等。对报文可靠性要求比较高的应用不要使用 UDP,推荐直接使用 TCP。当然,也可以在应用层做重试、去重保证可靠性
  • 如果发现服务器丢包,首先通过监控查看系统负载是否过高,先想办法把负载降低再看丢包问题是否消失
  • 如果系统负载过高,UDP丢包是没有有效解决方案的。如果是应用异常导致CPU、memory、IO 过高,请及时定位异常应用并修复;如果是资源不够,监控应该能及时发现并快速扩容
  • 对于系统大量接收或者发送UDP报文的,可以通过调节系统和程序的 socket buffer size 来降低丢包的概率
  • 应用程序在处理UDP报文时,要采用异步方式,在两次接收报文之间不要有太多的处理逻辑

应用层socket丢包

socket缓存区接收丢包

查看:

  1. 抓包分析是否存在丢包情况;
  2. 查看统计:

netstat -s|grep "packet receive errors"

解决方案:

1
2
3
4
5
6
7
# 调整socket缓冲区大小:
# socket配置(所有协议socket):
# Default Socket Receive Buffer
net.core.rmem_default = 31457280

# Maximum Socket Receive Buffer
net.core.rmem_max = 67108864

具体大小调整原理:

缓冲区大小没有任何设置值是最佳的,因为最佳大小随具体情况而不同

缓冲区估算原理:在数据通信中,带宽时延乘积(英语:bandwidth-delay product;或称带宽延时乘积、带宽延时积等)指的是一个数据链路的能力(每秒比特)与来回通信延迟(单位秒)的乘积。[1][2]其结果是以比特(或字节)为单位的一个数据总量,等同在任何特定时间该网络线路上的最大数据量——已发送但尚未确认的数据。

BDP = 带宽 * RTT

可以通过计算当面节点带宽和统计平均时延来估算BDP,即缓冲区的大小,可以参考下面常见场景估计:

640-23.png

参考:https://docs.oracle.com/cd/E56344_01/html/E53803/gnkor.html

应用设置tcp连接数大小丢包

查看:

请参考上面TCP连接队列分析;

解决方案:

设置合理的连接队列大小,当第三次握手时,当server接收到ACK 报之后, 会进入一个新的叫 accept 的队列,该队列的长度为 min(backlog, somaxconn),默认情况下,somaxconn 的值为 128,表示最多有 129 的 ESTAB 的连接等待 accept(),而 backlog 的值则应该是由 int listen(int sockfd, int backlog) 中的第二个参数指定,listen 里面的 backlog 可以有我们的应用程序去定义的;

应用发送太快导致丢包

查看统计:

netstat -s|grep "send buffer errors"

解决方案:

  • ICMP/UDP没有流控机制,需要应用设计合理发送方式和速度,照顾到底层buff大小和CPU负载以及网络带宽质量;
  • 设置合理的sock缓冲区大小:
    setsockopt(s,SOL_SOCKET,SO_SNDBUF, i(const char*)&nSendBuf,sizeof(int));
  • 调整系统socket缓冲区大小:
1
2
3
4
# Default Socket Send Buffer
net.core.wmem_default = 31457280
# Maximum Socket Send Buffer
net.core.wmem_max = 33554432

附:简单总结一下内核协议栈丢包:

640-24.png

相关工具介绍

1.dropwatch工具

原理: 监听 kfree_skb(把网络报文丢弃时会调用该函数)函数或者事件吗,然后打印对应调用堆栈;想要详细了解 linux 系统在执行哪个函数时丢包的话,可以使用 dropwatch 工具,它监听系统丢包信息,并打印出丢包发生的函数:

640-25.png

  1. tcpdump工具

原理: tcpdump 是一个Unix下一个功能强大的网络抓包工具,它允许用户拦截和显示发送或收到过网络连接到该计算机的TCP/IP和其他数据包

640-26.png

抓包命令参考:

https://www.tcpdump.org/manpages/tcpdump.1.html

数据包分析:

1.用wireshark工具分析 参考:Wireshark数据包分析实战.pdf
2.可以转化生成CSV数据,用Excel或者shell去分析特定场景报文;
3.可以在linux上用tshark命令行工具进行分析:

https://www.wireshark.org/docs/man-pages/tshark.html

计算机网络体系结构分层

651016-20190403213253371-112748496.png

数据包名称简介

  • 包:可以说是全能性术语;
  • 帧:用于表示数据链路层中包的单位;
  • 数据包:是 IP 和 UDP 等网络层以上的分层中包的单位;
  • 段:则表示 TCP 数据流中的信息;
  • 消息:是指应用协议中数据的单位。

  每个分层中,都会对所发送的数据附加一个首部,在这个首部中包含了该层必要的信息,如发送的目标地址以及协议相关信息。通常,为协议提供的信息为包首部,所要发送的内容为数据。在下一层的角度看,从上一层收到的包全部都被认为是本层的数据。

651016-20190403213115559-1163198356.jpg

数据处理流程

用户 a 向用户 b 发送邮件为例子:

1c7ddca5e0e0415c8b4c69047e680fc7.jpeg

微信截图_20210330090819.png

1,应用程序处理

  首先应用程序会进行编码处理,这些编码相当于 OSI 的表示层功能;编码转化后,邮件不一定马上被发送出去,这种何时建立通信连接何时发送数据的管理功能,相当于 OSI 的会话层功能。

2,TCP 模块的处理

  TCP 根据应用的指示,负责建立连接、发送数据以及断开连接。TCP 提供将应用层发来的数据顺利发送至对端的可靠传输。为了实现这一功能,需要在应用层数据的前端附加一个 TCP 首部。

3,IP 模块的处理

  IP 将 TCP 传过来的 TCP 首部和 TCP 数据合起来当做自己的数据,并在 TCP 首部的前端加上自己的 IP 首部。IP 包生成后,参考路由控制表决定接受此 IP 包的路由或主机。

4,网络接口(以太网驱动)的处理

  从 IP 传过来的 IP 包对于以太网来说就是数据。给这些数据附加上以太网首部并进行发送处理,生成的以太网数据包将通过物理层传输给接收端。

5,网络接口(以太网驱动)的处理

  主机收到以太网包后,首先从以太网包首部找到 MAC 地址判断是否为发送给自己的包,若不是则丢弃数据。如果是发送给自己的包,则从以太网包首部中的类型确定数据类型,再传给相应的模块,如 IP、ARP 等。这里的例子则是 IP 。

6,IP 模块的处理

  IP 模块接收到 数据后也做类似的处理。从包首部中判断此 IP 地址是否与自己的 IP 地址匹配,如果匹配则根据首部的协议类型将数据发送给对应的模块,如 TCP、UDP。这里的例子则是 TCP。另外,对于有路由器的情况,接收端地址往往不是自己的地址,此时,需要借助路由控制表,在调查应该送往的主机或路由器之后再进行转发数据。

7,TCP 模块的处理

  在 TCP 模块中,首先会计算一下校验和,判断数据是否被破坏。然后检查是否在按照序号接收数据。最后检查端口号,确定具体的应用程序。数据被完整地接收以后,会传给由端口号识别的应用程序。

8,应用程序的处理

接收端应用程序会直接接收发送端发送的数据。通过解析数据,展示相应的内容。

传输层中的 TCP 和 UDP

TCP/IP 中有两个具有代表性的传输层协议,分别是 TCP 和 UDP。

(1) TCP 是面向连接的、可靠的流协议。流就是指不间断的数据结构,当应用程序采用 TCP 发送消息时,虽然可以保证发送的顺序,但还是犹如没有任何间隔的数据流发送给接收端。TCP 为提供可靠性传输,实行“顺序控制”或“重发控制”机制。此外还具备“流控制(流量控制)”、“拥塞控制”、提高网络利用率等众多功能。

(2) UDP 是不具有可靠性的数据报协议。细微的处理它会交给上层的应用去完成。在 UDP 的情况下,虽然可以确保发送消息的大小,却不能保证消息一定会到达。因此,应用有时会根据自己的需要进行重发处理。

TCP 和 UDP 的优缺点无法简单地、绝对地去做比较:TCP 用于在传输层有必要实现可靠传输的情况;而在一方面,UDP 主要用于那些对高速传输和实时性有较高要求的通信或广播通信。TCP 和 UDP 应该根据应用的目的按需使用。

端口号

  数据链路和 IP 中的地址,分别指的是 MAC 地址和 IP 地址。前者用来识别同一链路中不同的计算机,后者用来识别 TCP/IP 网络中互连的主机和路由器。在传输层也有这种类似于地址的概念,那就是端口号。端口号用来识别同一台计算机中进行通信的不同应用程序。因此,它也被称为程序地址。

一台计算机上同时可以运行多个程序。传输层协议正是利用这些端口号识别本机中正在进行通信的应用程序,并准确地将数据传输。

3f35fe4b91bb4a27b4ab30f84639d32a.jpeg
65b24665096545c089a7a18300218c6d.jpeg

  • (1) 和 (2) 的通信是在两台计算机上进行的。它们的目标端口号相同,都是80。这里可以根据源端口号加以区分。
  • (3) 和 (1) 的目标端口号和源端口号完全相同,但它们各自的源 IP 地址不同。
  • 当 IP 地址和端口号全都一样时,我们还可以通过协议号来区分(TCP 和 UDP)。

端口号的确定

  • 标准既定的端口号:这种方法也叫静态方法。它是指每个应用程序都有其指定的端口号。但并不是说可以随意使用任何一个端口号。例如 HTTP、FTP、TELNET 等广为使用的应用协议中所使用的端口号就是固定的。这些端口号被称为知名端口号,分布在 0~1023 之间;除知名端口号之外,还有一些端口号被正式注册,它们分布在 1024~49151 之间,不过这些端口号可用于任何通信用途。
  • 时序分配法:服务器有必要确定监听端口号,但是接受服务的客户端没必要确定端口号。在这种方法下,客户端应用程序完全可以不用自己设置端口号,而全权交给操作系统进行分配。动态分配的端口号范围在 49152~65535 之间。

端口号与协议

  端口号由其使用的传输层协议决定。因此,不同的传输层协议可以使用相同的端口号。此外,那些知名端口号与传输层协议并无关系。只要端口一致都将分配同一种应用程序进行处理。

UDP

  • UDP 不提供复杂的控制机制,利用 IP 提供面向无连接的通信服务。
  • UDP 将应用程序发来的数据在收到的那一刻,立即按照原样发送到网络上的一种机制。即使是出现网络拥堵的情况,UDP 也无法进行流量控制等避免网络拥塞行为。
  • 传输途中出现丢包,UDP 也不负责重发。
  • 当包的到达顺序出现乱序时也没有纠正的功能。
  • 如果需要以上的细节控制,不得不交由采用 UDP 的应用程序去处理。

UDP 常用于一下几个方面:

  • 1.包总量较少的通信(DNS、SNMP等);
  • 2.视频、音频等多媒体通信(即时通信);
  • 3.限定于 LAN 等特定网络中的应用通信;
  • 4.广播通信(广播、多播)。

TCP

  TCP 与 UDP 的区别相当大。它充分地实现了数据传输时各种控制功能,可以进行丢包时的重发控制,还可以对次序乱掉的分包进行顺序控制。而这些在 UDP 中都没有。此外,TCP 作为一种面向有连接的协议,只有在确认通信对端存在时才会发送数据,从而可以控制通信流量的浪费。

  根据 TCP 的这些机制,在 IP 这种无连接的网络上也能够实现高可靠性的通信( 主要通过检验和、序列号、确认应答、重发控制、连接管理以及窗口控制等机制实现)。

三次握手

  TCP 提供面向有连接的通信传输。面向有连接是指在数据通信开始之前先做好两端之间的准备工作。三次握手是指建立一个 TCP 连接时,需要客户端和服务器端总共发送三个包以确认连接的建立。在socket编程中,这一过程由客户端执行connect来触发。

3148139034514574a74a055e2a35b6fd.jpeg

  • 第一次握手:客户端将标志位 SYN 置为1,随机产生一个值 seq=J,并将该数据包发送给服务器端,客户端进入 SYN_SENT 状态,等待服务器端确认。

  • 第二次握手:服务器端收到数据包后由标志位 SYN=1,知道客户端请求建立连接,服务器端将标志位 SYNACK 都置为1,ack=J+1,随机产生一个值 seq=K ,并将该数据包发送给客户端以确认连接请求,服务器端进入 SYN_RCVD 状态。

  • 第三次握手:客户端收到确认后,检查 ack 是否为 J+1ACK 是否为1,如果正确,则将标志位 ACK置为1,ack=K+1,并将该数据包发送给服务器端,服务器端检查 ack 是否为 K+1ACK 是否为1,如果正确则连接建立成功,客户端和服务器端进入 ESTABLISHED (已确立的)状态,完成三次握手,随后客户端与服务器端之间可以开始传输数据了。

  • SYN攻击:在三次握手过程中,Server 发送 SYN-ACK 后,收到 Client 的ACK之前的TCP连接称为半连接,此时Serve处于SYN_RECV状态,当收到ACK后,Server 转入ESTABLISHED状态。SYN 攻击就是 Client 在短时间内伪造大量不存在的IP地址,并向Server不断的发送 SYN 包,Server回复确认包,并等待 Client 的确认,由于源地址不存在,因此 Server 需要不断重发直至超时,这些伪造的SYN包将长时间占用未连接队列,导致正常的SYN请求因为队列满而被丢弃,从而引起网络阻塞甚至系统瘫痪。

SYN攻击就是一种典型的DDOS攻击,检测SYN攻击方式也很简单,即当有大量半连接状态且源地址是随机的,则可以断定遭到SYN攻击了,使用如下命令让其无处可逃:netstat -nap|grep SYN_RECV

四次挥手

  四次挥手即终止 TCP 连接,就是指断开一个TCP连接时,需要客户端和服务端总共发送4个包以确认连接的断开。在 socket 编程中,这一过程由 客户端 或 服务端 任一方执行 close 来触发。

  由于TCP连接是全双工的,因此,每个方向都必须要单独进行关闭,这一原则是当一方完成数据发送任务后,发送一个 FIN 来终止这一方向的连接,收到一个 FIN 只是意味着这一方向上没有数据流动了,即不会再收到数据了,但是在这个TCP连接上仍然能够发送数据,直到这一方向也发送了 FIN。首先进行关闭的一方将执行主动关闭,而另一方则执行被动关闭。

3e49dad546ba48eca6777783a8456a97.jpeg

中断连接端可以是客户端,也可以是服务器端。

  • 第一次挥手:客户端发送一个 FIN=M,用来关闭客户端到服务器端的数据传送,客户端进入 FIN_WAIT_1 状态。意思是说”我客户端没有数据要发给你了”,但是如果你服务器端还有数据没有发送完成,则不必急着关闭连接,可以继续发送数据。
  • 第二次挥手:服务器端收到 FIN 后,先发送 ack=M+1,告诉客户端,你的请求我收到了,但是我还没准备好,请继续你等我的消息。这个时候客户端就进入 FIN_WAIT_2 状态,继续等待服务器端的 FIN 报文。
  • 第三次挥手:当服务器端确定数据已发送完成,则向客户端发送 FIN=N 报文,告诉客户端,好了,我这边数据发完了,准备好关闭连接了。服务器端进入 LAST_ACK 状态。
  • 第四次挥手:客户端收到 FIN=N 报文后,就知道可以关闭连接了,但是他还是不相信网络,怕服务器端不知道要关闭,所以发送 ack=N+1 后进入 TIME_WAIT 状态,如果 Server 端没有收到 ACK 则可以重传。服务器端收到ACK后,就知道可以断开连接了。客户端等待了 2MSL 后依然没有收到回复,则证明服务器端已正常关闭,那好,我客户端也可以关闭连接了。最终完成了四次握手。

上面是一方主动关闭,另一方被动关闭的情况,实际中还会出现同时发起主动关闭的情况,

4c5ab6ed942c431bbed30009959783c0.jpeg

通过序列号与确认应答提高可靠性

  在 TCP 中,当发送端的数据到达接收主机时,接收端主机会返回一个已收到消息的通知。这个消息叫做确认应答(ACK)。当发送端将数据发出之后会等待对端的确认应答。如果有确认应答,说明数据已经成功到达对端。 反之,则数据丢失的可能性很大。

  在一定时间内没有等待到确认应答,发送端就可以认为数据已经丢失,并进行重发。由此,即使产生了丢包,仍然能够保证数据能够到达对端,实现可靠传输。

  未收到确认应答并不意味着数据一定丢失。也有可能是数据对方已经收到,只是返回的确认应答在途中丢失。这种情况也会导致发送端误以为数据没有到达目的地而重发数据。

  此外,也有可能因为一些其他原因导致确认应答延迟到达,在源主机重发数据以后才到达的情况也屡见不鲜。此时,源主机只要按照机制重发数据即可。

  对于目标主机来说,反复收到相同的数据是不可取的。为了对上层应用提供可靠的传输,目标主机必须放弃重复的数据包。为此引入了序列号。

  序列号是按照顺序给发送数据的每一个字节(8位字节)都标上号码的编号。接收端查询接收数据 TCP 首部中的序列号和数据的长度,将自己下一步应该接收的序列号作为确认应答返送回去。通过序列号和确认应答号,TCP 能够识别是否已经接收数据,又能够判断是否需要接收,从而实现可靠传输。

重发超时的确定

  重发超时是指在重发数据之前,等待确认应答到来的那个特定时间间隔。如果超过这个时间仍未收到确认应答,发送端将进行数据重发。最理想的是,找到一个最小时间,它能保证 “确认应答一定能在这个时间内返回”。

  TCP 要求不论处在何种网络环境下都要提供高性能通信,并且无论网络拥堵情况发生何种变化,都必须保持这一特性。为此,它在每次发包时都会计算往返时间及其偏差。将这个往返时间和偏差时间相加,重发超时的时间就是比这个总和要稍大一点的值。

  在 BSD 的 Unix 以及 Windows 系统中,超时都以0.5秒为单位进行控制,因此重发超时都是0.5秒的整数倍。不过,最初其重发超时的默认值一般设置为6秒左右。数据被重发之后若还是收不到确认应答,则进行再次发送。此时,等待确认应答的时间将会以2倍、4倍的指数函数延长。

  此外, 数据也不会被无限、反复地重发。达到一定重发次数之后,如果仍没有任何确认应答返回,就会判断为网络或对端主机发生了异常,强制关闭连接。并且通知应用通信异常强行终止。

以段为单位发送数据

  在建立 TCP 连接的同时,也可以确定发送数据包的单位,我们也可以称其为“最大消息长度”(MSS)。最理想的情况是,最大消息长度正好是 IP 中不会被分片处理的最大数据长度。

  TCP 在传送大量数据时,是以 MSS 的大小将数据进行分割发送。进行重发时也是以 MSS 为单位。

  MSS 在三次握手的时候,在两端主机之间被计算得出。两端的主机在发出建立连接的请求时,会在 TCP 首部中写入 MSS 选项,告诉对方自己的接口能够适应的 MSS 的大小。然后会在两者之间选择一个较小的值投入使用。

利用窗口控制提高速度

  TCP 以 1 个段为单位,每发送一个段进行一次确认应答的处理。这样的传输方式有一个缺点,就是包的往返时间越长,通信性能就越低。

  为解决这个问题,TCP 引入了窗口这个概念。确认应答不再是以每个分段,而是以更大的单位进行确认,转发时间将会被大幅地缩短。也就是说,发送端主机,在发送了一个段以后不必要一直等待确认应答,而是继续发送。如下图所示:

8c6eab31573940a5bc369ea648d45591.jpeg

  窗口大小就是指:无需等待确认应答,而可以继续发送数据的最大值。上图中窗口大小为4个段。这个机制实现了使用大量的缓冲区,通过对多个段,同时进行确认应答的功能。

滑动窗口控制

0f015679fbef46deb30d6669d5e28ddf.jpeg

  上图中的窗口内的数据,即便没有收到确认应答也可以被发送出去。不过,在整个窗口的确认应答没有到达之前,如果其中部分数据出现丢包,那么发送端仍然要负责重传。为此,发送端主机需要设置缓存保留这些待被重传的数据,直到收到他们的确认应答。

  在滑动窗口以外的部分,包括未发送的数据,以及已经确认对端已收到的数据。当数据发出后,若如期收到确认应答就可以不用再进行重发,此时数据就可以从缓存区清除。

  收到确认应答的情况下,将窗口滑动到确认应答中的序列号的位置。这样可以顺序地将多个段同时发送提高通信性能。这种机制也别称为 滑动窗口控制

窗口控制中的重发控制

  在使用窗口控制中, 出现丢包一般分为两种情况:

① 确认应答未能返回的情况。在这种情况下,数据已经到达对端,是不需要再进行重发的,如下图:

f665dba5def44bb8a9ae13848602442c.jpeg

② 某个报文段丢失的情况。接收主机如果收到一个自己应该接收的序列号以外的数据时,会针对当前为止收到数据返回确认应答。如下图所示,当某一报文段丢失后,发送端会一直收到序号为1001的确认应答,因此,在窗口比较大,又出现报文段丢失的情况下,同一个序列号的确认应答将会被重复不断地返回。而发送端主机如果连续3次收到同一个确认应答,就会将其对应的数据进行重发。这种机制比之前提到的超时管理更加高效,因此也被称为 高速重发控制

1a1667fade0340998a1879a9f06d8511.jpeg

网络层中的 IP 协议

  IP(IPv4、IPv6)相当于 OSI 参考模型中的第3层——网络层。网络层的主要作用是 “实现终端节点之间的通信”。这种终端节点之间的通信也叫 “点对点通信”。

微信截图_20210330090750.png

  • 主机:配置有 IP 地址,不进行路由控制的设备。
  • 路由器:既有 IP 地址又具有路由控制功能的设备。
  • 节点:主机和路由器的统称。

  网络的下一层—数据链路层 的主要作用是在互连同一种数据链路的节点之间进行包传递。而一旦跨越多种数据链路,就需要借助网络层。网络层可以跨越不同的数据链路,即使是在不同的数据链路上,也能实现两端节点之间的数据包传输。

IP 大致分为三大作用模块,它们是 IP 寻址、路由(最终节点为止的转发)、IP 分包与组包。

IP 地址

  在计算机通信中,为了识别通信对端,必须要有一个类似于地址的识别码进行标识。在数据链路中的 MAC 地址正是用来标识同一个链路中不同计算机的一种识别码。

  作为网络层的 IP,也有这种地址信息,一般叫做 IP 地址。IP 地址用于在 “连接到网络中的所有主机中识别出进行通信的目标地址”。因此,在 TCP/IP 通信中所有主机或路由器必须设定自己的 IP 地址。

  不论一台主机与哪种数据链路连接,其 IP 地址的形式都保持不变。

  IP 地址(IPv4 地址)由32位正整数来表示。IP 地址在计算机内部以二进制方式被处理。然而,由于我们并不习惯于采用二进制方式,我们将32位的 IP 地址以每8位为一组,分成4组,每组以 “.” 隔开,再将每组数转换成十进制数。如下:

902f8a4e03a242ecb6e16e3f718371e6.jpeg

将 IP 地址的32位二进制进行计算,得出约 43 亿个 IP 地址。

实际上,网络的发展超乎想象,互联网上的设备远超 43 亿, 2019 年 11 月 25 日全球的 IPv4 地址已经彻底耗尽,但是直到现在大家仍然还在用 IPv4 ,并没有因为地址没了而无法上网。是因为除了 IPv6 之外,我们使用 NAT 技术缓解了地址不足的问题。

IP 地址组成

IP 地址由网络号(网段地址)和主机号(主机地址)两部分组成。

微信截图_20210330090934.png

IP地址的主机标识

  如下图,网络标识在数据链路的每个段配置不同的值。网络标识必须保证相互连接的每个段的地址不相重复。而相同段内相连的主机必须有相同的网络地址。IP 地址的 “主机标识” 则不允许在同一个网段内重复出现。由此,可以通过设置网络地址和主机地址,在相互连接的整个网络中保证每台主机的 IP 地址都不会相互重叠,即 IP 地址具有了唯一性。

微信截图_20210330091419.png

IP地址的网络标识

  如下图,IP 包被转发到途中某个路由器时,正是利用目标 IP 地址的网络标识进行路由。因为即使不看主机标识,只要一见到网络标识就能判断出是否为该网段内的主机。

微信截图_20210330091204.png

IP 地址的分类

  IP 地址分为四个级别,分别为A类、B类、C类、D类。它根据 IP 地址中从第 1 位到第 4 位的比特列对其网络标识和主机标识进行区分。

微信截图_20210330091531.png

  • A 类 IP 地址是首位以 0 开头的地址。从第 1 位到第 8 位是它的网络标识(网络号)。用十进制表示的话,0.0.0.0~127.0.0.0 是 A 类的网络地址。A 类地址的后 24 位相当于主机标识。因此,一个网段内可容纳的主机地址上限为 16,777,214(2的24次方-2) 个。其中 0 和 127 属于保留地址,减去两个保留地址,因此有 126 个可用的 A 类地址。

微信截图_20210330091724.png
微信截图_20210330091808.png

  • B 类 IP 地址是前两位 10 的地址。从第 1 位到第 16 位是它的网络标识(网络号)。用十进制表示的话,128.0.0.0~191.255.0.0 是 B 类的网络地址。B 类地址的后 16 位相当于主机标识。因此,一个网段内可容纳的主机地址上限为65,534 (2的16次方-2)个。其中 128.0191.255 属于保留地址,减去两个保留地址,因此有 16382 个可用的 B 类地址。

微信截图_20210330091932.png

微信截图_20210330092058.png

  • C 类 IP 地址是前三位为 110 的地址。从第 1 位到第 24 位是它的网络标识(网络号)。用十进制表示的话,192.0.0.0~223.255.255.0 是 C 类的网络地址。C 类地址的后 8 位相当于主机标识。因此,一个网段内可容纳的主机地址上限为 254 (2的8次方-2)个。其中 192.0.0223.255.255 属于保留地址,减去两个保留地址,因此有 2097150 个可用的 C 类地址。

微信截图_20210330092208.png

微信截图_20210330092307.png

  • D 类 IP 地址是前四位为 1110 的地址。从第 1 位到第 32 位是它的网络标识(网络号)。用十进制表示的话,224.0.0.0~239.255.255.255 是 D 类的网络地址。D 类地址没有主机标识,常用于多播。

127.x.x.x 段地址空间是被保留的回环地址。

  在分配 IP 地址时关于主机标识有一点需要注意。即要用比特位表示主机地址时,不可以全部为 0 或全部为 1。因为全部为 0 只有在表示对应的网络地址或 IP 地址不可以获知的情况下才使用。而全部为 1 的主机通常作为广播地址。因此,在分配过程中,应该去掉这两种情况。这也是为什么 C 类地址每个网段最多只能有 254( 2的8次方- 2 = 254)个主机地址的原因。

广播地址

  广播地址( Broadcast Address) 是专门用于同时向网络中所有工作站进行发送的一个地址。在使用 TCP/IP 协议的网络中,主机标识段 host ID 为全1 (11111111,即十进制的255) 的IP 地址为广播地址,广播的分组传送给host ID 段所涉及的所有计算机。例如,对于 10.1.1.0 (255.0.0.0 )网段,其直播广播地址为 10.255.255.255 (255 即为 2 进制的11111111),当发出一个目的地址为 10.255.255.255 的分组(封包)时,它将被分发给该网段上的所有计算机。

广播地址应用于网络内的所有主机,广播分为受限广播(本地广播)和直接广播两种。在本网络内的广播叫做受限广播(本地广播);在不同网络之间的广播叫做直接广播。

  • (1)受限广播(本地广播)
    它不被路由发送,但会被送到相同物理网络段上的所有主机
    IP地址的网络字段和主机字段全为1就是地址 255.255.255.255
  • (2)直接广播
    网络广播会被路由,并会发送到专门网络上的每台主机
    IP地址的网络字段定义这个网络,主机字段通常全为1,如 192.168.10.255
受限地址

  受限的广播地址是 255.255.255.255。该地址用于主机配置过程中IP数据包的目的地址,此时,主机可能还不知道它所在网络的网络掩码,甚至连它的IP地址也不知道。在任何情况下,路由器都不转发目的地址为受限的广播地址的数据报,这样的数据报仅出本地网络中。

指向网络

  指向网络的广播地址是主机号为全1(11111111)的地址。A类网络广播地址为 netid.255.255.255,其中netid为A类网络的网络号。一个路由器必须转发指向网络的广播,但它也必须有一个不进行转发的选择。

指向子网

  指向子网的广播地址为主机号为全1(11111111)且有特定子网号的地址。作为子网直接广播地址的IP地址需要了解子网的掩码。例如,如果路由器收到发往 128.1.2.255 的数据报,当B类网络 128.1 的子网掩码为 255.255.255.0时,该地址就是指向子网的广播地址;但如果该子网的掩码为 255.255.254.0,该地址就不是指向子网的广播地址。

指向所有子网

  指向所有子网的广播也需要了解目的网络的子网掩码,以便与指向网络的广播地址区分开。指向所有子网的广播地址的子网号及主机号为全1。例如,如果目的子网掩码为 255.255.255.0 ,那么IP地址 128.1.255.255 是一个指向所有子网的广播地址。然而,如果网络没有划分子网,这就是一个指向网络的广播。

IP多播(组播)

  IP多播(也称 多址广播组播)技术,是一种允许一台或多台主机(多播源)发送单一数据包到多台主机(一次的,同时的)的TCP/IP网络技术。多播作为一点对多点的通信,是节省网络带宽的有效方法之一。在网络音频/视频广播的应用中,当需要将一个节点的信号传送到多个节点时,无论是采用重复点对点通信方式,还是采用广播方式,都会严重浪费网络带宽,只有多播才是最好的选择。多播能使一个或多个多播源只把数据包发送给特定的多播组,而只有加入该多播组的主机才能接收到数据包。目前,IP多播技术被广泛应用在 网络音频/视频广播、AOD/VOD、网络视频会议、多媒体远程教育、”push”技术(如股票行情等)和虚拟现实游戏等方面。

  有些应用会有这样的要求:一些分布在各处的进程需要以组的方式协同工作,组中的进程通常要给其他所有的成员发送消息。即有这样的一种方法能够给一些明确定义的组发送消息,这些组的成员数量虽然很多,但是与整个网络规模相比却很小。给这样一个组发送消息称为多点点播送,简称多播。需要注意的是多播数据包的目的ip地址实际上不可能对应某一台真实存在的主机的ip地址,也就是说该目的ip地址永远不可能作为源地址,即多播ip地址只能用于目的ip地址,不能用于源ip地址。

组播使用 D 类地址。因此 IP 地址前四位是 “1110” 开头的,就是组播地址。剩下的 28 位就是组播的组编号。组播的地址范围是 224.0.0.0 ~ 239.255.255.255 ,其中 224.0.0.0 ~ 224.0.0.255 既可以在同一个网段内实现组播,又可以跨网段给全网所有组员发送组播包。

微信截图_20210330093819.png

微信截图_20210330093945.png

1.多播地址和多播组

  IP多播通信必须依赖于IP多播地址,在 IPv4 中它是一个D类IP地址,并且ip首部中的协议字段为2,表明采用的是IGMP网际组管理协议。范围从 224.0.0.0239.255.255.255,并被划分为局部链接多播地址、预留多播地址和管理权限多播地址三类。因此,如果从首位开始到第 4 位是 1110 ,就可以认为是多播地址,而剩下的 28 位可以成为多播的组编号。所有的主机(路由器以外的主机和终端主机)必须属于 224.0.0.1 的组,所有的路由器必须属于 224.0.0.2 的组。

  • 局部链接多播地址范围在 224.0.0.0~224.0.0.255,这是为路由协议和其它用途保留的地址,路由器并不转发属于此范围的IP包;
  • 预留多播地址为 224.0.1.0~238.255.255.255,可用于全球范围(如Internet)或网络协议;
  • 管理权限多播地址为 239.0.0.0~239.255.255.255,可供组织内部使用,类似于私有IP地址,不能用于 Internet,可限制多播范围。

  使用同一个IP多播地址接收多播数据包的所有主机构成了一个主机组,也称为多播组。一个多播组的成员是随时变动的,一台主机可以随时加入或离开多播组,多播组成员的数目和所在的地理位置也不受限制,一台主机也可以属于几个多播组。此外,不属于某一个多播组的主机也可以向该多播组发送数据包。

2. 多播技术硬件支持

要实现IP多播通信,要求介于多播源和接收者之间的路由器、集线器、交换机以及主机均需支持IP多播。目前,IP多播技术已得到硬件、软件厂商的广泛支持。

  • (1)主机
    支持IP多播通信的平台包括 Windows CE 2.1、Windows 95、Windows 98、Windows NT 4 和 Windows 2000 等,运行这些操作系统的主机都可以进行IP多播通信。此外,新生产的网卡也几乎都提供了对IP多播的支持。
  • (2)集线器和交换机
    目前大多数集线器、交换机只是简单地把多播数据当成广播来发送接收,但一些中、高档交换机提供了对IP多播的支持。例如,在 3COM SuperStack 3 Swith 3300 交换机上可启用 802.1p 或 IGMP 多播过滤功能,只为已侦测到IGMP 数据包的端口转发多播数据包。
  • (3)路由器
    多播通信要求多播源节点和目的节点之间的所有路由器必须提供对 Internet组管理协议(IGMP)、多播路由协议(如PIM、DVMRP等)的支持。

  多播用于将包发送给特定组内的所有主机。由于其直接使用 IP 地址,因此也不存在可靠传输。相比于广播,多播既可以穿透路由器,又可以实现只给那些必要的组发送数据包。请看下图:

71e3a03024f04d32954f591d6e1edb43.jpeg

子网掩码

  子网掩码是在IPv4地址资源紧缺的背景下为了解决lP地址分配而产生的虚拟lP技术,通过子网掩码将A、B、C三类地址划分为若干子网,从而显著提高了IP地址的分配效率,有效解决了IP地址资源紧张的局面。如果是都是使用的IPV6的话是没有子网掩码的概念。IPV6是端到端的连接通信,不需要子网了。

  子网掩码用 32 位的二进制表示, IP 地址的网段地址部分设置为 1 , IP 地址的主机地址部分设置为 0 。换句话说, IP 地址有多少位网段地址,子网掩码就有多少位取 1 ,其余都取 0 。为了方便记录,每 8 位为一组,以 . 隔开,再转换为十进制数。

将子网掩码和 IP 地址进行与( AND )运算,可得到这个 IP 地址的网段地址。

详情参考:IP4-子网掩码

概念 特征 网络范围 默认掩码
A类地址 第1个8位中的第1位始终为0 0-127.x.x.x 255.0.0.0/8
B类地址 第1个8位中的第1、2位始终为10 128-191.x.x.x 255.255.0.0/16
C类地址 第1个8位中的第1、2、3位始终为110 192-y.x.x.x 255.255.255.0/24

  对于子网掩码,目前有两种表示方式。第一种是,将 IP 地址与子网掩码的地址分别用两行来表示。以 172.20.100.52 的前 26 位是网络地址的情况为例,如下:

bb3cd3458dc94871a4a68f3fdd4897eb.jpeg

第二种表示方式是,在每个 IP 地址后面追加网络地址的位数用 / 隔开,如下:

050f0e2d38554dd89fdc4427226cc688.jpeg

CIDR 与 VLSM

解决 IP 地址浪费问题,除了使用子网掩码,还使用了 CIDR 和 VLSM 技术。

CIDR ,即无类域间路由,采用任意长度分割 IP 地址的网络号和主机号。它有两个作用:

  • 把多个网段聚合到一起,生成一个更大的网段;
  • 汇总路由表 IP 地址,分担路由表压力。

微信截图_20210330094830.png

VLSM ,即可变长子网掩码,它可以对 A 、 B 、 C 类地址再进行子网划分,以达到充分利用 IP 地址的目的。

假如一家企业有 100 台电脑,按以前的办法,只能分配一个 C 类地址 222.222.222.0 。但是 VLSM 可以在一个 C 类地址上划分出多个子网地址,再分配其中一个容纳主机数量与稍大于企业需求数量的子网地址给企业,这样就可以实现 IP 地址的合理使用。

计算容纳 100 台电脑的子网:使用主机号的位数计算出子网的主机地址数量。当主机号有 7 位时,有 126 个可用主机地址,可容纳 100 台电脑。

微信截图_20210330095148.png

计算子网地址:当主机号有 7 位时,网络号有 32 - 7 = 25 位,也就是 222.222.222.0/24 向主机位借了一位作为子网位,那么子网掩码也就是 255.255.255.128。可分配 222.222.222.0/25 使用。

微信截图_20210330095237.png

222.222.222.0/25子网详情:

微信截图_20210330095312.png

CIDR 和 VLSM 的区别

CIDR 是主机号向网络号借位,目的是把几个网络汇总成一个大的网络,增加子网主机数量;

VLSM 是网络号向主机号借位,目的是把一个标准的网络划分成几个子网,减少子网主机数量。

公网地址与私有地址

IP 地址分为公网地址和私有地址。公网地址是在互联网上使用的,私有地址是在局域网中使用的。

公网地址由 Internet NIC 负责分配,通过它直接访问互联网。

微信截图_20210330095612.png

私有地址是一段保留的 IP 地址。只在局域网中使用,无法在互联网上使用。但是私有地址可以通过 NAT 技术,将私有地址转换为公网地址接入互联网。

微信截图_20210330095637.png

公网 IP 地址在互联网范围内是唯一的,私有 IP 地址只要在同一个局域网内唯一即可。在不同局域网内出现相同的私有 IP 不会影响使用。

IP路由

  发送数据包时所使用的地址是网络层的地址,即 IP 地址。然而仅仅有 IP 地址还不足以实现将数据包发送到对端目标地址,在数据发送过程中还需要类似于 指明路由器或主机 的信息,以便真正发往目标地址。保存这种信息的就是 路由控制表

  IP 协议始终认为路由表是正确的。然后,IP 本身并没有定义制作路由控制表的协议。即 IP 没有制作路由控制表的机制。该表示由一个叫做 路由协议 的协议制作而成。

当一个数据包到达路由器时,路由器根据数据包的目的地址查询路由表,根据查询结果将数据包转发出去,这个过程就是 IP路由。

微信截图_20210330101202.png

路由表

  为了将数据包发给目的节点,所有节点都维护着一张路由表。路由表记录 IP 数据在下一跳应该发给哪个路由器。IP 包将根据这个路由表在各个数据链路上传输。

微信截图_20210330101335.png

  路由控制表的形成方式有两种:一种是管理员手动设置,也叫做 静态路由控制;另一种是路由器与其他路由器相互交换信息时自动刷新,叫做 动态路由控制

微信截图_20210330101457.png

下一跳

Hop ,中文叫 “跳”。它是指网络中的一个区间。IP 包就是在网络中一跳一跳的转发,在每一个区间内决定 IP 包下一跳的路径。

一跳是指数据链路中广播域的区间,也就是说不经过路由器而能直接到达的相连主机或路由器网卡的一个区间。

微信截图_20210330101607.png

IP 数据包就像包裹,而送货车就像数据链路。包裹不可能自己移动,必须有送货车承载转运。而一辆送货车只能将包裹送到某个区间范围内。每个不同区间的包裹将由对应的送货车承载、运输。IP 的工作原理也是如此。

微信截图_20210330101639.png

路由条目类型

默认路由

默认路由是指路由表中任何一个地址都能与之匹配的条目。所有数据包都可以使用默认路由进行数据转发。默认路由为 0.0.0.0/0default

微信截图_20210330102027.png

主机路由

IP地址/32 被称为主机路由,它是路由表中指向单个 IP 地址或主机名的路由条目。例如:192.168.153.15/32 就是一条主机路由,表示整个 IP 地址的所有位都将参与路由。

回环地址

以 127 开头的 IP 地址都是环回地址,其所在的回环接口可以理解为虚拟网卡。使用回环地址时,数据包会直接被主机的 IP 层获取,而不经过链路层,也不会流向网络。一般用来检查主机上运行的网络服务是否正常。

路由汇总

路由汇总主要是为了减少路由条目,把可以聚合的路由汇聚为一个大网络。

路由表越大,查找路由表所需的内存和 CPU 也就越多,时间也会越长,导致转发 IP 数据包的性能下降。如果想要搭建大规模、高性能的网络,就需要尽可能的路由表的大小。

微信截图_20210330102240.png
微信截图_20210330102302.png

IP 地址与路由控制

IP 地址的网络地址部分用于进行路由控制。路由控制表中记录着网络地址与下一步应该发送至路由器的地址。

  在发送 IP 包时,首先要确定 IP 包首部中的目标地址,再从路由控制表中找到与该地址具有相同网络地址的记录,根据该记录将 IP 包转发给相应的下一个路由器。如果路由控制表中存在多条相同网络地址的记录,就选择一个最为吻合的网络地址。

97e1e1332e5445c5b3da354f7cf407f9.jpeg

IP 分包与组包

数据链路与MTU

数据链路不同, MTU 则不同。

  每种数据链路的最大传输单元(MTU)都不尽相同,因为每个不同类型的数据链路的使用目的不同。使用目的不同,可承载的 MTU 也就不同,网络层的 IP 是数据链路的上一层, IP 通过分片屏蔽数据链路的差异,实现不同数据链路互通。从 IP 的上一层看,它完全可以忽略各个数据链路上的 MTU ,只需要按照源 IP 地址发送的长度接收数据包。

微信截图_20210330102721.png

IP报文的分片与重组

  任何一台主机都有必要对 IP 分片进行相应的处理。分片往往在网络上遇到比较大的报文无法一下子发送出去时才会进行处理。经过分片之后的 IP 数据报在被重组的时候,只能由目标主机进行。路由器虽然做分片但不会进行重组。

微信截图_20210330104125.png

路径 MTU 发现

分片机制有两点不足:

  • 加重路由器的处理性能;
  • 在分片传输中,一旦某个分片丢失,会造成整个 IP 数据包作废。

因此,只要允许,是不希望由路由器进行 IP 数据包的分片处理的。

为了应对分片机制的不足,路径MTU发现(Path MTU Discovery) 技术应运而生。

  路径 MTU 指的是,从发送端主机到接收端主机之间不需要分片是最大 MTU 的值。即路径中存在的所有数据链路中最小的 MTU 。进行路径 MTU 发现,就可以避免在中途的路由器上进行分片处理,也可以在 TCP 中发送更大的包。

微信截图_20210330104310.png

路径 MTU 发现的工作原理如下:

  • 1,发送端主机发送 IP 数据包时将其头部的分片禁止标志位设置为 1 。根据这个标志位,途中的路由器即使收到需要分片的大包,也不会分片,而是直接将包丢弃。之后通过一个 ICMP 不可达消息将数据链路上 MTU 值给发送端主机。

  • 2,发送端主机根据收到的 MTU 值对数据包进行分片处理,再把 IP 数据包发送给相同的目的主机。如此重复,直到数据包被发送到目标主机为止没有再收到任何 ICMP ,就认为最后一次 ICMP 所通知的 MTU 即是一个合适的 MTU 值。MTU 值至少可以缓存约 10 分钟,在这 10 分钟内使用刚得到的 MTU ,过了 10 分钟后就重新做一次路径 MTU 发现。

上面的例子是 UDP ,如果是在 TCP 的情况下,根据路径 MTU 的大小计算出最大段长度( MSS ),然后再根据这些信息进行数据包的发送。因此,在 TCP 中如果使用路径 MTU 发现, IP 层则不会再分片。

路由器三层转发原理

  路由器有多个端口,分别连接不同的数据链路。它通过识别目的 IP 地址的网络号,再根据路由表进行转发,路由表中有匹配的路由条目才会转发,无匹配的路由条目则直接丢弃。路由条目既可以手动设置静态路由,也可以通过路由协议自动生成动态路由。

路由器如何进行三层转发

当一台路由器收到一个数据包时,会执行如下步骤:

1,对数据包进行解封装。
通过解封装,查看网络层头部信息的 目的 IP 地址。

2,在路由表中查找匹配的路由条目。

查找匹配的路由条目,就需要将数据包的目的 IP 地址与各个路由条目的网段地址先进行二进制与( AND )运算,再将运算结果与路由条目的网段地址进行比较,若一致则该条目与目的 IP 地址相匹配。最后,与所有路由条目完成运算和比较,可得到一条或多条相匹配的路由条目。也可能没有匹配的路由条目,那么丢弃数据包。

微信截图_20210330104705.png

3,从多个匹配项中选择掩码最长的路由条目。

如果路由表中有多条路由条目都匹配数据包的目的 IP 地址,则路由器会选择掩码长度最长的路由条目,这种匹配方式称为最长匹配原则。

例如:10.1.3.10 的网络地址与 10.1.3.0/1610.1.3.0/24 两项都匹配,这时应该选择匹配度最长的 10.1.3.0/24

微信截图_20210330104813.png

4,将数据包按照相应路由条目进行转发。

路由条目中包含下一跳和出接口。当路由器找到相应的路由条目后,它就会根据对应的下一跳和出接口,将数据包从出接口发送数据给下一跳设备。

微信截图_20210330104927.png

IPv6

  IPv6(IP version 6)是为了根本解决 IPv4 地址耗尽的问题而被标准化的网际协议。IPv4 的地址长度为 4 个 8 位字节,即 32 比特。而 IPv6 的地址长度则是原来的 4 倍,即 128 比特,一般写成 8 个 16 位字节

IPv6 的特点

  • IP 地址的扩大与路由控制表的聚合。
  • 性能提升。包首部长度采用固定的值(40字节),不再采用首部检验码。简化首部结构,减轻路由器负担。路由器不再做分片处理。
  • 支持即插即用功能。即使没有 DHCP服务器 也可以实现自动分配 IP 地址。
  • 采用认证与加密功能。应对伪造 IP 地址的网络安全功能以及防止线路窃听的功能。
  • 多播、Mobile IP 成为扩展功能。

IPv6 中 IP 地址的标记方法

  一般人们将 128 比特 IP 地址以每 16 比特为一组,每组用冒号( : )隔开进行标记。而且如果出现连续的 0 时还可以将这些 0 省略,并用两个冒号(::)隔开。但是,一个 IP 地址中只允许出现一次两个连续的冒号。

IPv6 地址的结构

  IPv6 类似 IPv4,也是通过 IP 地址的前几位标识 IP 地址的种类。在互联网通信中,使用一种全局的单播地址。它是互联网中唯一的一个地址,不需要正式分配 IP 地址。

be1bff3dd05c4f999c7836ca26598c7d.jpeg

全局单播地址

  全局单播地址是指世界上唯一的一个地址。它是互联网通信以及各个域内部通信中最为常用的一个 IPv6 地址。

  格式如下图所示,现在 IPv6 的网络中所使用的格式为,n = 48,m = 16 以及 128 - n - m = 64。即前 64 比特为网络标识,后 64 比特为主机标识。

478cf4cd8c2b43339b80d7b667a6520a.jpeg

链路本地单播地址

  链路本地单播地址是指在同一个数据链路内唯一的地址。它用于不经过路由器,在同一个链路中的通信。通常接口 ID 保存 64 比特版的 MAC 地址。

d9e6580e7ce245aa9116004055f69b8b.jpeg

唯一本地地址

  唯一本地地址是不进行互联网通信时所用的地址。唯一本地地址虽然不会与互联网连接,但是也会尽可能地随机生成一个唯一的全局 ID。

  • L 通常被置为 1
  • 全局 ID 的值随机决定
  • 子网 ID 是指该域子网地址
  • 接口 ID 即为接口的 ID

8efd0df062b049978546f10dc3895af5.jpeg

IPv6 分段处理

  IPv6 的分片处理只在作为起点的发送端主机上进行,路由器不参与分片。

  IPv6 中最小 MTU 为 1280 字节,因此,在嵌入式系统中对于那些有一定系统资源限制的设备来说,不需要进行 路径MTU发现,而是在发送 IP 包时直接以 1280 字节为单位分片送出。

IP 协议相关技术

  IP 旨在让最终目标主机收到数据包,但是在这一过程中仅仅有 IP 是无法实现通信的。必须还有能够解析主机名称和 MAC 地址的功能,以及数据包在发送过程中异常情况处理的功能。

DNS

  我们平常在访问某个网站时不适用 IP 地址,而是用一串由罗马字和点号组成的字符串。而一般用户在使用 TCP/IP 进行通信时也不使用 IP 地址。能够这样做是因为有了 DNS (Domain Name System)功能的支持。DNS 可以将那串字符串自动转换为具体的 IP 地址。

  这种 DNS 不仅适用于 IPv4,还适用于 IPv6。

ARP

  地址解析协议,即 ARP(Address Resolution Protocol),是根据IP地址获取物理地址的一个 TCP/IP 协议。主机发送信息时将包含目标IP地址的 ARP 请求广播到局域网络上的所有主机,并接收返回消息,以此确定目标的物理地址;收到返回消息后将该IP地址和物理地址存入本机 ARP缓存 中,并保留一定时间,下次请求时直接查询 ARP缓存 以节约资源。

  地址解析协议是建立在网络中各个主机互相信任的基础上的,局域网络上的主机可以自主发送 ARP 应答消息,其他主机收到应答报文时不会检测该报文的真实性就会将其记入本机 ARP缓存;由此攻击者就可以向某一主机发送伪 ARP 应答报文,使其发送的信息无法到达预期的主机或到达错误的主机,这就构成了一个 ARP欺骗。ARP命令可用于查询本机 ARP缓存 中 IP 地址和 MAC 地址的对应关系、添加或删除静态对应关系等。相关协议有 RARP代理ARP。NDP用于在IPv6中代替地址解析协议。

  只要确定了 IP 地址,就可以向这个目标地址发送 IP 数据报。然而,在底层数据链路层,进行实际通信时,还要知道每个 IP 地址所对应的 MAC 地址。

  ARP 是一种解决地址问题的协议。以目标 IP 地址为线索,用来定位下一个应该接收数据分包的网络设备对应的 MAC 地址。不过 ARP 只适用于 IPv4,不能用于 IPv6。IPv6 中可以用 ICMPv6 替代 ARP 发送邻居探索消息。

RARP 是将 ARP 反过来,从 MAC 地址定位 IP 地址的一种协议。

ARP 的工作原理

当主机 A 向同一个网段内的主机 C 发送数据,但是不知道主机 C 的 MAC 地址。

微信截图_20210330105123.png

1,ARP 请求:主机 A 以主机 C 的 IP 地址为目的 IP 地址,以广播 MAC 地址为目的 MAC 地址,在同网段内发送这个广播报文,这个报文就叫 ARP 请求报文。

二层交换机不查看 IP 地址,根据目的 MAC 地址将报文除接收端口外的所有端口发送。

微信截图_20210330105217.png

2,ARP 响应:主机 C 发现目的 IP 地址是自己的 IP 地址,于是主机 C 以自己 MAC 地址和 IP 地址作为源 MAC 地址和源 IP 地址,以主机 A 的 MAC 地址和 IP 地址作为目的 MAC 地址和目的 IP 地址,发送响应报文给主机 A ,这个报文就叫 ARP 响应报文。其它主机收到主机 A 的 ARP 请求报文,因为目的 IP 地址不是自己的 IP 地址,因此不会进行响应。

当主机 A 在发送 ARP 广播请求报文时,二层交换机已经有主机 A 的 MAC 地址表条目。当收到主机 C 发送的单播 ARP 响应报文时,二层交换机将报文从相应端口发送出去。并将主机 C 的 MAC 地址和对应端口记录到 MAC 地址表中。

微信截图_20210330105326.png

3,更新 ARP 缓存表:主机 A 收到 ARP 响应报文后,将主机 C 的 IP 地址和 MAC 地址记录到 ARP 缓存表中。下次再向主机 C 发送数据时,直接将缓存的目的 MAC 地址进行封装。

微信截图_20210330105401.png

当主机 A 向不同网段的主机 C 发送数据,但是不知道主机 C 的 MAC 地址。

微信截图_20210330105435.png

1,主机 A 使用主机 C 的 IP 地址查询 ARP ,ARP 发现主机 C 不在同一个网段,需要通过默认网关(即默认路由的下一跳地址),但是没有网关 MAC 地址;

微信截图_20210330105523.png

2,主机 A 先将发送给主机 C 的数据放入缓存中,然后发送 ARP 请求报文,主机 A 以网关 IP 地址为目的 IP 地址发送 ARP 广播请求报文;

微信截图_20210330105548.png

3,路由器收到 ARP 广播请求报文后,将主机 A 的 MAC 地址和对应端口添加到自己的 MAC 表中,然后查看目的 IP 地址发现是请求自己的 MAC 地址,于是单播发送 ARP 响应报文;

微信截图_20210330105612.png

4,主机 A 收到 ARP 响应报文后,将发送给主机 C 的数据封装网关 MAC 地址为目的 MAC 地址进行发送;

微信截图_20210330105634.png

5,路由器收到报文后,查看目的 IP 地址,是发送给主机 C 的,于是查询路由表从相应端口发送数据。由于没有主机 C 的 MAC 地址,路由器发送 ARP 请求报文,源 MAC 地址和源 IP 地址替换为发送端口的MAC 地址和 IP 地址;

微信截图_20210330105656.png

6,主机 C 收到 ARP 请求报文后,添加路由器的端口和 MAC 地址到 MAC 地址表,单播发送 ARP 响应报文;

微信截图_20210330105715.png

7,路由器收到主机 C 的 MAC 地址后,将其添加到 MAC 地址表中。将主机 A 发送给主机 C 的报文重新封装,以自己的 MAC 地址为源 MAC 地址,以主机 C 的 MAC 地址为目的 MAC 地址,发送给主机 C ;

微信截图_20210330105737.png

8,主机 C 收到主机 A 发送的数据,发送过程结束。

当主机 C 向主机 A 发送回复报文时,同主机 A 向主机 C 发送数据的步骤一致。

ARP 代理

如果 ARP 请求是从一个网络的主机发往同一网段却不在同一物理网络上的另一台主机,那么连接它们的具有代理 ARP 功能的设备就可以回答该请求,这个过程称作 代理ARP 。

代理 ARP 功能屏蔽了分离的物理网络,让用户使用起来,跟在同一个物理网络上一样。

免费 ARP

免费 ARP 是一种特殊的 ARP 请求,它并非通过 IP 找到对应的 MAC 地址,而是当主机启动的时候,发送一个免费 ARP 请求,即请求自己的 IP 地址的 MAC 地址。

与普通 ARP 请求报文的区别在于报文中的目标 IP 地址。普通 ARP 报文中的目标 IP 地址是其它主机的 IP 地址;而免费 ARP 的请求报文中,目标 IP 地址是自己的 IP 地址。

微信截图_20210330110049.png

免费 ARP 的作用:

  • 起到一个宣告作用。它以广播的形式将数据包发送出去,不需要得到回应,只为了告诉其它主机自己的 IP 地址和 MAC 地址。
  • 可用于检测 IP 地址冲突。当一台主机发送了免费 ARP 请求报文后,如果收到了 ARP 响应报文,则说明网络内已经存在使用该 IP 地址的主机。
  • 可用于更新其它主机的 ARP 缓存表。如果该主机更换了网卡,而其它主机的 ARP 缓存表仍然保留着原来的 MAC 地址。这时,通过免费的 ARP 数据包,更新其它主机的 ARP 缓存表。

ICMP

IP 提供尽力而为的服务,指为了把数据包发送到目的地址尽最大努力。它并不做对端目的主机是否收到数据包的验证,无法保证服务质量。

  ICMP(Internet Control Message Protocol) Internet控制报文协议。它是 TCP/IP 协议簇的一个子协议,用于在IP主机、路由器之间传递控制消息。控制消息是指网络通不通、主机是否可达、路由是否可用等网络本身的消息。这些控制消息虽然并不传输用户数据,但是对于用户数据的传递起着重要的作用。

  ICMP 使用 IP 的基本支持,就像它是一个更高级别的协议,但是,ICMP 实际上是IP的一个组成部分,必须由每个IP模块实现。

  ICMP 的主要功能包括,确认 IP 包是否成功送达目标地址,通知在发送过程当中 IP 包被废弃的具体原因,改善网络设置等。

  IPv4 中 ICMP 仅作为一个辅助作用支持 IPv4。也就是说,在 IPv4 时期,即使没有 ICMP,仍然可以实现 IP 通信。然而,在 IPv6 中,ICMP 的作用被扩大,如果没有 ICMPv6,IPv6 就无法进行正常通信。

ICMP 报文像 TCP/UDP 一样通过 IP 进行传输,但是 ICMP 的功能不是传输层的补充,应该把它当做网络层协议。’

ICMP 头部封装字段如:

微信截图_20210330110618.png

通过类型字段和编码字段的取值判断这个 ICMP 消息的类型。常见的 ICMP 消息所对应的类型和编码值如下图。

微信截图_20210330110640.png

从功能上,ICMP 的消息分为两类:一类是通知出错原因的错误消息,另一类是用于诊断的查询消息。

微信截图_20210330110700.png

ping

我们常用的 ping 工具就是通过 ICMP 消息测试网络层连通性的。源主机发出 Echo request 消息,目的主机回应 Echo reply 消息,则两台主机间的网络层通信正常。也可以通过 ping 命令来判断目标主机是否启用。

微信截图_20210330110752.png

DHCP

  如果逐一为每一台主机设置 IP 地址会是非常繁琐的事情。特别是在移动使用笔记本电脑、只能终端以及平板电脑等设备时,每移动到一个新的地方,都要重新设置 IP 地址。

  于是,为了实现自动设置 IP 地址、统一管理 IP 地址分配,就产生了 DHCP(Dynamic Host Configuration Protocol)协议。有了 DHCP,计算机只要连接到网络,就可以进行 TCP/IP 通信。也就是说,DHCP 让即插即用变得可能。

   DHCP (Dynamic Host Configuration Protocol,动态主机配置协议) 是一个局域网的网络协议,使用UDP协议工作,指的是由服务器控制一段IP地址范围,客户机登录服务器时就可以自动获得服务器分配的IP地址和子网掩码。默认情况下,DHCP作为 Windows Server 的一个服务组件不会被系统自动安装,还需要管理员手动安装并进行必要的配置。

  主要有两个用途:给内部网络或网络服务供应商自动分配IP地址,给用户或者内部网络管理员作为对所有计算机作中央管理的手段。

  在RFC 2131中有详细的描述,DHCP有3个端口,其中 UDP67UDP68 为正常的 DHCP 服务端口,分别作为 DHCP ServerDHCP Client 的服务端口;546号端口用于 DHCPv6 Client,而不用于 DHCPv4 ,是为 DHCP failover 服务,这是需要特别开启的服务,DHCP failover 是用来做双机热备的。

DHCP 不仅在 IPv4 中,在 IPv6 中也可以使用。

NAT

  NAT(Network Address Translator)是用于在本地网络中使用私有地址,在连接互联网时转而使用全局 IP 地址的技术。

  除转换 IP 地址外,还出现了可以转换 TCP、UDP 端口号的 NAPT(Network Address Ports Translator)技术,由此可以实现用一个全局 IP 地址与多个主机的通信。

  NAT(NAPT)实际上是为正在面临地址枯竭的 IPv4 而开发的技术。不过,在 IPv6 中为了提高网络安全也在使用 NAT,在 IPv4 和 IPv6 之间的相互通信当中常常使用 NAT-PT

IP隧道

e11421fc61d14423adab54661884f497.jpeg

夹着 IPv4 网络的两个 IPv6 网络

  如上图的网络环境中,网络A 网络B 之间无法直接进行通信,为了让它们之间正常通信,这时必须得采用 IP 隧道的功能。

  IP 隧道可以将那网络A 发过来的 IPv6 的包统合为一个数据,再为之追加一个 IPv4 的首部以后转发网络C。

  一般情况下,紧接着 IP 首部的是 TCP 或 UDP 的首部。然而,现在的应用当中 “IP首部的后面还是 IP首部” 或者 “IP首部 的后面是 IPv6的首部” 等情况与日俱增。这种在网络层的首部后面追加网络层首部的通信方法就叫做 “IP隧道”。

扩展:运行在传输层中的 TCP 和 UDP 的协议

每一个应用层(TCP/IP参考模型的最高层)协议一般都会使用到两个传输层协议之一:

运行在 TCP协议上的协议:

  • HTTP(HypertextTransferProtocol,超文本传输协议),主要用于普通浏览。
  • HTTPS(HTTP over SSL,安全超文本传输协议), HTTP协议的安全版本。
  • FTP(FileTransferProtocol,文件传输协议),用于文件传输。
  • POP3(PostOfficeProtocol,version3,邮局协议),收邮件用。
  • SMTP(SimpleMailTransferProtocol,简单邮件传输协议),用来发送电子邮件。
  • TELNET(Teletypeover theNetwork,网络电传),通过一个 终端(terminal)登陆到网络。
  • SSH(SecureShell,用于替代安全性差的TELNET),用于加密安全登陆用。

运行在 UDP协议上的协议:

  • BOOTP(BootProtocol,启动协议),应用于无盘设备。
  • NTP(NetworkTimeProtocol,网络时间协议),用于网络同步。
  • DHCP(DynamicHostConfigurationProtocol,动态主机配置协议),动态配置IP地址。

运行在 TCP和 UDP协议上:

  • DNS(DomainNameService,域名服务),用于完成地址查找,邮件转发等工作。

参考:

https://www.sohu.com/a/339068354_774177

71张图详解IP 地址、IP 路由、分片和重组、三层转发、ARP、ICMP

https://blog.csdn.net/weixin_44630560/article/details/108100907

网络掩码

  子网掩码是在IPv4地址资源紧缺的背景下为了解决lP地址分配而产生的虚拟lP技术,通过子网掩码将A、B、C三类地址划分为若干子网,从而显著提高了IP地址的分配效率,有效解决了IP地址资源紧张的局面。如果是都是使用的IPV6的话是没有子网掩码的概念。IPV6是端到端的连接通信,不需要子网了。

  网络掩码做为一个辅助工具,可以帮助主机区分以上三种情况,所以网络掩码是必不可少的,和IP地址如影相随。最初的网络掩码长度为8的整数倍,8、16、24、32,这里的长度为二进制的长度,即一个字节长度的整数倍。

概念 特征 网络范围 默认掩码
A类地址 第1个8位中的第1位始终为0 0-127.x.x.x 255.0.0.0/8
B类地址 第1个8位中的第1、2位始终为10 128-191.x.x.x 255.255.0.0/16
C类地址 第1个8位中的第1、2、3位始终为110 192-y.x.x.x 255.255.255.0/24

1.1.1.1/8
这个组合经常出现的路由器的配置里,其中 1.1.1.1 为IP地址。 /8 表示网络掩码的长度,8个二进制长度。

172.16.1.1/16
172.16.1.1 为IP地址。/16 表示网络掩码的长度,16个二进制长度。

192.168.1.1/24
192.168.1.1 为IP地址。/24表示网络掩码的长度,24个二进制长度。

127.0.0.1/32
127.0.0.1 为IP地址。/32 表示网络掩码的长度,32个二进制长度。

子网掩码

如果不对掩码长度是8的整数倍做强制要求,那么就实现精细化的子网掩码。

CIDR :( Classless Inter-Domain Routing,元类域间路由选择).我们需要了解这种网络表示法。形式如:192.168.10.32/28。前面的数字是我们的网络地址,后面的28表示用28位来表示网络位,用32-28=4位来表示主机位。通过这种记法,我们能明确两个信息:
网络地址:192.168.10.32
子网掩码:255.255.255.240

通过下表我们能明确 子网掩码斜杠表示法 之间的关系:

1679092-20190709175902328-586874586.png
1679092-20190709175913957-2145237488.png

其中 /8-/15 只能用于A类网络,/16-/23 可用于A类和B类网络,而 /24-/30 可用于A类、B类和C类网络。这就是大多数公司都使用A类网络地址的一大原因,因为它们可使用所有的子网掩码,进行网络设计时的灵活性最大。

假设现有一IP地址 180.210.242.131,即 10110100.11010010.11110010.10000011
同时指定子网掩码为 255.255.248.0  即 11111111.11111111.11111000.00000000,则

网络号:两者进行与运算,即 10110100.11010010.11110000.00000000(180.210.240.0)
主机号:子网掩码取反再和IP做与运算,即 00000000.00000000.00000010.10000011(0.0.2.131)
子网号:这个IP本来是B类地址,默认的子网掩码是 255.255.0.0,所以本来的网络号是16位,但它实际网络号是21位,就是借了5位网络位,所以可以划分 2^5 个子网,即32个,实际使用30个,这个网段可以容纳主机 2^11 个,即2048个,有效2046个一头一尾分别做网络号和广播。

从前有一个地主,有256间房子,地主家的门牌号码是 192.168.1,那么他家第一间房子的门牌号码是 192.168.1.0 ,第二间是 192.168.1.1,……第256间的编号是 192.168.1.255

地主老了,需要把256间房子分给4个儿子,平均分配,每个儿子可以分64间。

请来一位先生主持公道,先生这么来操作:

192.168.1.0-192.168.1.63 分给大儿子
192.168.1.64-192.168.1.127 分给二儿子
192.168.1.128 -192.168.1.191 分给三儿子
192.168.1.192-192.168.1.255 分给四儿子

如何来描述四个儿子的子网网段呢?

1
2
3
4
192.168.1.0/26
192.168.1.64/26
192.168.1.128/26
192.168.1.192/26

/26 解析

255.255.255.192 的二进制是:11111111-11111111-11111111-11 总共是26个1,为了简化子网掩码的表示,用 /26 代替 255.255.255.192

按位与运算我们来看大儿子的网段 192.168.1.0/26 是如何得到的?

以大儿子的房间为例:192.168.1.0-192.168.1.63

二进制表示:

192.168.1.0 对于二进制:11000000.10101000.00000001.00000000

192.168.1.63 对于二进制:11000000.10101000.00000001.00111111

首尾地址完全相同的是: 11000000.10101000.00000001.00,总共26位!那么用这个 192.168.1.0/26 就可以表示大儿子所有房间。

对照房间的门牌号码 192.168.1.199,很显然属于四儿子的。

Q1:一个主机 192.168.1.199/26 能否和直连主机 192.168.1.200/24 通信?

可以的,因为都是四儿子的房间。

Q2:一个主机 192.168.1.199/26 能否和直连主机 192.168.1.1/24 通信?

不可以,因为一个是大儿子的房间,一个是四儿子的房间,无法直连通信!

参考:

子网掩码有那么难吗?

最大报文段长度(MSS)是TCP协议的一个选项,用于在TCP连接建立时,收发双方协商通信时每一个报文段所能承载的最大数据长度(不包括文段头)。

开放式互联网模型

开放式系统互联模型(OpenSystemInterconnection Model,简称为OSI模型)是一种互联网概念化模型,由国际标准化组织(InternationalOrganization forStandardization,简称为ISO)提出,定义于ISO/IEC 7498-1。OSI模型将互联网分为七层,由最高层(用户端)到最底层(物理层面)排列为:

  • 第7层 应用层(Application Layer);
  • 第6层 表达层(Presentation Layer);
  • 第5层 会话层(Session Layer);
  • 第4层 传输层(Transport Layer);
  • 第3层 网络层(Network Layer);
  • 第2层 数据链接层(Data Link Layer);
  • 第1层 物理层(Physical Layer);

MSS是第四层传输层中的一种协议(TCP)的选项之一。

503d269759ee3d6d55fbf8fa925e7a224f4a20a470e3.png

区分MSS与MTU

最大报文段长度(MSS)与最大传输单元(Maximum Transmission Unit, MTU)均是协议用来定义最大长度的。不同的是,MTU应用于OSI模型的第二层数据链接层,并无具体针对的协议。MTU限制了数据链接层上可以传输的数据包的大小,也因此限制了上层(网络层)的数据包大小。例如,如果已知某局域网的MTU为1500字节,则在网络层的因特网协议(Internet Protocol, IP)里,最大的数据包大小为1500字节(包含IP协议头)。MSS针对的是OSI模型里第四层传输层的TCP协议。因为MSS应用的协议在数据链接层的上层,MSS会受到MTU的限制。

d009b3de9c82d158ccbfd28051420ed8bc3eb135e4e3.png

IPv4 Header结构

P 提供最简单的服务:实现从源到目的的数据转发。不会在传输数据前先与接收方建立连接,也不保证传输的可靠性,它只提供尽力而为的服务。

IP 通信时传输的是 IP 报文, IP 报文由 IP 头部和数据两部分组成。IP 头部包含控制报文转发的必要信息。通过 IP 头部的结构,可以对 IP 的功能有一个详细的了解。

2015-04-14-3.jpg

微信截图_20210330111145.png

版本( Version )

字段长度为 4 比特,表示 IP 的版本号。IPv4 的版本号是 4 ,所以这个字段的值也是 4 。常见的版本号有 IPv4 和 IPv6 。

头部长度( IHL:Internet Header Length )

字段长度为 4 比特,表示 IP 头部大小,单位是 4 字节( 32 比特)。没有可选项的 IP 包,头部长度为 5 ,即 20 字节( 4 × 5 = 20 )。

区分服务( TOS:Type Of Service )

字段长度为 8 比特,用来说明数据是要加速传输还是精确传输,以及数据在传输过程中是否遇到了拥塞。

总长度( Total Length )

字段长度为 16 比特,表示 IP 头部和数据加起来的总字节数。IP 包的最大长度为 65535 字节。

标识( ID:Identification )

字段长度为 16 比特,用于分片重组。同一个分片的标识值相同,不同分片的标识值不同。通常,每发送一个 IP 包,它的值也逐渐递增。另外,即使 ID 相同,如果目标地址、源地址或协议不同的话,也会被认为是不同的分片。

标志( Flags )

字段长度为 3 比特,表示分片信息。每比特的具体含义如下表。

微信截图_20210330111238.png

分片偏移( FO:Fragment Offset )

字段长度为 13 比特,表示分片在整个数据包中的位置。作用是告诉重组分片的设备,应该按照什么样的顺序重组数据包。

生存时间( TTL:Time To Live )

字段长度为 8 比特,表示数据包可以经过的中转路由器数量。每经过一个路由器, TTL 会减少 1 ,直到变成 0 则丢弃改包,避免数据包在网络中无限传递。

注意:TTL与DNS TTL有区别。二者都是生存时间,前者指ICMP包的转发次数(跳数),后者指域名解析信息在DNS中的存在时间。

协议( Protocol )

字段长度为 8 比特,表示 IP 上一层所使用的协议。常见的 IP 上层协议有 TCP 和 UDP 。

微信截图_20210330111316.png

头部校验和( Header Checksum )

字段长度为 16 比特,用来校验数据包的头部是否被破坏。设备会丢弃校验失败的数据包。IPv6 以取消头部校验和字段,通过上层的 TCP 或 UDP 校验协议是否正确。

源地址( Source Address )

字段长度为 32 比特( 4 字节),表示发送端 IP 地址。

目的地址( Destination Address )

字段长度为 32 比特( 4 字节),表示接收端 IP 地址。

可选项( Options )

这个字段很少使用,在 IPv6 协议中已经取消。

填充( Padding )

在有可选项的情况下, 头部长度不是 32 比特的整数倍时,通过向字段填充 0 ,调整为 32 比特的整数倍。

数据( Data )

IP 数据字段,用于存放数据。把 IP 上一层协议的头部也作为数据进行处理。

参考:

https://abcdxyzk.github.io/blog/2015/04/14/kernel-net-sock-raw/

ethernet-frame.gif

octets:(Bytes)字节
Frame:帧

d009b3de9c82d158ccbfd28051420ed8bc3eb135e4e3.png

20210127194819642.png

Ethernet帧格式历史

1980 DEC,Intel,Xerox 制订了 Ethernet I 的标准

1982 DEC,Intel,Xerox 又制订了 Ehternet II 的标准

1982 IEEE 开始研究 Ethernet 的国际标准 802.3

1983 迫不及待的 Novell 基于 IEEE 802.3 的原始版开发了专用的 Ethernet 帧格式 (因此 802.3 Raw 先于 IEEE 802.3 出台.)

1985 IEEE 推出 IEEE 802.3 规范,

后来为解决 Ethernet II 与 802.3 帧格式 的兼容问题,推出折衷的 Ethernet SNAP 格式

(其中早期的 Ethernet I 已经完全被其他帧格式取代了 ,所以现在 Ethernet 只能见到后面几种 Ethernet的帧格式,现在大部分的网络设备都支持这几种 Ethernet 的帧格式,如:cisco 的路由器再设定 Ethernet 接口时可以指定不同的以太网的帧格式:arpa,sap,snap,novell-ether)

今天的实际环境中大多数TCP/IP设备都使用Ethernet V2格式的帧。
这是因为第一种大规模使用的TCP/IP系统(4.2/3 BSD UNIX)的出现时间介于RFC 894和RFC 1042之间,
它为了避免不能和别的主机互操作的风险而采用了RFC 894的实现;
也由于大家都抱着这种想法,所以 802.3 标准并没有如预期那样得到普及;

CISCO设备的Ethernet Interface默认封装格式是ARPA(Ethernet V2)

不同厂商对这几种帧格式不同的叫法

Frame Type Novell公司 Cisco 公司
Ethernet Version 2 Ethernet_II arpa
802.3 Raw Ethernet_802.3 novell_ether
IEEE 802.3/802.2 Ethernet_802.2 sap
IEEE 802.3/802.2 SNAP ETHERNET_SNAP snap

帧格式

Ethernet I (V1)

这是最原始的一种格式,是由 Xerox PARC 提出的 3Mbps CSMA/CD 以太网标准的封装格式,
后来在1980年由 DEC,Intel 和 Xerox 标准化形成 Ethernet V1 标准;

Ethernet II (V2) (ARPA)

这是最常见的一种以太网帧格式,也是今天以太网的事实标准,由DEC,Intel 和Xerox [简称 DIX以太网联盟] 在1982年公布其标准,主要更改了Ethernet V1 的电气特性和物理接口, 在帧格式上并无变化;Ethernet V2 出现后迅速取代 Ethernet V1 成为以太网事实标准;

Ethernet V2 帧头(Frame Header)结构为: 6bytes的源地址(源MAC) + 6bytes的目标地址(目标MAC) + 2Bytes协议类型字段(用于标示封装在这个 Frame 里面数据的类型),
数据长度 46–1500 Bytes,4Bytes的帧校验。

Ethernet V2 类型以太网帧的最小长度为64字节(6+6+2+46+4),最大长度为1518字节(6+6+2+1500+4)。

常见协议类型如下:

0x0800   IP协议数据,
0x86dd   IPv6协议数据,
0x809B   AppleTalk协议数据,
0x8138   Novell类型协议数据等。
0x0806   ARP
0x0600   XNS (Xerox)
0x6003   DECNET

如果协议类型字段取值为0000-05dc(十进制的0-1500),则该帧就不是 Ethernet V2(ARPA) 类型了,而是下面的三种 802.3帧 类型之一;

Ethernet V2 可以支持 TCP/IP,Novell IPX/SPX,Apple Talk Phase I 等协议;RFC 894 定义了IP报文在Ethernet V2 上的封装格式;

Novell Ethernet (802.3 Raw) novell_ether

这是1983年 Novell 发布其划时代的 Netware/86 网络套件时,采用的私有以太网帧格式,该格式以当时尚未正式发布的 802.3 标准为基础;

但是当两年以后 IEEE正式发布 802.3 标准时情况发生了变化 — IEEE 在802.3帧头中又加入了802.2 LLC(Logical Link Control)头,这使得 Novell 的 802.3 RAW 格式跟正式的 IEEE 802.3 标准互不兼容;可以看到在 Novell 的 RAW 802.3 帧结构中并没有标志协议类型的字段,而只有 Length 字段(2bytes,取值为0000-05dc,即十进制的0-1500),因为 RAW 802.3帧 只支持 IPX/SPX 一种协议;

802.3 Raw 帧头与 Ethernet 帧头有所不同,其中 Ethernet II 帧头中的类型域变成了长度域,后面接着的两个字节为 0xFFFF,用于标示这个帧是 Novell Ether 类型的 Frame,由于前面的 0xFFFF 站掉了两个字节所以数据域缩小为 44-1498 个字节,帧校验不变。

802.3Raw.png

  • 目标地址:此数据包的目标MAC地址。
  • 源地址:此数据包的源MAC地址。
  • 长度:帧包含的数量必须或等于 1500。(在 Ethernet 802.3 raw 类型以太网帧中,原来 Ethernet II 类型以太网帧中的类型字段被”总长度”字段所取代,它指明其后数据域的长度,其取值范围为:46-1500。)
  • 数据:高层协议(IPX/SPX)、数据和填充符,范围在46~1500字节。(长度紧跟着的接下来的2个字节是固定不变的16进制数 0xFFFF,它标识此帧为 Novell 以太类型数据帧。)
  • FCS:数据帧校验序列,用于确定数据包在传输过程中是否损坏。

这是IEEE 正式的 802.3 标准,它由 Ethernet V2 发展而来。

IEEE 802.3 的 Frame Header 和 Ethernet II 的帧头有所不同,IEEE 802.3 将 Ethernet V2 帧头的协议类型字段替换为帧长度字段(取值为0000-05dc;十进制的1500)。

其中又引入 802.2 协议(LLC,Logical Link Control) 在 802.3 帧头后面添加了一个 LLC 首部,LLC头包含目的 服务访问点(DSAP,Destination Service Access Point)、源服务访问点(SSAP,Source Service Access Point)和 控制(Control)字段。

IEEE 802.3 把 DLC (数据链路控制,Digital Loop Carrier) 层分隔成明显的两个子层:MAC 层和 LLC 层,其中 MAC 层主要是指示硬件目的地址和源地址,LLC层用来提供一些服务:

  • 通过SAP地址来辨别接收和发送方法
  • 兼容无连接和面向连接服务
  • 提供子网访问协议(Sub-network Access Protocol,SNAP),类型字段即由它的首部给出。

MAC层要保证最小帧长度不小于64字节,如果数据不满足64字节长度就必须进行填充。

利用 Sniffer 等协议分析工具去捕获的 IEEE 802.3 帧的解码,可以看到在 DLC 层源地址后紧跟着就是 802.3 的长度(Length)字段 0026,它小于 05FF(二进制1535),可以肯定它不是 Ethernet V2 的帧,而接下来的 Offset 0E 处的值 4242 (代表DSAP和SSAP),既不是 Novell 802.3 Raw 的特征值 FFFF ,也不是 IEEE 802.3 SNAP 的特征值 AAAA ,因此它肯定是一个 IEEE 802.3 的帧。

以太网类型码:

ETHERNET_type_code.png

decimal:十进制
octal:八进制

802.2 SAP (Service Access Point) 介绍

为了区别 802.3 数据帧中所封装的数据类型,IEEE 引入了 802.2 SAP 和 SNAP 的标准。它们工作在数据链路层的 LLC(逻辑链路控制)子层。

通过在802.3帧的数据字段中划分出被称为服务访问点(SAP)的新区域来解决识别上层协议的问题,这就是 802.2 SAP。

LLC标准 介绍

LLC 标准包括两个服务访问点,源服务访问点(SSAP)和目标服务访问点(DSAP)。每个SAP只有1字节长,而其中仅保留了6比特用于标识上层协议,所能标识的协议数有限。

因此,又开发出另外一种解决方案,在 802.2 SAP 的基础上又新添加了一个 2字节长的类型域(同时将SAP的值置为AA),使其可以标识更多的上层协议类型,这就是 802.2 SNAP。

常见SAP值:

  • 0:Null LSAP[IEEE]
  • 4:SNA Path Control[IEEE]
  • 6:DOD IP[79,JBP]
  • AA:SNAP[IEEE]
  • FE:ISO DIS 8473[52,JXJ]
  • FF:Global DSAP[IEEE]

IEEE_802.3.png

  • 目标地址:此数据包的目标mac地址;
  • 源地址:此数据包的源mac地址;
  • 长度:帧包含的数据量必须小于或等于1500(16进制的05DC);
  • DSAP:目标服务存取点(Destination Service Access Point);
  • SSAP:源服务存取点(Source Service Access Point);
  • 控制:无连接或面向连接的C;
  • 数据:高层协议、数据和填充符;
  • FCS:数据帧校验序列,用于确定数据包在传输过程中是否损坏。

Ethernet SNAP (IEEE 802.3/802.2 SNAP, ETHERNET_SNAP, snap)

SNAP (Sub-Network Access Protocol)子网访问协议,是逻辑链路控制(Logical Link Control)的一个子集,它允许协议不用通过 服务访问点(SAP)即可实现 IEEE 兼容的 MAC 层功能,因此它在 DSAP 和 SSAP域里的值是固定的 (AAAA)。也正源于此,它需要额外提供5个字节的头来指定接收方法,3个字节标识厂商代码,2个字节标识上层协议。

其 MAC 层保证数据帧长度不小于64字节,不足的话需要进行数据填充。

Sniffer 捕获的 IEEE 802.3 SNAP 帧的解码,可以看到在 DLC 层源地址后紧跟着就是 802.3 的长度(Length)字段 0175,它小于 05FF,可以肯定它不是 Ethernet V2 的帧,而接下来的 Offset 0E 处的值 AAAA (代表DSAP和SSAP),这是 IEEE 802.3 SNAP 的特征值 AAAA ,因此可以断定它是一个 IEEE 802.3 SNAP 的帧。

SNAP Frame 与 802.3/802.2 Frame 的最大区别是增加了一个 5 Bytes 的 SNAP ID,其中前面3个byte通常与源mac地址的前三个bytes相同为厂商代码,有时也可设为0,后2 bytes 与 Ethernet II 的类型域相同。

ETHERNET_SNAP.png

小结

Frame Type Header & CRC Data Min Data Max
Ethernet II (DIX) 18 46 1500
802.3 (IEEE) 21 43 1497
SNAP 26 38 1492
  • Ethernet II 和 IEEE 802.3 是局域网里最常见的帧
  • Ethernet II 可以装载的数据长度是46—1500;
  • IEEE802.3 SAP 可以装装的数据长度是43—1497;
  • IEEE 802.3 SNAP 可以装载的数据长度是38—1492;
  • Ethernet II 不提供 MAC 层的数据填充功能;
  • IEEE802.3 SAP 和 SNAP 都提供数据填充功能.

Ethernet V2 帧与IEEE 802.3 帧的比较

Ethernet V2 可以装载的最大数据长度是1500字节,而 IEEE 802.3 可以装载的最大数据是1492字节(SNAP)或是1497字节; Ethernet V2 不提供 MAC层 的数据填充功能,而 IEEE 802.3 不仅提供该功能,还具备服务访问点(SAP)和 SNAP 层,能够提供更有效的数据链路层控制和更好的传输保证。那么我们可以得出这样的结 论:Ethernet V2 比 IEEE 802.3 更适合于传输大量的数据,但 Ethernet V2 缺乏数据链路层的控制,不利于传输需要严格传输控制的数据,这也正是 IEEE 802.3 的优势所在,越需要严格传输控制的应用,越需要用 IEEE 802.3或 SNAP 来封装,但 IEEE 802.3 也不可避免的带来数据装载量的损失,因此该格式的封装往往用在较少数据量承载但又需要严格控制 传输的应用中。

在实际应用中,我们会发现,大多数应用的以太网数据包是 Ethernet V2 的帧(如HTTP、FTP、SMTP、POP3等应用),而交换机之间的BPDU(桥协议数据单元)数据包则是IEEE 802.3的帧,VLAN Trunk 协议如 802.1Q 和Cisco的CDP(思科发现协议)等则是采用 IEEE 802.3 SNAP 的帧。可以利用Sniffer等协议分析工具去捕捉数据包。

参考:

以太网帧与ieee 802.3帧

以太网类型码(Ethernet type codes)

Ethernet frame

ETHERNET帧结构

车小胖谈网络:Ethernet Frame

循环冗余检验CRC是一种检验方法,而FCS是添加在数据后面的帧检验序列。CRC 检验只能保证接收端接收到的帧没有差错,至于有没有出现帧丢失,帧重复,帧失序,是无法判断的。

CRC

循环冗余校验(Cyclic Redundancy Check, CRC)是一种根据网络数据包或计算机文件等数据产生简短固定位数校验码的一种信道编码技术(算法),主要用来检测或校验数据传输或者保存后可能出现的错误。它是利用除法及余数的原理来作错误侦测的。

FCS

帧校验序列码 FCS ( Frame Check Sequences) 是为提高通信的可靠性设置的。将每一帧中的第一个字符@到该帧中正文的最后一个ASCII 字符作“异或”运算, 并将异或的结果转换为两个ASCII码, 便得到了FCS , 它作为帧的一部分发送到接收端。接收端计算出收到的帧的FCS , 如果与发送端传送过来的FCS 不同, 可以判定通信有误。

帧校验序列(FCS)是指特别的检测码字符被添加到在一个通信协议中的帧中进行检错和纠错。发送主机在整个帧中有一个检测码随着发送。接收主机在整个帧中的检测码使用相同的运算法则,并将它与接收到的 FCS 相比较。这样,它能够探测是否任何数据在运输中丢失或被改变。它可能当时丢失这个数据,和请求错误帧的重传。一个循环冗余码校验常被用来估算 FCS。

FCS 字段:包含帧的 32 位循环冗余校验 (CRC), 数据链路层帧方式接入协议(LAPF)中的字段,是一个16比特的序列。它具有很强的检错能力,它能检测出在任何位置上的 3 个以内的错误、所有的奇数个错误、16个比特之内的连续错误以及大部分的大量突发错误。

ethernet-frame.gif

octets:(Bytes)字节
Frame:帧

参考:

循环冗余检验算法(CRC)与帧检验序列(FCS)

帧检验序列(FCS)

最大传输单元(Maximum Transmission Unit,MTU)用来通知对方所能接受数据服务单元的最大尺寸,说明发送方能够接受的有效载荷大小。
是包或帧的最大长度,一般以字节记。如果MTU过大,在碰到路由器时会被拒绝转发,因为它不能处理过大的包。如果太小,因为协议一定要在包(或帧)上加上包头,那实际传送的数据量就会过小,这样也划不来。大部分操作系统会提供给用户一个默认值,该值一般对用户是比较合适的。

简介

以太网和802.3对数据帧的长度都有一个限制,其最大值分别是1500字节和1492字节。链路层的这个特性称为MTU,即最大传输单元。不同类型网络的数帧长度大多数都有一个上限。如果IP层有一个数据报要传,而且数据帧的长度比链路层的MTU还大,那么IP层就需要进行分片( fragmentation),即把数据报分成干片,这样每一片就都小于MTU。

当同一个网络上的两台主机互相进行通信时,该网络的MTU是非常重要。但是如果两台主机之间的通信要通过多个网络,每个网络的链路层可能有不同的MTU,那么这时重要的不是两台主机所在网络的MTU的值,而是两台主机通信路径中的最小MTU,称为 路径 MTU( Path mtu,PMTU)。

两台主机之间的PMTU不一定是个常数,它取决于当时所选择的路径,而且路由选择也不一定是对称的(从A到B的路由可能与从B到A的路由不同),因此,PMTU在两个方向上不一定是一致的。
RFC1191描述了PMTU的发现机制,即确定路径MTU的方法。ICMP的不可到达错误采用的就是这种方法, traceroute程序也是用这种方法来确定到达目的节点的PMT的。

MTU字节

在远端节点的配置响应中将包含在该信道使用的实际的MTU大小,信道的方向是流向本地节点,MTU值取在configReq中的MTU和远端节点的输出MTU能力中最小值。该MTU只能用于这个信道,不能用于相反方向的信道。
MTU字段:2个字节。

MTU字段表示发起请求方可以接受的最大的L2CAP分组净荷(按字节计)。MTU是非对称的,请求的发送方指定在该信道上它可以接收的MTU值。L2CAP的实现必须支持最小的48字节的MTU值。缺省值是672字节。

用途

MTU是网络调节的重要因素,因为包中的额外开销量相当高。高的MTU减少了头信息浪费的字节数。对大量数据传输尤其重要,而对小于MTU的传输没有影响。因此,注意配置传输大量数据流的服务器(如文件服务器和FTPH&.务器)上的MTU。

选择MTU时,规则是选择传输中不需分段的最大MTU。如果网络使用一种媒体类型,缺省的设置就可以。选择比媒体最大值更小的MTU并没有好处,整个数据报会因为每个包的错误而重发。换言之,不能重发单个段。

IP分片与重组

数据链路不同,最大传输单元( Maximum transmission Unit,MTU)也不同,由于IP协议是数据链路的上一层,所以它必须不受数据链路的MTU大小的影响能够加以利用。当IP数据报太大时,就要采用分片技术,以保证数据帧不大于要过的网络的MTU。

IP协议除了具有路由寻址功能外,另一个重要的功能就是IP数据报的分片处理。每个数据链路层能够确定发送的一个帧的最大长度称为最大传输单元。在Ethernet中,MTU为1500字节;在FDDI中,MTU为4352字节;在 IP over ATM中,MTU为9180字节。

如果要发送的IP数据报比数据链路层的MTU大,则无法发送该数据报。对于来自于上一层的IP协议,当要求发送的IP数据报比数据链路层的MTU大时,必把该数据报分割成多个IP数据报才能发送。另外,在进行通信的各台主机之间,存在着MTU不同的数据链路;在发送的过程中,也有MTU缩小的情况发生。当出现上述情况时,在发送过程中必须有一台能够进行分片处理的路由器。

接收端主机必须对经过分片处理后的IP数据报进行还原处理。在中继路由器中,虽然路由器进行了分片处理,但并不进行还原处理。另外,经分片处理的IP数据报只有经过还原处理后才能还原成原来的IP数据报,才可以向上一层的模块传递数据。

d009b3de9c82d158ccbfd28051420ed8bc3eb135e4e3.png

参考:

最大传输单元

查看Linux内核版本

1
2
cat /proc/version
uname -a

查看Linux系统版本

1
2
3
4
5
6
7
8
9
10
# 这个命令适用于所有的Linux发行版,包括RedHat、SUSE、Debian…等发行版。
# 如果未安装,需要命令:yum install redhat-lsb -y
lsb_release -a

# 只适合Redhat系的Linux
cat /etc/redhat-release
file /bin/bash

# 适用于所有的Linux发行版
cat /etc/issue