【Linux 网络】网络基础(二)(应用层协议:HTTP、HTTPS)-- 详解

我们程序员写的一个个解决我们实际问题,满足我们日常需求的网络程序,都是在应用层。

前面写的套接字接口都是传输层经过对 UDP 和 TCP 数据发送能力的包装,以文件的形式呈现给我们,让我们可以进行应用层编程。换而言之,前面写的所有套接字代码全都属于应用层开发。


一、协议

协议本质就是一种 “约定”。socket api 的接口在读写数据时,都是按 “字符串” 的方式来发送接收的。


1、序列化与反序列化的概念

如果我们要传输一些 “结构化的数据” 怎么办呢?

通过前面的学习,知道了 TCP 是面向字节流的方式进行通信的。

如何保证刚度读到一个完整的数据呢?

举例:我们使用 QQ 发送消息时,别人接收到的不只有消息,还包含了用户昵称、头像信息、消息内容、发送时间等,这就叫做结构化的数据这些结构化的数据可以打包成一个报文(变成一个整体),这个过程就叫作序列化,而把这个整体报文解开的过程就叫做反序列化

结构化数据要先序列化,再发送到网络中,收到序列字节流后,要先反序列化再使用。而这里序列化和反序列化的过程用的就是业务协议


2、自定义协议实现网络版计算器

例如,我们需要实现一个服务器版的加法器。我们需要客户端把要计算的两个加数发过去,然后由服务器进行计算,最后再把结果返回给客户端。


(1)约定方案

A. 约定方案一
  • 客户端发送一个形如 "1+1" 的字符串。
  • 这个字符串中有两个操作数,都是整形。
  • 两个数字之间会有一个字符是运算符,运算符只能是 +。
  • 数字和运算符之间没有空格。
  • ... ...

B. 约定方案二
  • 定义结构体来表示我们需要交互的信息。
  • 发送数据时将这个结构体按照一个规则转换成字符串,接收到数据的时候再按照相同的规则把字符串转化回结构体,这个过程叫做 “序列化” 和 “反序列化”。
// proto.h 定义通信的结构体
typedef struct Request {
    int a;
    int b;
    char op;
} Request;

typedef struct Response {
    int result;
    int code;
} Response;

// client.c 客户端核心代码
Request request; 
Response response; 
scanf("%d,%d", &request.a, &request.b);
write(fd, request, sizeof(Request));
read(fd, response, sizeof(Response)); 

// server.c 服务端核心代码
Request request;
read(client_fd, &request, sizeof(request));
Response response;
response.sum = request.a + request.b;
write(client_fd, &response, sizeof(response));

无论是采用方案一,还是方案二,亦或是其他的方案,只要保证一端发送时构造的数据在另一端能够正确的进行解析,就是可以的。这种约定就是应用层协议。 


(2)准备工作 

  • const std::string &:输入型参数
  • std::string *:输出型参数
  • std::string &:输入输出型参数

(3)服务端

自定义协议里要包含两各类,一个是请求,一个是响应服务端会收到请求,客户端收到响应。

请求就是左操作符、右操作符和符号。
响应包含了退出码和结果,如果正常结束退出码为 0,如果有错误,可以自定义不同的退出码表示不同的错误。

为什么要有计算结果的状态码?

因为在计算的过程中可能会出现异常,比如除 0 或模 0,输入的操作码 op 不属于我们规定的符号。状态码为 0 表示计算结果正确,状态码为其它数字表示不同出错含义。


A. 服务端业务处理流程

服务端处理数据流程

客户端发过来的数据已经序列化成了一个序列字节流数据(报文),所以服务端要先把报文反序列化,构成一个结构化请求对象 Request,然后就可以进行计算处理,形成一个 Response 对象,再序列化后发送给客户端。

可以看到计算处理这一步其实跟接收发送消息、序列化与反序列化没有什么关系,所以可以把计算处理任务在服务端启动时再传递进去。

计算处理函数:typedef std::function<bool(const Request& req, Response& resp)> func_t;
这里的 req 是输入型参数(已经反序列化好的对象),resp 是输出型参数,为了获取计算结果。


B. TCP 的发送与接收缓冲区
​​​

前面使用的 write 和 read 接口并不是直接往网络里发送数据或者从网络里读取数据。write 其实是把数据拷贝到传输层的缓冲区,由 TCP 协议决定什么时候把缓冲区的数据发送到网络中,所以 TCP 协议也叫作传输控制协议
发送数据的本质是将数据从发送缓冲区拷贝到接收缓冲区。

所以,客户端 / 服务端发送数据不会影响接受数据。所以,TCP 是全双工的。

这就会导致一个问题,数据可能堆积在缓冲区来不及度,一次会读取多个报文挨在一起。那该如何保证读取完整报文呢?

看下面解释。


C. 保证读取完整报文

因为 TCP 是面向字节流的,所以要明确报文与报文的分界。

为什么要这样做呢?

举例:现在要把两个数字合并成字符串进行发送:1、12。如果不处理的话就是 "112",如果这样的话,反序列化时就不知道该怎么组合了。而如果我们选择在分割的地方加一个符号,比如 ,,那么在序列化后:"1,12",自热就很容易拆分了。

保证报文读取完整性的方法:

  1. 定长: 规定长度,每次就读取这么多。
  2. 特殊字符: 就是上面的方法。
  3. 自描述方式: 比如在报文前面带上四个字节的字段,标识报文长度。

D. 自定义协议 —— 序列化与反序列化 
【请求】

请求序列化反序列化

我们想要的序列化结果 "x_ op_ y_"

这里的反序列化将传进去的字符串把 "\r\n" 去掉了。


响应】

我们想要的序列化结果:"_code _result"

响应序列化反序列化


E. 计算流程

计算结果会形成一个 resp 响应,里面包含了退出码,后续可以自己设置退出码数值含义。

计算逻辑


F. 在有效载荷前添加长度报头(协议报头)

使用特殊字符来对内容进行区分:

"x_ op_ y_" -> "length\r\nx_ _op_ y_\r\n"
"code_ result_" -> "length\r\necode_ result_\r\n"
能够保证 length 里面不会出现 '\r' 或 '\n'吗?

能,因为 length 是一个整数,其内部不会出现任何的特殊符号。


G. 发送响应 send

服务端收到请求到把响应发送出去的整个流程:

那么这里的第一步是怎么读取请求的呢?

这个请求必须是恰好一个完整的请求。


H.  读取一个完整的报文 recv

收到的请求还需要去掉报头

服务端的业务逻辑也就完成了:


(4)客户端

整体流程跟服务端差不多,就是序列化请求,添加报头,发送,接收响应,去掉报头,反序列化,获取结果。


(5)守护进程(精灵进程)

目前学到的所有服务器都是在前台运行的。

什么是前台?

和终端关联的进程就叫作前台

判断一个进程是否为前台进程,取决于该进程能否正常获取输入,能否正常将输入的内容进行处理,那么对应的进程就是前台进程。90% 以上的情况下,bash 就是前台进程。

只要在终端下能够输入内容,能让我们输入内容的进程就叫作前台进程。 

任何 XShell 登陆都只允许一个前台进程和多个后台进程

什么是前台进程组?

任何时刻都只能有一个前台进程组,当我们登录 Windows时,就必须要给我们提供一个图形化界面,在 Linux 下就需要(前台进程组(可以只有一个进程))给我们加载 bash(一个任务),这就是为什么我们在登录时要有 Shell。

如果我们把后台进程提到前台,那么我们的 Shell 就无法运行了,是因为只能有一个前台进程组,bash 就会自己把自己投递到后台了,所以命令行解释器就用不了了。 

所以,在命令行中启动一个进程,在会话中启动一个进程组来完成某种任务,所有会话内的进程 fork() 创建子进程,一般而言依旧属于当前会话。

tips:如果电脑使用的时间长了,那么当前会话占的资源就会比较多,所以就可能会卡,那么我们可以选择退出,注销一下账号,注销就是把这个会话之前申请的资源全部释放,然后再重新登陆,这就是为什么卡的时候可以选择注销(和重启类似,但有些任务不一定通过注销能解决)  。

进程除了有自己的 pid、ppid 以外,还有以一个组 ID

  • 它的 PPID 是1(附件特征)
  • COMMAND:称为进程启动的命令
  • TIME:进程启动时长的问题
  • UID:是谁启动的(ls-n / ls-l 就可以看见用户的UID和我们看见的用户名是对应的,就像之前文件名和inode的映射一样)
  • STAT:状态
  • TPGID:当前进程组和终端相关的信息(-1 就是说这个进程和中单没有任何关系,具体数字就是和终端有关)
  • TTY:代表是哪一个终端
  • SID:当前进程的会话 id

在命令行中,同时用管道启动多个进程,多个进程是兄弟关系,父进程是 bash,所以它们之间可以用匿名管道来进行通信

同时被创建的多个进程可以成为一个进程组的概念,一般第一个进程被称为组长

仔细观察上图,可以发现还有一个 SID(会话 ID)。

最后一次登陆的用户需要有多个进程(组)来给这个它提供服务(bash),用户可以自己启动很多进程或进程组。将给用户提供服务的进程或者用户自己启动的所有进程或服务,整天都是要属于一个叫作会话的机制中的。

那么我们的网络服务器就不能属于这个会话内,否则就会受这个会话,用户登录和注销的影响(不一定会退出),所以在有网络服务的时候就应该脱离这个会话,让它在计算机里面形成一个新的会话(也就是自成进程组,自成新会话),自成一个会话这样的进程就被称为守护进程 / 精灵进程

如何将自己变成自成会话呢?

调用 setsid()将调用进程设置成独立的会话。

注意:setsid 要被成功调用就必须保证当前进程不是进程组的组长。 

如何保证我不是进程组的组长呢?

fork()

如何在 Linux 中正确的写一个让进程守护进程化的代码呢? 

通过自己写一个函数,让我们的进程调用这个函数,自动变成守护进程。

守护进程不能直接向显示器打印消息,一旦打印就会被暂停、终止。

在 Linux 设备中,存在一个 /dev/null 的文件,它有一个特点:向其写入的所有内容都会被自动丢弃,想从该文件中读取内容,它不会阻塞且什么都不会让我们读到,如同 Linux 下的一个文件黑洞,可以让我们进行任意操作而不影响系统运行。

将我们的服务守护进程化,让它变成一个网络服务:

相当于服务部署到了 Linux 当中,哪怕是自己的 XShell 关了也可以 ./client 继续用,就只能用信号杀了(一般守护进程的命名是 d 结尾)

那就只能用 kill -9 杀了。

守护进程的父进程是 1 号进程,叫作被领养了,也就是说,守护进程本质是孤儿进程的一种。他和孤儿进程的区别:孤儿进程可能依旧属于某一个会话,而守护进程自成会话。


(6)代码


(7)结果显示


3、使用 Json 进行序列化和反序列化

序列化与反序列化 C++ 都给我们提供了 Json 的库,可以直接使用:

Json(JavaScript Object Notation)是一种轻量级的数据交换格式,常用于 Web 应用程序中的数据传输。它是一种基于文本的格式,易于读写和解析。Json 格式的数据可以被多种编程语言支持,包括 JavaScript、Python、Java、C#、C++ 等。Json 数据由键值对组成,使用大括号表示对象,使用方括号表示数组。

先安装 Json 库:

sudo yum install jsoncpp-devel

头文件:#include <jsoncpp/json/json.h>

注意:使用 jsoncpp 库记得在编译时加上 -ljsoncpp。


⚪ demo 代码

A. Json::StyledWriter


B. Json::FastWriter(显示结果更加精简)



二、HTTP 协议

在前面我们已经实现了网络版的计算器中,其中对数据的处理计算就是我们自己手写的应用层协议。应用层是程序员基于 socket 接口之上编写的具体逻辑,做的很多工作都是和文本处理相关的(协议分析与处理),HTTP 协议具有大量的文本分析和协议处理

在编写网络通信代码时,我们可以自己进行协议的定制,但实际有很多优秀的工程师早就写出了许多非常成熟且好用的应用层协议供我们直接参考使用,其中最典型的就是 HTTP超文本传输协议)是一个简单的请求-响应协议,通常运行在 TCP 之上


1、认识URL

URL 就是我们平时俗称的 “网址”。在全球范围内,只要找到 url 就能访问该资源。

协议名称://server ip[:80]/a/b/c/d/e.html

要访问一个服务器,ip 地址和端口号是必须要有的,有 ip 地址就可以找到这台唯一的机器,能够访问到端口号就可以找到给我们提供服务对应端口的进程,可是上图在 url 中并没有体现出来,是因为一般在请求时,端口号是被省略的(在请求网络服务时,对应的端口号都是众所周知的(客户端知道))。

使用浏览器访问 URL(统一资源定位符):通过域名(server ip)找到唯一一台网络主机,而域名后面就是该机器提供服务的进程,接着是客户想访问的资源路径,通过资源路径找到想要的文件名,可能是图片或者文本,把资源(客户想访问的资源路径 + 客户要的文件名)返回给浏览器。

HTTP 的本质就是通过 HTTP 协议从服务端拿下文件资源,而因为文件资源的种类特别多,HTTP  都能搞定,所以叫做超文本传输协议。


(1)urlencode 和 urldecode

像 / ? : 等这样的字符已经被 url 当做特殊意义理解了,所以这些字符不能随意出现。如果用户想在 url 中包含 url 本身用来作为特殊字符的字符,那么在 url 形式时,浏览器会自动给我们进行编码 encode。

转义的规则:取出字符的 ASCII 码,将其转成 16 进制,然后再在前面加上百分号即可。比如下图,"+" 被转成了 "%2B",这个过程就叫做 encode,decode 就是把特殊符号转回去。

urlencode 工具:UrlEncode编码/UrlDecode解码 - 站长工具

实际当服务器拿到对应的 URL 后,也需要对编码后的参数进行解码,此时服务器才能拿到你想要传递的参数,解码实际就是编码的逆过程。


2、HTTP协议格式

HTTP 是基于请求和响应的应用层服务,底层采用 TCP,作为客户端可以向服务器发起 request,服务器收到这个 request 之后,会对这个 request 做数据分析,得出你想要访问什么资源,然后服务器再构建 response,完成这一次 HTTP 的请求,返回响应。

由于 HTTP 是基于请求和响应的应用层访问,所以必须要知道 HTTP 对应的请求格式和响应格式。

CS 模式: 

如何保证请求和响应被应用层完整读取?

HTTP 所有请求字段都是按行为单位的字符串,比如说对于 HTTP 请求,我们使用 while 循环按行读取,直到遇到空行为止,这样就可以保证把请求行和请求报头读完。而报头的 key: val 结构就有一个属性是 Content-Length: XXX,它表示的是正文的长度,由此,正文的也能完整读取了。

如果现在我们想获得 name 的 key 值,如何把数据从字符串中反序列化呢?
  1. 对于报头部分,其实请求 / 响应报头布置包含 name: val 信息,后边还有字符串分隔符:name: val\r\n,序列化直接发送就行,想要反序列化就可以按照 \r\n 来按行提取,所以 HTTP 报头是用特殊字符进行信息分离。
  2. 对于正文部分,不需要做处理,如果需要的话,可以设计自定义序列化与反序列化方案。

(1)HTTP 请求

  • 首行:[方法] + [url] + [版本]
  • Header:请求的属性,冒号分割的键值对,每组属性之间使用 \n 分隔,遇到空行表示 Header 部分结束。
  • Body:空行后面的内容都是 Body,Body 允许为空字符串。如果 Body 存在,则在 Header 中会有一个 Content-Length 属性来标识 Body 的长度。

(2)HTTP 响应

  • 首行:[版本号] + [状态码] + [状态码解释]
  • Header:请求的属性,冒号分割的键值对,每组属性之间使用 \n 分隔,遇到空行表示 Header 部分结束。
  • Body:空行后面的内容都是 Body,Body 允许为空字符串。如果 Body 存在,则在 Header 中会有一个 Content-Length 属性来标识 Body 的长度,如果服务器返回了一个 html 页面,那么 html 页面内容就是在 body 中。

3、HTTP 的请求方法

其中最常用的就是  GET  方法和  POST  方法。

我们平时上网的行为无非就分为两种:

  1. 从服务器端获取资源数据(GET)
  2. 把客户端的数据提交到服务器(POST、GET) 

表单负责手机用户数据并把用户数据推送给服务器。表单中的数据会被转成 http request 的一部分,表单被提交需要指明提交方法。

比方说我们在百度里搜索东西,要把数据提交到对应的输入框里:

其实本质是前端通过 form 表单进行提交的,浏览器会自动将 form 表单里的内容转成 GET/POST 方法请求。


(1)GET 方法

GET 方法通过 URL 传递参数,回显到浏览器的域名当中。

(HTML 默认大小写不敏感)

这一块整体就是个 form 表单,可以通过 GET 方法提交。

可以看到 GET 方法可以把要提交的参数拼接到到 url 的后边:


(2)POST 方法

POST 方法通过请求正文提交参数


(3)总结

因为 POST 方法是通过正文传参的,所以一般不会回显,用户看不到,私密性(不等于安全性,加解密才具有安全性)更好,而 GET 方法会回显输入的私密信息,不够私密。但无论是 GET 还是 POST 方法都不安全(HTTP 请求都是可以被抓到的,想要安全必须加密,使用 HTTPS 协议)。一般情况下,传递大字段或者较为私密的数据的时候使用 POST 方法,其他的使用 GET 方法。


4、HTTP 的状态码 

一般情况下,HTTP 的状态码都要匹配上状态码的描述

前面我们定义的状态行中的 200 就是状态码:

常见的状态码,比如 200(OK),404(Not Found),403(Forbidden),302(Redirect,重定向),504(Bad Gateway)


(1) 3xx —— Redirection(重定向状态码)

重定向就是通过各种方法将各种网络请求重新定个方向转到其它位置(跳转网站),此时这个服务器相当于提供了一个引路的服务。

当我们发送请求给服务端,服务端返回一个新的 url,状态码是 3,浏览器自动用这个新的 url 继续发送请求给新的地址,所以重定向是由客户端完成的。而重定向又分为临时重定向和永久重定向,其中状态码 301(Moved Permanently)表示的就是永久重定向,而状态码 302(Found)和 307(Temporary Redirect)表示的是临时重定向。

临时重定向和永久重定向本质是影响客户端的标签,决定客户端是否需要更新目标地址。

  • 如果某个网站是永久重定向,那么第一次访问该网站时由浏览器帮你进行重定向,但后续再访问该网站时就不需要浏览器再进行重定向了,此时访问的就是重定向后的网站
  • 如果某个网站是临时重定向,那么每次访问该网站时如果需要进行重定向都需要浏览器来帮我们完成重定向跳转到目标网站

A. 临时重定向演示

当我们访问浏览器的时候自动会跳转到我们指定的网站:



5、HTTP 常见的 Header 信息

  • Content-Type:数据类型(text / html 等)。
  • Content-Length:Body 的长度。
  • Host:客户端告知服务器, 所请求的资源是在哪个主机的哪个端口上。
  • User-Agent:声明用户的操作系统和浏览器版本信息。
  • referer:当前页面是从哪个页面跳转过来的。
  • location:搭配 3xx 状态码使用,告诉客户端接下来要去哪里访问。
  • Cookie:用于在客户端存储少量信息,通常用于实现会话(session)的功能。

(1) Content-Length


6、HTTP 会话保持(Cookie & Session)

HTTP 的特征:

  1. 简单快捷
  2. 无连接
  3. 无状态

HTTP 实际上是一种无状态协议,每次请求并不会记录它历史上请求过什么。HTTP 的每次请求/响应之间是没有任何关系的,但在使用浏览器时发现并不是这样的,比如在登录一次 CSDN 后,就算把 CSDN 网站关闭甚至重启电脑,当再次打开 CSDN 网站时,CSDN 并没有要求我们再次输入账号和密码,这实际上是通过 Cookie 技术实现的,点击浏览器当中锁的标志就可以看到对应网站的各种 Cookie 数据。

这些 cookie 数据实际都是对应的服务器方写的,如果你将对应的某些 cookie 删除,那么此时可能就需要你重新进行登录认证了,因为你删除的可能正好就是你登录时所设置的 cookie 信息。

结论:会话保持不是 HTTP 协议天然具备的特点,而是浏览器为了满足用户的使用需求,做了相应的工作。

如何做到的呢?

用户在第一次输入账号和密码时,浏览器会进行保存(Cookie),近期再次访问同一个网站(发送 http 请求),浏览器会自动将用户信息添加到报头中推送给服务器。这样只要用户首次输入密码,一段时间内将不用再做登录操作了。

这种把用户名和密码保存起来的技术叫做 Cookie 技术,而 Cookie 又分为 Cookie 内存和 Cookie 文件


(1)内存级别与文件级别

Cookie 就是在浏览器当中的一个小文件,文件里记录的就是用户的私有信息。Cookie 文件可以分为两种,一种是内存级别的 Cookie 文件,另一种是文件级别的 Cookie 文件。

  1. 将浏览器关掉后再打开,访问之前登录过的网站,如果需要你重新输入账号和密码,说明你之前登录时浏览器当中保存的 Cookie 信息是内存级别的。
  2. 将浏览器关掉甚至将电脑重启再打开,访问之前登录过的网站,如果不需要你重新输入账户和密码,说明你之前登录时浏览器当中保存的 Cookie 信息是文件级别的(真实的文件,保存在磁盘,进程退出也不影响)。

(2)Cookie 安全问题

本地的 Cookie 如果被不法分子拿到了,那么此时这个非法用户就可以用我们的 Cookie 信息,以我们的身份去访问我们曾经访问过的网站,将这种现象称为 Cookie 被盗取了。

为了保证安全,我们可以把信息保存在服务端,在服务端形成一个文件:Session 文件,而因为有很多 Session 文件,所以给每个文件一个名字:Session ID。并将其返回给浏览器,浏览器存到 Cookie 的其实是 Session id。接下来我们把 Session ID 放到请求中,然后发送到服务端,在服务端获取登录信息(鉴权)。目前只保证了用户信息的泄漏,接下来只能靠服务端的安全策略保障安全,例如账号被异地登录了,服务端察觉后只要让 session id 失效即可,这样异地登录就会让用户重新验证账号密码或手机或人脸信息(尽可能确保是本人),一定程度上保障了信息的安全。


(3)写入 Cookie 信息

就是向发送给浏览器的响应中写入报头中。


 7、HTTP 长连接

HTTP 请求是基于 TCP 协议的,而 TCP 是需要进行连接的。对于一个完整的网页来说,可能包含多种元素资源,那就需要发起多次 Connect。为了减少连接次数,需要客户端和服务器均支持长链接,建立一条连接,传输完后不断开连接,一直传递资源,不用频繁创建连接。如果是短连接请求了一份资源后就会自动关闭连接。

客户端和服务端怎么知道是否是长连接呢?

在报头信息中会有 Connection 字段。

Connection: keep-alive //支持长连接
Connection: close //短连接

8、简单的 HTTP 服务器


(1)代码验证请求格式

这里实现的就是一个简单的 TCP 服务器,而处理的任务就是把接收到的 HTTP 请求进行打印即可,服务器会把收到的数据全部放入请求缓冲区,然后直接打印出来。客户端并不用我们自己实现,有一个现成的客户端就是浏览器。

说明以下收到的请求:
对于请求行 GET / HTTP/1.1(Get 表示请求方法)

  • / 表示 url:url 当中的 / 不能称之为我们云服务器上根目录,这个 / 表示的是 web 根目录,这个 web 根目录可以是我们机器上的任何一个目录,是可以自己指定的,不一定就是 Linux 的根目录。
  • HTTP/1.1 表示协议版本。
注意 此处我们使用 9090 端口号启动了 HTTP 服务器。虽然 HTTP 服务器一般使用 80 端口,但这只是一个通用的习惯,并不是说 HTTP 服务器就不能使用其他的端口号。使用 Chrome 测试我们的服务器时,可以看到服务器打出的请求中还有一个 GET /favicon.ico HTTP/1.1 这样的请求。
为什么请求要包含版本?

因为客户端的会存在更新的情况,但是有的客户端并没有更新,所以服务端要根据版本来提供不同的服务。

而请求报头进过验证也是 name: val 的格式,里面都是属性字段。 


(2)代码验证响应格式

A. telnet 命令

telnet 是一种用于远程访问和管理计算机网络设备、服务器和服务的协议和命令行工具。它可以用于连接到运行 Telnet 服务器软件的任何计算机,并在远程计算机上执行命令和操作。

通常我们会使用该命令传参测试我们自己的服务器与其他的服务器是不是能正常访问。

telnet [ip地址] [端口]

telnet 127.0.0.1 8080

当使用 Telnet 命令连接到远程 IP 地址和端口时,如果连接成功,则会返回响应:

  • Trying 127.0.0.1…:表示正在尝试连接指定的 IP 地址
  • Connected to 127.0.0.1.:表示连接已经建立
  • Escape character is ‘^]’.:是提示信息,表示可以使用 Ctrl + ] 来退出 Telnet 命令。


(3)解析状态行信息

目的是把请求状态行的信息解析出来:


(4)web 根目录

上图的 url 中的 / 是 web 根目录,这个根目录可以自己设置,比如果我们就设置在当前路径下:

以后我们想要访问的资源就从 wwwroot 目录下开始,未来的所有资源放在这个目录里,可以通过 url 请求,例如:./wwwroot/a/b/c

如果直接是 ./wwwroot 呢?

此时就可以获得主页资源


(5)获取服务器资源

读取资源其实就是读取文件。

此时,如果客户端只请求了一个 /,直接返回默认首页:

加几个资源文件来获取试试看:


三、HTTPS 协议

1、HTTPS 是什么

TLS/SSL:可选的,一般负责加密和解密。

HTTPS 也是⼀个应用层协议,是在 HTTP 协议的基础上引入了⼀个加密层发送和接收必须用同一种方式(HTTP 或者 HTTPS)区分就用端口号。由于经过加密层,所以在 网络中是密文发送,在应用层是明文的,保证了数据在网络中的安全。
HTTP 协议内容都是按照⽂本的方式明文传输的,这就导致了在传输过程中出现⼀些被篡改的情况。

2、加密和解密

(1)什么是加密和解密

加密 就是把明文(要传输的信息)进行⼀系列变换,生成密文
解密 就是把密文再进行⼀系列变换,还原成明文
在这个加密和解密的过程中,往往需要⼀个或者多个中间的数据来辅助进行这个过程,这样的数据称为 密钥
安全 :破解的成本远远大于破解的收益。

举例:有 a 和 key,现在要对 a 加密,那么就让它们异或得到密文:b = a^key,当我想要把密文解密时,再异或一次 key 即可:a ^ key ^ key = a。这里我们把 a 叫做原始数据,b 叫做密文,key 叫做密钥。

加密解密到如今已经发展成⼀个独立的学科:密码学,而密码学的奠基人也正是计算机科学的祖师爷之⼀,艾伦·⻨席森·图灵,计算机领域中的最高荣誉就是以他名字命名的 “图灵奖” 


(2)为什么要加密和解密

在下载时可能会出现的情况:明明要下载的是 A 软件,但实际下载下来的却是 B 软件。为什么会出现这种情况呢?

由于我们通过网络传输的任何的数据包都会经过运营商的网络络设备(路由器,交换机等),那么运营商的网络设备就可以解析出你传输的数据内容并进行篡改点击 “下载按钮” 其实就是在给服务器发送了⼀个 HTTP 请求,获取到的 HTTP 响应其实就包含了该 APP 的下载链接。运营商劫持之后就发现这个请求是要下载 A 软件,那么就自动的把交给用户的响应给篡改成 B 软件的下载地址了。

因为 HTTP 的内容是明文传输的,明文数据会经过路由器、Wifi 热点、通信服务运营商、代理服务器等多个物理节点,如果信息在传输过程中被劫持,传输的内容就完全暴露了。劫持者还可以篡改传输的信息且不被双方察觉,这就是中间人攻击 ,所以才需要对信息进⾏加密。

不止运营商可以劫持,其他的黑客也可以用类似的手段进行劫持,以此来窃取用户的隐私信息或者篡改内容。如果黑客在用户登陆支付宝时获取到用户的账户余额,甚至获取到用户的支付密码等。

在互联网上,明文传输是比较危险的事情。

HTTPS 就是在 HTTP 的基础上进行了加密,进⼀步的来保证用户的信息安全。


(3)常见的加密方式

A. 对称加密
采用单钥密码系统的加密方法,同⼀个密钥可以同时用作信息的加密和解密,这种加密⽅法称为对称加密,也称为单密钥加密。
  • 特征加密和解密所用的密钥是相同的。
  • 常见对称加密算法(了解):DES、3DES、AES、TDEA、Blowfish、RC2 等。
  • 特点算法公开、计算量小、加密速度快、加密效率高。

按位异或就是一个简单的对称加密。假设明⽂ a = 1234,密钥 key = 8888,则加密 a ^ key 得到的密⽂ b 为 9834,然后针对密文 9834 再次进行运算 b ^ key,得到的就是原来的明文 1234。(对于字符串的对称加密也是同理,每⼀个字符都可以表示成⼀个数字)

当然,按位异或只是最简单的对称加密,不过 HTTPS 中并不是使用按位异或。


B. 非对称加密
需要两个密钥 来进行加密和解密,这两个密钥是公开密钥 (public key,简称公钥)和私有密钥(private key,简称私钥)。
  • 特征公钥和私钥是配对的。最大的缺点就是运算速度非常慢,比对称加密要慢很多。
  • 常见非对称加密算法(了解):RSA,DSA,ECDSA。
  • 特点:算法强度复杂、安全性依赖于算法与密钥但是由于其算法复杂,而使得加密解密速度没有对称加密解密的速度快。

通过公钥对明文加密变成密文,通过私钥对密文解密变成明文。也可以反着用,通过私钥对明文加密变成密文,通过公钥对密文解密变成明文。

非对称加密的数学原理比较复杂,涉及到⼀些数论相关的知识。举例:A 要给 B ⼀些重要的文件,但是 B 可能不在,于是 A 和 B 提前做出约定:B 说:“我桌子上有个盒子,然后我给你⼀把锁,你把文件放盒子里用锁锁上,然后我回头拿着钥匙来开锁取⽂件。”

在上面这个场景中,这把锁就相当于公钥,钥匙就是私钥。公钥给谁都行(不怕泄露),但是私钥只有 B 自己持有,持有私钥的人才能解密。

如何理解加密的安全性?

不存在不可被破解的加密,我们可以从算力成本角度来分析:比如我们加密的成本是 100 块,而解密的花费却要 100 亿,这种我们就可以称为是安全的。


(4)数据摘要 && 数据指纹

现在有一篇很大的文章,我们可以通过哈希函数把这个文章处理成一个固定长度字符串,现在就选修改了一个标点符号,字符串也会变化。把这个固定长度的字符串就叫做 hash 摘要,而这个过程就叫做数据摘要

数字指纹 (数据摘要),其基本原理是利用单向散列函数(Hash 函数)对信息进行运算,生成⼀串固定长度的数字摘要。任意的文本经过 Hash 形成的摘要都是不一样的。数字指纹并不是⼀种加密机制,但可以⽤来判断数据有没有被篡改。
  • 摘要常见算法:MD5、SHA1、SHA256、SHA512 等。
  • 算法把无限的映射成有限,因此可能会有碰撞(两个不同的信息,算出的摘要相同,但是概率非常低)。
  • 摘要特征:和加密算法的区别是:摘要严格意义不是加密,因为没有解密,只不过从摘要很难反推原信息,通常用来进行前后数据对比观察数据是否被修改过,也可以用于实现网盘的秒传功能、公司数据库密码存储等。

A. 网盘秒传功能

比方说我们很多人都想保存同一个电影到网盘中,如果网盘把每个人的请求全部保存起来, 那么会浪费很多空间。其实只用保存一份形成 hash 摘要,当另一个用户也要保存同一部电影时,要先形成摘要,然后在网盘中的一大堆摘要中进行对比,如果有这个摘要,那么直接建立映射关系即可,不需要再保存。

数据密码存储同理,把密码形成摘要,因为涉及到密码的东西都要进行加密。
每次用户登录时都将转换成哈希摘要与数据库的哈希摘要进行对比,所以数据库泄露也不怕。因为摘要是把无限变有限,所以可能存在碰撞,但是概率极低,就像指纹一样。


(5)数字签名

可能摘要的信息也不想让别人看到,把对数据摘要 再加密,就得到 数字签名

3、HTTPS 的工作过程

既然要保证数据安全, 就需要进行加密。网络传输中不再直接传输明文了,而是加密之后的密文。加密的方式有很多,但是整体可以分成两大类:对称加密和非对称加密。

网络通信的过程中,需要解决以下两个问题:

  1. 数据被监听
  2. 数据被篡改 

(1)方案一 —— 只使用对称加密

如果通信双方都各自持有同⼀个密钥 X,且没有别人知道,这两方的通信安全当然是可以被保证的(除非密钥被破解)。

引入对称加密之后,即使数据被截获,由于黑客不知道密钥是什么,也就无法进行解密,自然就不知道请求的真实内容了。如果通信双方只使用一个密钥进行加密通信,那么完全可以实现加密通信,除非密钥被破解。但实际没这么简单,服务器同一时刻其实是给很多客户端提供服务的,每个客户端用的秘钥肯定是不同的(如果是相同那密钥就太容易扩散了,黑客就也能拿到了),所以服务器就需要维护每个客户端和每个密钥之间的关联关系,这也是个很麻烦的事情。

比较理想的做法就是能在客户端和服务器建立连接时,双方协商确定这次的密钥是什么。

但是如果直接把密钥明文传输,那么黑客也就能获得密钥了,此时后续的加密操作就形同虚设了。因此密钥的传输也必须加密传输,但是要想对密钥进行对称加密,就仍然需要先协商确定一个个 “密钥的密钥”,这就成了 “先有鸡还是先有蛋” 的问题了,那此时密钥的传输再用对称加密就行不通了。

所以在进行正常加密数据通信之前,首先要解决的是密钥如何被对方安全的收到。


(2)方案二 —— 只使用非对称加密

非对称加密既可以使用公钥加密,也可以使用私钥加密。使用公钥加密必须使用私钥解密,使用私钥加密必须使用公钥解密。

这样就算中间人在通信过程中获取了公钥,但是没有私钥也无法进行解密,由此保证了从客户端发送给服务端数据的安全。

但是客户端给服务器发送的消息是不安全的,因为使用公钥加密的密文发给客户端,客户端没有私钥,解不了密,那能否在响应时把私钥传过去?

不行,因为私钥一但暴露到公网中就可能被劫持,黑客拿到私钥原地破解密文。

鉴于非对称加密的机制,如果服务器先把公钥以明文方式传输给浏览器,之后浏览器向服务器传数据前都先用这个公钥加密好再传,从客户端到服务器信道似乎是安全的(有安全问题),因为只有服务器有相应的私钥能解开公钥加密的数据。

服务器到浏览器的这条路该如何保障安全呢?
如果服务器用它的私钥加密数据传给浏览器,那么浏览器用公钥可以解密它,而这个公钥是⼀开始通过明文传输给浏览器的,若这个公钥被中间人劫持到了,那他也能用该公钥解密服务器传来的信息了。

(3)方案三 —— 双方都使用非对称加密

  1. 服务端拥有公钥 S 与对应的私钥 S',客户端拥有公钥 C 与对应的私钥 C'。
  2. 客户和服务端交换公钥。
  3. 客户端给服务端发信息:先用 S 对数据加密再发送,只能由服务器解密,因为只有服务器有私钥 S'。
  4. 服务端给客户端发信息:先用 C 对数据加密再发送,只能由客户端解密,因为只有客户端有私钥 C'。

这样做看似也行,但实则速度慢、效率低,其次是这样做也会有安全问题


(4)方案四 —— 非对称加密 + 对称加密

A. 解决效率问题

使用非对称加密让双方知道对称密钥,后续再使用对称加密的方式进行通信。

只有首次是使用非对称加密,后续所有的通信都采用对称加密。对称加密的速度快,大大提高了通信速度。

  1. 服务端具有非对称公钥 S 和私钥 S'。
  2. 客户端发起 HTTPS 请求,获取服务端公钥 S。
  3. 客户端在本地生成对称密钥 C,通过公钥 S 加密,发送给服务器。
  4. 由于中间的网络设备没有私钥,即使截获了数据也无法还原出内部的原文,也就无法获取到对称密钥。
  5. 服务器通过私钥 S' 解密还原出客户端发送的对称密钥 C,并且使用这个对称密钥加密给客户端返回的响应数据。
  6. 后续客户端和服务器的通信都只用对称加密即可,由于该密钥只有客户端和服务器两个主机知道,其他主机/设备不知道密钥,所以即使截获数据也没有意义。

由于对称加密的效率比非对称加密高很多,因此只是在开始阶段协商密钥的时候使用非对称加密,后续的传输仍然使用对称加密,但依旧有安全问题。


(5)中间人攻击方式

Man-in-the-MiddleAttack,简称 “MITM 攻击”。

在方案二、三、四中,客户端获取到公钥 S 之后,对客户端形成的对称秘钥 X 用服务端给客户端的公钥 S 进行加密,中间人即使窃取到了数据,但此时中间⼈确实无法解出客户端形成的密钥 X,因为只有服务器有私钥 S'。但是中间人的攻击如果在最开始握手协商的时候就进行了,那就不⼀定了,假设 hacker 已经成功成为中间人。

  1. 服务器具有非对称加密算法的公钥 S、私钥 S'。
  2. 中间人具有非对称加密算法的公钥 M、私钥 M'。
  3. 客户端向服务器发起请求,服务器明文传送公钥 S 给客户端。
  4. 中间⼈劫持数据报⽂,提取公钥 S 并保存好,然后将被劫持报文中的公钥 S 替换成为自己的公钥 M,并将伪造报文发给客户端。
  5. 客户端收到报文,提取公钥 M(自己不知道公钥被更换过了),自己形成对称秘钥 X,用公钥 M 加密 X,形成报文发送给服务器。
  6. 中间人劫持后,直接用自己的私钥 M' 进行解密,得到通信秘钥 X,再用曾经保存的服务端公钥 S 加密后将报⽂推送给服务器。
  7. 服务器拿到报文,用自己的私钥 S' 解密,得到通信秘钥 X。
  8. 双方开始采用 X 进行对称加密进行通信,但这⼀切都在中间人的掌握中,劫持数据、进行窃听甚至修改都是可以的。

上面的攻击方案同样适用于方案二、三。

只要已经交换了密钥,中间人就来迟了,但中间人如果在最开始的时候就可以进行篡改替换。

中间人攻击能够成功,其本质是什么呢?

本质是中间人能够对数据做篡改且客户端无法确定收到的公钥是合法的,也无法确定其含有公钥的数据报文就是目标服务器发送过来的。

这样中间人也得到了 C,利用 C 先解密再加密后发送给服务端,那么即使修改了数据客户端和服务端也不知道中间人的存在

该场景的本质问题是服务器在返回公钥的时候,被中间人截取并替换了公钥,并且客户端没有能力辨别公钥是否合法。 所以需要客户端具有判别公钥是否合法的能力


(6)数字证书

为了解决上面的问题,Client 需要对服务器的合法性进行认证。


A. CA 认证

相关简介:CA认证_百度百科 (baidu.com)

服务端在使用 HTTPS 前,需要向 CA 机构(权威机构)申领⼀份数字证书(CA 证书),数字证书里含有证书申请者信息公钥信息等。服务器把证书传输给浏览器,浏览器从证书里获取公钥就行了,证书就如身份证,证明服务端公钥的权威性, 是服务端公钥的身份证明。

这个证书可以理解成是⼀个结构化的字符串,只有证书是合法的时候才会进行非对称加密, 里面包含了以下信息:
  • 证书发布机构
  • 证书有效期
  • 公钥
  • 证书所有者
  • 签名
  • ......

注意:申请证书时需要在特定平台生成查,会同时生成⼀对密钥对,即公钥和私钥。这对密钥对就是用来在网络通信中进行明文加密以及数字签名的。

其中公钥会随着 CSR 文件,⼀起发给 CA 进行权威认证,私钥服务端自己保留,用来后续进行通信(其实主要就是用来交换对称密钥)。

在线生成 CSR 和私钥:CSR在线生成工具 (myssl.com) 

形成 CSR 后,后续就是向 CA 进行申请认证,不过⼀般认证过程很繁琐,网络各种提供证书申请的服务商,⼀般真的需要,直接找平台解决就行。

B. 数据签名

签名的形成是基于非对称加密算法的,数据签名的本质是防止被篡改

注意 :目前暂时和 https 没有关系,不要和 https 中的公钥私钥搞混了。

a. 签名过程 

假设现在我们有了数据(比如明文信息),我们把这个数据进行摘要形成数据摘要(数据指纹),然后把数据指纹用签名者(比如 CA 机构)的私钥进行加密形成了签名,然后再把明文信息和签名放在一起形成了数字签名的数据(比如证书)。


b. 验证过程

首先把数据签名的数据分成数据和签名,然后先对数据进行相同的摘要方式形成数据摘要,然后把用公钥加密过的签名用私钥解密,得到数据摘要,两者比对即可。散列值不一样说明有人篡改了签名或者数据,散列值一样就说明没有被篡改过。


c. CA 证书的申请和验证

当服务端申请 CA 证书时,CA 机构会对该服务端进行审核,并专门为该网站形成数字签名,过程如下:

生成证书
  1. CA 机构拥有非对称加密的私钥 A 和公钥 A'。
  2. CA 机构对服务端申请的证书明文数据进行 hash 摘要(公开的),形成数据摘要。
  3. CA 机构用 CA 私钥 A' 加密数据摘要,得到数字签名 S。
  4. CA 机构把明文数据和签名结合起来形成证书。

因为我们使用的是 CA 形成的数据签名,所以只有 CA 能形成可信任的证书,此时服务器会把证书响应给客户端,证书里面包含了公钥。

服务端申请的证书明文和数字签名 S 共同组成了数字证书,这样⼀份数字证书就可以颁发给服务端了。

验证证书合法性(公钥的合法性)

  1. 先看有没有过期。
  2. 把数据签名和明文信息分开。
  3. 对明文信息进行 hash 摘要(公开的),形成数据摘要。然后用 CA 的公钥把数据签名解密,得到了数据摘要,这里的公钥是哪来的呢?(CA 会在所有的浏览器中内置自己的公钥)
  4. 把两个数据摘要进行对比,相等就说明内容没有被篡改,不相等说明被篡改了。
有没有可能原文和签名全部都被替换了呢?原文中的公钥确实能被修改,那么签名呢?

改不了,因为私钥只有 CA 有,用自己的私钥的话浏览器不认识。

中间人能不能直接把整个证书替换掉?

首先因为浏览器里面内置了 CA 的私钥,那么我们替换的证书必须是一个真正的证书,因为假证书没有办法解密。而证书里面的域名信息,域名是唯一的,不可能一样。所以做不到整体替换。


(7)方案五 —— 非对称加密 + 对称加密 + 证书认证

在客户端和服务器刚建立连接时,服务器给客户端返回⼀个证书,证书包含了之前服务端的公钥,也包含了网站的身份信息,由此可以验证公钥的合法性。

所以非对称加密 + 对称加密保证了通信的安全,数字证书保证了通信之前交换密钥的安全。


A. 客户端进行认证
当客户端获取到这个证书之后,会对证书进行校验(防止证书是伪造的)。
  • 判定证书的有效期是否过期。
  • 判定证书的发布机构是否受信任(操作系统中已内置的受信任的证书发布机构)。
  • 验证证书是否被篡改:从系统中拿到该证书发布机构的公钥,对签名解密得到⼀个 hash 值(数据摘要),设为 hash1。然后计算整个证书的 hash 值设为 hash2,对比 hash1 和 hash2 是否相等。如果相等,则说明证书是没有被篡改过的。

B. 查看浏览器的受信任证书发布机构

Chrome 浏览器:


(8)常见问题

中间人有没有可能篡改该证书?
  • 中间⼈篡改了证书的明文。
  • 由于他没有 CA 机构的私钥,所以⽆法 hash 之后⽤私钥加密形成签名,那么也就没法办法对篡改后的证书形成匹配的签名。
  • 如果强行篡改,客户端收到该证书后会发现明⽂和签名解密后的值不一致,则说明证书已被篡改,证书不可信,从而终止向服务器传输信息,防止信息泄露给中间人。

中间人整个掉包证书?
  • 因为中间⼈没有 CA 私钥,所以无法制作假的证书。
  • 所以中间⼈只能向 CA 申请真证书,然后用自己申请的证书进行掉包。
  • 这个确实能做到证书的整体掉包,但是证书明文中包含了域名等服务端认证信息,如果整体掉包,客户端依旧能够识别出来。
  • 记住:中间人没有 CA 私钥,所以对任何证书都无法进行合法修改,包括自己的。

为什么摘要内容在网络传输时一定要加密形成签名?

常见的摘要算法有:MD5 和 SHA 系列。

以 MD5 为例,我们不需要研究具体的计算签名的过程,只需要了解 MD5 的特点:
  • 定长:无论多长的字符串,计算出来的 MD5 值都是固定长度(16 字节版本或者 32 字节版本)。
  • 分散:源字符串只要改变⼀点点,最终得到的 MD5 值都会差别很大。
  • 不可逆:通过源字符串⽣成 MD5 很容易,但是通过 MD5 还原成原串理论上是不可能的。

正因为 MD5 有这样的特性,我们可以认为如果两个字符串的 MD5 值相同,则认为这两个字符串相同。

理解判定证书篡改的过程(好比如判定这个⾝份证是不是伪造的身份证):

  • 假设我们的证书只是⼀个简单的字符串 hello,对这个字符串计算 hash 值(比如 md5),结果为 BC4B2A76B9719D91
  • 如果 hello 中有任意的字符被篡改了,比如变成了 hella, 那么计算的 md5 值就会变化很大,BDBD6F9CF51F2FD8
  • 然后我们可以把这个字符串 hello 和 哈希值 BC4B2A76B9719D91 从服务器返回给客⼾端, 此时客户端如何验证 hello 是否是被篡改过?那么就只要计算 hello 的哈希值,看看是不是 BC4B2A76B9719D91 即可。

但还有个问题,如果黑客把 hello 篡改了,同时也把哈希值重新计算了一下,那么客户端就分辨不出来了。 

被传输的哈希值不能传输明文,需要传输密文。所以,对证书明文("hello")hash 形成散列摘要,然后 CA 使用自己的私钥加密形成签名,将 hello 和加密的签名合起来形成 CA 证书颁发给服务端,当客户端请求时就发送给客户端,中间人截获了,因为没有 CA 私钥,就无法更改或者整体掉包,就能安全的证明证书的合法性。

最后,客户端通过操作系统⾥已经存的了的证书发布机构的公钥进行解密,还原出原始的哈希值,再进行校验。


为什么签名不是选择直接加密,而是要先 hash 形成摘要?

缩小签名密文的长度,加快数字签名的验证签名的运算速度。


如何成为中间人?(了解)
  • ARP 欺骗:在局域网中,hacker 经过收到 ARP Request 广播包,能够偷听到其它节点的(IP, MAC)地址。例如:黑客收到两个主机 A、B 的地址,告诉 B(受害者),自己是 A,使得 B 在发送给 A 的数据包都被黑客截取。
  • ICMP 攻击:由于 ICMP 协议中有重定向的报文类型,我们就可以伪造⼀个 ICMP 信息,然后发送给局域网中的客户端并伪装自己是⼀个更好的路由通路,从而导致目标所有的上网流量都会发送到我们指定的接口上,达到和 ARP 欺骗同样的效果。
  • 假 Wifi && 假网站等。

(9)完整流程

左侧都是客户端做的事情,右侧都是服务器做的事情:


4、总结

HTTPS 整个工作过程中涉及的密钥有三组:

  • 第⼀组(非对称加密):⽤于校验证书是否被篡改. 服务器持有私钥(私钥在形成CSR⽂件与申请证书时获得),客户端持有公钥(操作系统包含了可信任的 CA 认证机构有哪些,同时持有对应的公钥)。服务器在客户端请求时,返回携带签名的证书。客户端通过这个公钥进行证书验证,保证证书的合法性,进⼀步保证证书中携带的服务端公钥权威性。
  • 第⼆组(非对称加密):用于协商⽣成对称加密的密钥。客户端用收到的 CA 证书中的公钥(是可被信任的)给随机生成的对称加密的密钥加密,传输给服务器,服务器通过私钥解密获取到对称加密密钥。
  • 第三组(对称加密):客户端和服务器后续传输的数据都通过这个对称密钥加密解密。

其实⼀切的关键都是围绕这个对称加密的密钥,其他的机制都是辅助这个密钥工作的。

第⼆组非对称加密的密钥是为了让客户端把这个对称密钥传给服务器,第⼀组非对称加密的密钥是为了让客户端拿到第⼆组非对称加密的公钥。

  • 36
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
linux C语言 网络编程教程及源码 一、网络应用层编程 1、Linux网络编程01——网络协议入门 2、Linux网络编程02——无连接和面向连接的区别 3、Linux网络编程03——字节序和地址转换 4、Linux网络编程04——套接字 5、Linux网络编程05——C/S与B/S架构的区别 6、Linux网络编程06——UDP协议编程 7、Linux网络编程07——广播 8、Linux网络编程08——多播 9、Linux网络编程09——TCP编程之客户端 10、Linux网络编程10——TCP编程之服务器 11、Linux网络编程11——tcp、udp迭代服务器 12、Linux网络编程12——tcp三次握手、四次挥手 13、Linux网络编程13——connect()、listen()和accept()三者之间的关系 14、Linux网络编程14——I/O复用之select详解 15、Linux网络编程15——I/O复用之poll详解 16、Linux网络编程16——I/O复用之epoll详解 17、Linux网络编程17——tcp并发服务器(多进程) 18、Linux网络编程18——tcp并发服务器(多线程) 19、Linux网络编程——tcp高效并发服务器(select实现) 20、Linux网络编程——tcp高效并发服务器(poll实现) 21、Linux网络编程——tcp高效并发服务器(epoll实现) 网络底层编程(黑客模式) 1、Linux网络编程1——啥叫原始套接字 2、Linux网络编程2——原始套接字编程 3、Linux网络编程3——原始套接字实例:MAC头分析 4、Linux网络编程4——原始套接字实例:MAC地址扫描器 5、Linux网络编程5——IP数据报格式详解 6、Linux网络编程6——TCP、UDP数据包格式详解 7、Linux网络编程7——原始套接字实例:发送UDP数据包 8、Linux网络编程8——libpcap详解 9、Linux网络编程9——libnet详解
Linux多线程服务端编程:使用muduo C++网络库》主要讲述采用现代C++在x86-64 Linux上编写多线程TCP网络服务程序的主流常规技术,重点讲解一种适应性较强的多线程服务器的编程模型,即one loop per thread。 目 录 第1部分C++ 多线程系统编程 第1章线程安全的对象生命期管理3 1.1当析构函数遇到多线程. . . . . . . . . . . . . . . . .. . . . . . . . . . . 3 1.1.1线程安全的定义. . . . . . . . . . . . . . . . .. . . . . . . . . . . 4 1.1.2MutexLock 与MutexLockGuard. . . . . . . . . . . . . . . . . . . . 4 1.1.3一个线程安全的Counter 示例.. . . . . . . . . . . . . . . . . . . 4 1.2对象的创建很简单. . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . 5 1.3销毁太难. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . 7 1.3.1mutex 不是办法. . . . . . . . . . . . . . . . . . . .. . . . . . . . 7 1.3.2作为数据成员的mutex 不能保护析构.. . . . . . . . . . . . . . 8 1.4线程安全的Observer 有多难.. . . . . . . . . . . . . . . . . . . . . . . . 8 1.5原始指针有何不妥. . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . 11 1.6神器shared_ptr/weak_ptr . . . . . . . . . .. . . . . . . . . . . . . . . . 13 1.7插曲:系统地避免各种指针错误. . . . . . . . . . . . . . . . .. . . . . . 14 1.8应用到Observer 上.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 1.9再论shared_ptr 的线程安全.. . . . . . . . . . . . . . . . . . . . . . . . 17 1.10shared_ptr 技术与陷阱. . . .. . . . . . . . . . . . . . . . . . . . . . . . 19 1.11对象池. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . . 21 1.11.1enable_shared_from_this . . . . . . . . . . . . . . . . . . . . . . 23 1.11.2弱回调. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . 24 1.12替代方案. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . 26 1.13心得与小结. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . 26 1.14Observer 之谬. . . .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 第2章线程同步精要 2.1互斥器(mutex). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 2.1.1只使用非递归的mutex . . . . . . . . . . . . . .. . . . . . . . . . 33 2.1.2死锁. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . 35 2.2条件变量(condition variable). . . . . . . . . .
太大了,分了四个包<br>目 录<br>译者序<br>前言<br>第一部分 TCP/IP基础<br>第1章 开放式通信模型简介 1<br>1.1 开放式网络的发展 1<br>1.1.1 通信处理层次化 2<br>1.1.2 OSI参考模型 3<br>1.1.3 模型的使用 5<br>1.2 TCP/IP参考模型 7<br>1.3 小结 7<br>第2章 TCP/IP和Internet 8<br>2.1 一段历史 8<br>2.1.1 ARPANET 8<br>2.1.2 TCP/IP 9<br>2.1.3 国家科学基金会(NSF) 9<br>2.1.4 当今的Internet 12<br>2.2 RFC和标准化过程 12<br>2.2.1 获得RFC 13<br>2.2.2 RFC索引 13<br>2.2.3 有关RFC的幽默 13<br>2.3 Internet服务简介 13<br>2.3.1 Whois和Finger 14<br>2.3.2 文件传输协议 14<br>2.3.3 Telnet 14<br>2.3.4 Email 14<br>2.3.5 WWW 14<br>2.3.6 USENET News 15<br>2.4 Intranet和Extranet概览 15<br>2.4.1 Intranet 15<br>2.4.2 将Intranet对外开放 16<br>2.5 Internet的明天 16<br>2.5.1 下一代Internet(NGI) 16<br>2.5.2 超速骨干网服务 16<br>2.5.3 Internet2(I2) 17<br>2.6 Internet管理组织 17<br>2.6.1 Internet协会 17<br>2.6.2 Internet体系结构组 17<br>2.6.3 Internet工程任务组 17<br>2.6.4 Internet工程指导组 17<br>2.6.5 Internet编号管理局 18<br>2.6.6 Internet名字和编号分配组织<br> (ICANN) 18<br>2.6.7 Internet网络信息中心和其他注<br> 册组织 18<br>2.6.8 RFC编辑 18<br>2.6.9 Internet服务提供商 18<br>2.7 小结 19<br>第3章 TCP/IP概述 20<br>3.1 TCP/IP的优点 20<br>3.2 TCP/IP的层和协议 21<br>3.2.1 体系结构 21<br>3.2.2 传输控制协议 21<br>3.2.3 IP协议 23<br>3.2.4 应用层 25<br>3.2.5 传输层 25<br>3.2.6 网络层 25<br>3.2.7 链路层 25<br>3.3 远程登录(Telnet) 25<br>3.4 文件传输协议(FTP) 25<br>3.5 普通文件传输协议(TFTP) 26<br>3.6 简单邮件传输协议(SMTP) 26<br>3.7 网络文件系统(NFS) 26<br>3.8 简单网络管理协议(SNMP) 27<br>3.9 TCP/IP和系统结合 27<br>3.10 内部网概述 28<br>3.11 小结 28<br>第部分 命名和寻址<br>第4章 IP网络中的名字和地址 29<br>4.1 IP寻址 29<br>4.1.1 进制和十进制数 30<br>4.1.2 IPv4地址格式 30<br>4.2 子网的出现 34<br>4.2.1 分子网 35<br>4.2.2 可变长子网掩码(VLSM) 37<br>4.3 无类域前路由(CIDR) 38<br>4.3.1 无类地址 38<br>4.3.2 强化路由汇聚 39<br>4.3.3 超网化 39<br>4.3.4 CIDR怎样工作 39<br>4.3.5 公共地址空间 40<br>4.3.6 RFC 1597和1918 40<br>4.4 小结 40<br>第5章 ARP和RARP 41<br>5.1 使用地址 41<br>5.1.1 子网寻址 41<br>5.1.2 IP地址 43<br>5.2 使用地址解析协议 44<br>5.2.1 ARP cache 45<br>5.2.2 代理ARP 47<br>5.2.3 反向地址解析协议 47<br>5.3 使用ARP命令 47<br>5.4 小结 47<br>第6章 DNS:名字服务器 48<br>6.1 域名系统概述 48<br>6.2 授权局 50<br>6.3 DNS分布数据库 50<br>6.4 域和区 50<br>6.5 Internet顶级域 51<br>6.6 选择一个域名服务器 52<br>6.7 名字服务解析过程 52<br>6.7.1 递归查询 52<br>6.7.2 叠代查询 52<br>6.8 高速缓存 52<br>6.9 反向解析(Pointer)查询 52<br>6.10 DNS安全 52<br>6.11 资源记录 53<br>6.12 小结 54<br>第7章 WINS 55<br>7.1 NetBIOS 55<br>7.2 NetBIOS名字解析 57<br>7.3 动态NetBIOS名字解析 58<br>7.3.1 使用WINS的优点 58<br>7.3.2 WINS如何工作 59<br>7.3.3 配置WINS客户机 60<br>7.3.4 为代理配置WINS 60<br>7.3.5 配置NT 4.0系统 61<br>7.3.6 配置Windows 95或Windows 98<br> 系统 61<br>7.4 安装WINS服务器 61<br>7.5 WINS管理和维护 62<br>7.5.1 加入静态表项 62<br>7.5.2 维护WINS数据库 63<br>7.5.3 备份WINS数据库 65<br>7.5.4 备份WINS注册项 65<br>7.5.5 恢复WINS数据库 65<br>7.5.6 压缩WINS数据库 66<br>7.5.7 WINS复制参与者 66<br>7.5.8 WINS实现建议 67<br>7.6 集成WINS和DNS名字解析服务 67<br>7.7 DHCP服务WINS选项 67<br>7.8 通过LMHOSTS进行NetBIOS名字<br> 解析 68<br>7.9 小结 69<br>第8章 地址发现协议(BOOTP和DHCP) 71<br>8.1 “引导”协议(BOOTP) 71<br>8.2 动态主机配置协议(DHCP) 72<br>8.2.1 DHCP如何工作 72<br>8.2.2 理解租用地址 73<br>8.3 管理地址池 74<br>8.4 DHCP能处理的其他分配 75<br>8.4.1 注意重载 75<br>8.4.2 其他分配 75<br>8.5 小结 76<br>第三部分 IP和相关协议<br>第9章 IP协议家族 77<br>9.1 TCP/IP模型 77<br>9.1.1 解剖TCP/IP模型 78<br>9.1.2 协议组件 78<br>9.2 理解网际协议(IP) 79<br>9.2.1 IPv4结构 79<br>9.2.2 IP做什么 80<br>9.3 理解传输控制协议(TCP) 81<br>9.3.1 TCP头结构 81<br>9.3.2 TCP做什么 83<br>9.4 理解用户数据协议(UDP) 85<br>9.4.1 UDP头结构 85<br>9.4.2 UDP能做什么 85<br>9.4.3 TCP和UDP 86<br>9.5 小结 86<br>第10章 IPv6 87<br>10.1 IPv6数据报 87<br>10.1.1 优先级分类 88<br>10.1.2 流标识 89<br>10.1.3 128位IP地址 89<br>10.1.4 IP扩展头 90<br>10.2 多IP地址主机 91<br>10.3 单播、组播和任一播头 91<br>10.4 从IPv4到IPv6的过渡 93<br>10.5 小结 94<br>第四部分 IP互联<br>第11章 IP网络中的路由 95<br>11.1 路由基本知识 95<br>11.1.1 静态路由 96<br>11.1.2 距离-向量路由 99<br>11.1.3 链路-状态路由 100<br>11.2 IP网络中的收敛 102<br>11.2.1 适应拓扑变化 102<br>11.2.2 收敛时间 106<br>11.3 计算IP网络中的路由 106<br>11.3.1 存储多条路由 107<br>11.3.2 初始化更新 107<br>11.3.3 路由度量标准 107<br>11.4 小结 108<br>第12章 路由信息协议(RIP) 109<br>12.1 理解RFC1058 109<br>12.1.1 RIP报文格式 109<br>12.1.2 RIP路由表 111<br>12.2 操作机制 112<br>12.2.1 计算距离向量 113<br>12.2.2 更新路由表 116<br>12.2.3 寻址问题 118<br>12.3 拓扑变化 120<br>12.3.1 收敛 120<br>12.3.2 计值到无穷 122<br>12.4 RIP的限制 127<br>12.4.1 跳数限制 128<br>12.4.2 固定度量 128<br>12.4.3 对路由表更新反应强烈 128<br>12.4.4 收敛慢 128<br>12.4.5 缺乏负载均衡 128<br>12.5 小结 129<br>第13章 开放式最短路径优先 130<br>13.1 OSPF起源 130<br>13.2 理解RFC 2328 OSPF,版本2 130<br>13.2.1 OSPF区 131<br>13.2.2 路由更新 134<br>13.3 研究OSPF数据结构 136<br>13.3.1 HELLO报文 137<br>13.3.2 数据库描述报文 137<br>13.3.3 链路-状态请求报文 138<br>13.3.4 链路-状态更新报文 138<br>13.3.5 链路-状态应答报文 140<br>13.4 计算路由 140<br>13.4.1 使用自动计算 140<br>13.4.2 使用缺省路由耗费 141<br>13.4.3 最短路径树 142<br>13.5 小结 144<br>第14章 网关协议 145<br>14.1 网关、桥和路由器 145<br>14.1.1 网关 145<br>14.1.2 网桥 146<br>14.1.3 路由器 146<br>14.1.4 自治系统 146<br>14.2 网关协议基础知识 146<br>14.3 内部网关协议和外部网关协议 147<br>14.3.1 网关-网关协议(GGP) 147<br>14.3.2 外部网关协议(EGP) 147<br>14.3.3 内部网关协议(IGP) 148<br>14.4 小结 148<br>第五部分 网络服务<br>第15章 互联网打印协议 149<br>15.1 IPP历史 149<br>15.2 IPP和端用户 150<br>15.3 使用HP的IPP实现 151<br>15.4 小结 152<br>第16章 LDAP:目录服务 153<br>16.1 为什么使用目录服务 153<br>16.2 目录服务的功能 153<br>16.3 IP上的目录服务 154<br>16.4 OSI X.500目录模型 156<br>16.4.1 早期的X.500 157<br>16.4.2 今天的X.500 157<br>16.5 LDAP结构 157<br>16.5.1 LDAP层次结构 157<br>16.5.2 名字结构 158<br>16.6 目录系统代理和访问协议 158<br>16.7 轻型目录访问协议 158<br>16.7.1 查询信息 159<br>16.7.2 存储信息 160<br>16.7.3 访问权限和安全 160<br>16.8 LDAP服务器-服务器通信 161<br>16.8.1 LDAP数据互换格式(LDIF) 161<br>16.8.2 LDAP复制 162<br>16.9 设计LDAP服务 162<br>16.9.1 定义需求 162<br>16.9.2 设计策略 163<br>16.9.3 性能 164<br>16.9.4 网络功能 165<br>16.9.5 安全 166<br>16.10 LDAP配置 169<br>16.11 产品环境 169<br>16.11.1 创建计划 170<br>16.11.2 有价值的建议 171<br>16.12 选择LDAP软件 171<br>16.13 小结 174<br>第17章 远程访问协议 175<br>17.1 远程互联 175<br>17.1.1 ISDN 176<br>17.1.2 电缆调制解调器 176<br>17.1.3 数字用户环(DSL) 176<br>17.1.4 无线网络 177<br>17.2 远程认证拨入用户服务(RADIUS) 177<br>17.2.1 RADIUS认证 178<br>17.2.2 记账信息 179<br>17.3 用SLIP、CSLIP和PPP传输IP数<br> 据报文 179<br>17.3.1 串行线路接口协议(SLIP) 179<br>17.3.2 压缩的SLIP(CSLIP) 180<br>17.3.3 点到点协议(PPP) 180<br>17.4 隧道远程访问 184<br>17.4.1 点到点隧道协议(PPTP) 185<br>17.4.2 两层隧道协议(L2TP) 188<br>17.4.3 IPSec 192<br>17.5 小结 194<br>第18章 防火墙 195<br>18.1 使网络安全 195<br>18.2 使用防火墙 196<br>18.2.1 代理服务器 197<br>18.2.2 报文过滤器 198<br>18.3 使服务安全 198<br>18.3.1 电子邮件(SMTP) 198<br>18.3.2 HTTP:万维网 199<br>18.3.3 FTP 199<br>18.3.4 Telnet 199<br>18.3.5 Usenet:NNTP 199<br>18.3.6 DNS 200<br>18.4 建造用户自己的防火墙 200<br>18.5 使用商业防火墙软件 200<br>18.6 小结 202<br>第19章 IP安全 203<br>19.1 使用加密 203<br>19.1.1 公共-私钥加密 204<br>19.1.2 对称私钥加密 205<br>19.1.3 DES、IDEA及其他 205<br>19.2 数字签名认证 206<br>19.3 破译加密的数据 207<br>19.4 保护网络 207<br>19.4.1 登录名和口令 208<br>19.4.2 文件的目录允许权限 208<br>19.4.3 信任关系 209<br>19.4.4 UNIX和Linux系统上的UUCP 209<br>19.5 应付最坏情况 210<br>19.6 小结 210<br>第六部分 实现TCP/IP<br>第20章 一般配置问题 211<br>20.1 安装网卡 211<br>20.1.1 网卡 211<br>20.1.2 资源配置 212<br>20.1.3 安装适配器软件 213<br>20.1.4 重定向器和API 214<br>20.1.5 服务 214<br>20.1.6 NIC接口 215<br>20.2 网络和传输层协议 215<br>20.2.1 IP配置要求 215<br>20.2.2 配置缺省网关地址 216<br>20.2.3 配置名字服务器地址 217<br>20.2.4 配置邮件服务器地址 217<br>20.2.5 注册域名 218<br>20.3 IP配置 218<br>20.4 配置路由表 218<br>20.5 异种协议的IP封装 219<br>20.6 小结 220<br>第21章 Windows 98 221<br>21.1 Windows 98网络体系结构 221<br>21.1.1 安装网卡 222<br>21.1.2 更改网卡配置 224<br>21.1.3 当Windows 98引导失败 224<br>21.2 配置Windows 98的TCP/IP 225<br>21.2.1 写在开始之前 225<br>21.2.2 安装TCP/IP 225<br>21.2.3 配置微软的TCP/IP 225<br>21.2.4 DNS配置 227<br>21.2.5 静态配置文件 228<br>21.2.6 注册表配置 229<br>21.2.7 测试TCP/IP 231<br>21.3 小结 232<br>第22章 Windows 98拨号网络 233<br>22.1 配置拨号网络适配器 233<br>22.2 安装拨号网络 234<br>22.3 服务器类型 235<br>22.4 编写脚本 238<br>22.5 多重链接 238<br>22.6 PPTP 239<br>22.6.1 安装及配置PPTP 240<br>22.6.2 建立PPTP连接 240<br>22.7 Windows 98拨号服务器 241<br>22.8 解决拨号网络连接中的问题 242<br>22.8.1 确认DUN配置 242<br>22.8.2 PPP日志 243<br>22.9 小结 243<br>第23章 Windows NT 4.0 244<br>23.1 Windows NT版本 244<br>23.2 体系结构 244<br>23.3 安装Windows NT 4.0 244<br>23.4 配置TCP/IP 246<br>23.4.1 IP地址 246<br>23.4.2 DNS 248<br>23.4.3 WINS地址 248<br>23.4.4 DHCP中继 249<br>23.4.5 路由 250<br>23.5 简单TCP/IP服务 250<br>23.6 远程访问服务(RAS) 250<br>23.7 DHCP服务器 252<br>23.7.1 安装DHCP服务器服务 252<br>23.7.2 控制DHCP服务器服务 253<br>23.7.3 压缩DHCP数据库 253<br>23.7.4 管理DHCP 254<br>23.8 使用Microsoft DNS 256<br>23.8.1 安装DNS 256<br>23.8.2 创建区 257<br>23.8.3 配置逆向域名解功能 258<br>23.8.4 配置DNS与WINS服务器的连<br> 接 259<br>23.8.5 增加辅助名字服务器 259<br>23.9 FTP和HTTP服务 259<br>23.10 TCP/IP打印服务 259<br>23.10.1 安装TCP/IP打印服务 259<br>23.10.2 安装LPR服务 260<br>23.11 Windows 2000新特性 260<br>23.12 小结 261<br>第24章 在Novell NetWare中支持IP 262<br>24.1 Novell与TCP/IP 262<br>24.1.1 IP与NetWare 4 262<br>24.1.2 NetWare 5与Pure IP初始化 262<br>24.2 传统解决方案:NetWare 3.x到<br> NetWare 4.x的IP支持 263<br>24.2.1 IP隧道 264<br>24.2.2 IP中继 264<br>24.2.3 LAN WorkPlace 264<br>24.2.4 IPX-IP网关 265<br>24.2.5 NetWare/IP 265<br>24.3 NetWare 5—Novell对IP的<br> 完全支持 266<br>24.3.1 纯IP 266<br>24.3.2 多协议 266<br>24.4 安装选项 266<br>24.4.1 NetWare 5的IP-Only安装 267<br>24.4.2 IPX-Only安装 267<br>24.4.3 混合TCP/IP安装 268<br>24.5 IP迁移辅助工具 268<br>24.5.1 NDS 268<br>24.5.2 DNS 269<br>24.5.3 DHCP 269<br>24.5.4 DDNS 269<br>24.5.5 SLP 269<br>24.5.6 兼容模式 269<br>24.5.7 迁移代理 270<br>24.6 迁移策略 270<br>24.6.1 使用测试平台 270<br>24.6.2 迁移建议 270<br>24.7 小结 271<br>第七部分 使用TCP/IP应用<br>第25章 Whois和Finger 273<br>25.1 理解Whois协议 273<br>25.1.1 互联网注册 273<br>25.1.2 Whois数据库 274<br>25.1.3 基于Web的Whois 275<br>25.1.4 命令行方式的Whois 276<br>25.1.5 示例 276<br>25.1.6 基于Telnet的Whois 278<br>25.2 扩充Whois 279<br>25.2.1 提示Whois(RWhois) 279<br>25.2.2 WHOIS++ 280<br>25.3 使用Finger 280<br>25.3.1 Finger命令 280<br>25.3.2 Finger 守护进程 282<br>25.3.3 非UNIX环境下的Finger 283<br>25.3.4 Finger的应用 283<br>25.4 相关RFC文档 285<br>25.5 小结 285<br>第26章 文件传输协议 286<br>26.1 FTP和TFTP在网络世界中的作用 286<br>26.2 使用FTP传输文件 286<br>26.2.1 FTP连接 287<br>26.2.2 使用FTP客户端建立连接 288<br>26.2.3 FTP安全 296<br>26.2.4 FTP服务器及守护进程 299<br>26.2.5 匿名FTP访问 299<br>26.3 使用TFTP 300<br>26.3.1 FTP与TFTP的区别 301<br>26.3.2 TFTP命令 301<br>26.4 小结 301<br>第27章 使用Telnet 302<br>27.1 理解Telnet协议 302<br>27.2 Telnet守护进程 303<br>27.3 使用Telnet 304<br>27.3.1 UNIX telnet命令 304<br>27.3.2 Telnet GUI应用 305<br>27.3.3 Telnet命令 305<br>27.3.4 示例 308<br>27.4 高级主题 309<br>27.4.1 安全 309<br>27.4.2 Telnet应用 309<br>27.4.3 使用Telnet访问其他TCP/IP<br> 服务 310<br>27.5 相关RFC文档 312<br>27.6 小结 313<br>第28章 使用r系列实用工具 314<br>28.1 理解r系列命令 314<br>28.1.1 安全问题 314<br>28.1.2 禁止使用r系列命令 315<br>28.1.3 增强r系列命令的安全性 316<br>28.2 使用r系列命令的替代方法 317<br>28.3 r系列命令详解 317<br>28.3.2 相关文件 320<br>28.4 在非UNIX环境下实现r系<br> 列命令的功能 321<br>28.5 小结 322<br>第29章 使用网络文件系统(NFS) 323<br>29.1 什么是NFS 323<br>29.1.1 NFS的历史 323<br>29.1.2 为何使用NFS 323<br>29.2 实现—NFS工作过程 324<br>29.2.1 远程过程调用(RPC)<br> 和外部数据表示(XDR) 324<br>29.2.2 加载类型 324<br>29.3 NFS使用的文件及命令 325<br>29.3.1 NFS守护进程 325<br>29.3.2 与NFS相关的文件 327<br>29.3.3 NFS服务器命令 329<br>29.3.4 NFS客户命令 331<br>29.4 示例:共享及加载NFS文件系统 333<br>29.5 NFS常见问题及解决方案 334<br>29.5.1 不能加载 334<br>29.5.2 不能卸载 334<br>29.5.3 硬加载与软加载 334<br>29.6 相关协议及产品 334<br>29.6.1 WebNFS 335<br>29.6.2 基于PC的NFS及其他客户端<br> 软件 335<br>29.6.3 SMB和CIFS 335<br>29.6.4 其他产品 336<br>29.7 小结 336<br>第八部分 使用基于IP的应用<br>第30章 在应用中集成TCP/IP 337<br>30.1 使用浏览器作为表示层 338<br>30.2 不断增加的Internet应用 338<br>30.3 在已有应用中集成TCP/IP 339<br>30.4 在其他网络中使用TCP/IP 339<br>30.4.1 NetBIOS与TCP/IP 339<br>30.4.2 IPX与UDP 340<br>30.4.3 ARCNET与TCP/IP 340<br>30.5 小结 340<br>第31章 Internet Email协议 341<br>31.1 电子邮件 341<br>31.1.1 电子邮件的历史 341<br>31.1.2 标准及制定标准的组织 341<br>31.2 X.400 341<br>31.3 简单邮件传输协议(SMTP) 343<br>31.3.1 MIME和SMTP 343<br>31.3.2 其他编码标准 344<br>31.3.3 SMTP命令 344<br>31.3.4 SMTP状态码 345<br>31.3.5 扩展SMTP 345<br>31.3.6 检查SMTP的头 346<br>31.3.7 SMTP的优势与不足 347<br>31.4 使用POP和IMAP取回客户邮件 347<br>31.4.1 邮局协议(POP) 347<br>31.4.2 互联网邮件访问协议(IMAP) 348<br>31.4.3 POP3与IMAP4的比较 348<br>31.5 高级主题 349<br>31.6 相关RFC文档及其他参考信息 351<br>31.7 小结 352<br>第32章 HTTP: World Wide Web 353<br>32.1 万维网(WWW) 353<br>32.1.1 Web简史 353<br>32.1.2 Web的发展 354<br>32.2 统一资源定位器 354<br>32.3 Web服务器与浏览器 355<br>32.4 理解HTTP 356<br>32.4.1 HTTP/1.1 356<br>32.4.2 MIME与Web 358<br>32.4.3 HTTP通信示例 358<br>32.5 高级主题 359<br>32.5.1 服务器方功能 359<br>32.5.2 SSL和S-HTTP 359<br>32.6 Web语言 359<br>32.6.1 HTML 360<br>32.6.2 XML 360<br>32.6.3 CGI 361<br>32.6.4 Java 361<br>32.6.5 JavaScript 362<br>32.6.6 动态服务器页面 362<br>32.7 Web的未来 363<br>32.7.1 HTTP-ng 363<br>32.7.2 IIOP 363<br>32.7.3 IPv6 363<br>32.7.4 IPP 363<br>32.8 小结 364<br>第33章 NNTP:互联网新闻组 365<br>33.1 互联网新闻组 365<br>33.2 新闻组和层次 366<br>33.3 网络新闻传输协议 367<br>33.3.1 获取新闻组 367<br>33.3.2 获取消息 369<br>33.3.3 发布消息 370<br>33.4 大量广告(Spamming)和新闻黑洞<br> (Blackholing) 371<br>33.5 小结 371<br>第34章 Web服务 373<br>34.1 Web服务工作概览 373<br>34.2 主流Web服务器 375<br>34.3 运行Apache HTTP Web服务 376<br>34.3.1 下载、安装和配置Apache 376<br>34.3.2 在Windows环境下使用Apache 381<br>34.4 浏览其他Web服务器 383<br>34.5 小结 383<br>第九部分 使用与管理TCP/IP网络<br>第35章 协议配置与调整 385<br>35.1 系统的初始化问题 385<br>35.2 配置文件 390<br>35.2.1 在/etc/protocols文件中定义网<br> 络协议 390<br>35.2.2 在/etc/hosts文件中标识主机 391<br>35.2.3 TCP/IP与/etc/services文件 392<br>35.2.4 inetd守护进程与/etc/inetd.conf<br> 文件 394<br>35.2.5 在/etc/networks文件中设置网络 397<br>35.2.6 DNS客户与/etc/resolv.conf 397<br>35.3 小结 398<br>第36章 配置DNS 399<br>36.1 域名服务器 399<br>36.2 资源记录 400<br>36.3 域名解析 401<br>36.4 配置UNIX或Linux域名服务器<br> (DNS) 401<br>36.4.1 添加资源记录 402<br>36.4.2 完成DNS文件 402<br>36.4.3 启动DNS守护进程 405<br>36.4.4 配置客户端 405<br>36.5 Windows和域名服务器 405<br>36.6 小结 406<br>第37章 网络管理 407<br>37.1 制定网络监控方案 407<br>37.2 网络问题及其解决方案 408<br>37.3 网络管理工具 408<br>37.3.1 使用协议分析器 409<br>37.3.2 专家系统 410<br>37.3.3 基于PC的分析器 410<br>37.3.4 网络管理协议支持 411<br>37.3.5 集成网络仿真/模型工具 411<br>37.4 配置SNMP 412<br>37.4.1 配置Windows SNMP 413<br>37.4.2 配置UNIX SNMP 414<br>37.4.3 SNMP安全属性 414<br>37.4.4 SNMP代理与管理 415<br>37.5 SNMP工具及命令 416<br>37.6 RMON及相关的MIB模型 417<br>37.7 建立网管需求 417<br>37.8 小结 419<br>第38章 SNMP:简单网络管理协议 420<br>38.1 什么是SNMP 420<br>38.2 管理信息基(MIB) 421<br>38.3 使用SNMP 421<br>38.4 UNIX与SNMP 422<br>38.4.1 在UNIX和Linux上安装SNMP 423<br>38.4.2 SNMP命令 424<br>38.5 Windows与SNMP 424<br>38.5.1 Windows NT 425<br>38.5.2 Windows 95、Windows 98和<br> Windows 3.x 425<br>38.6 小结 427<br>第39章 加强TCP/IP传输安全 428<br>39.1 定义所需的网络安全 428<br>39.1.1 什么是网络安全 428<br>39.1.2 为什么网络安全非常重要 429<br>39.1.3 安全级别 429<br>39.1.4 口令与口令文件 430<br>39.1.5 控制对口令的访问 430<br>39.2 加强网络安全 431<br>39.2.1 攻击种类 431<br>39.2.2 加强网络安全 432<br>39.3 应用配置 434<br>39.3.1 Internet守护进程与<br> /etc/inetd.conf 434<br>39.3.2 网络加密软件 436<br>39.3.3 TCP Wrapper 436<br>39.4 使用端口及可信端口 437<br>39.4.1 防火墙 437<br>39.4.2 包过滤 437<br>39.4.3 应用层网关 438<br>39.4.4 其他应用的过滤 438<br>39.5 一般安全事务 438<br>39.5.1 用户帐号维护 438<br>39.5.2 审计 438<br>39.5.3 正确的系统配置 438<br>39.6 小结 438<br>第40章 问题解决工具及要点 440<br>40.1 监视网络行为 440<br>40.2 标准应用程序 440<br>40.2.1 测试基本连接 441<br>40.2.2 ping命令 442<br>40.2.3 解决网络访问故障 443<br>40.3 解决网络接口层问题 449<br>40.4 解决网络层问题 449<br>40.4.1 TCP/IP配置参数 449<br>40.4.2 IP地址配置问题 450<br>40.5 解决TCP和UDP问题 453<br>40.6 解决应用层问题 455<br>40.7 小结 455<br>第十部分 附 录<br>附录A RFC及标准化 457<br>附录B Linux 469<br>附录C 简写与缩略语 480<br>

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值