2017-2018-1 20155306 《信息安全系统设计基础》第8周学习总结
教材学习内容总结
第11章 网络编程
11.1 客户端-服务器编程模型
每个网络应用都是基于客户端-服务器模型的
。
一个应用是由一个服务器户端提供某种服务。服务器管理某种资源,并且通过操作这种资源来为它的客户端提供某种服务。
客户端-服务器模型中的基本操作是事务。
事务由四步组成:
- 当一个客户端需要服务时,它向服务器发送一个请求,发起一个事务。
- 服务器收到请求后,解释它,并以适当的方式操作它的资源。
- 服务器给客户端发送一响应,并等待下一个请求。
- 客户端收到响应并处理它。
11.2 网络
每个以太网适配器都有—个全球唯一的48位地址,它存储在这个适配器的非易失性存储器上。一台主机可以发送一段位,称为帧。每个主机适配器都能看到这个帧,但是只有目的主机实际读取它。
桥接以太网是使用一些电缆和叫做网桥的小盒子,将多个以太网段连接起来形成的较大的局域网。电缆的带宽可以是不同的。
协议必须提供两种基本能力:
- 命名机制。不同的局域网技术有不同的和不兼容的方式来为主机分配地址。
- 传送机制。在电缆上编码位和将这些位封装成帧方面,不同的联网技术有不同和不兼容的方式。一个包是由包头和有效载荷组成,其中包头包括包的大小以及源主机和目的主机的地址,有效载荷包括从源主机发出的数据位。
在层次的更高级别中,多个不兼容的局域网可以通过叫做路由器的计算机连接起来,组成一个Internet。
把因特网看做一个世界范围的主机集合,满足一下特性:
- 主机集合被映射为一组32位的IP地址。
- 这组IP地址被映射为一组称为因特网域名的标识符。
- 因特网主机上的进程能够通过连接和任何其他因特网主机上的进程通信。
11.3 全球IP因特网
因特网客户端和服务器互相通信时使用的是IP地址。因特网也定义了一组更加人性化的域名,以及一种将域名映射到IP地址的机制。
域名集合形成了一个层次结构,每个域名编码了它在这个层次中的位置。层次结构可以表示为一棵树。树的节点表示城名,反向到根的路径形成了域名。子树称为子域。层次结构中的第一层是个未命名的根节点。下一层是一组一级域名。常见的第一层域名包括com、edu、gov、org、net。下一层是二级域名,一旦一个组织得到了一个二级域名,那么它就可以在这个子域中创建任何新的域名了。
11.4 套接字接口
服务器和客户端连接的各函数:
第12章 并发编程
使用应用级并发的应用程序称为并发程序。现代操作系统提供了三种基本的构造并发程序的方法:
- 进程。
- I/O多路复用。
- 线程。
12.1 基于进程的并发编程
一个基于进程的并发的echo服务器的代码,重要说明:
- 首先,通常服务器会运行很长时间,所以我们必须包括一个SIGCHLD处理程序,来回收僵死子进程资源。
- 其次,父子进程必须关闭他们的connfd拷贝。
- 最后,因为套接字的文件表表项的引用计数,直到父子进程的connfd都关闭了,到客户端的连接才会终止。
关于进程的优劣,对于在父、子进程间共享状态信息,进程有一个非常清晰的模型:共享文件表,但是不共享用户地址空间。进程有独立的地址空间既是优点又是缺点。这样一来,一个进程不可能不小心覆盖另一个进程的虚拟存储器。另一方面,独立的地址空间使得进程共享状态信息变得更加困难。
12.2 基于i/o多路复用的并发编程
一个echo服务器,它也能对用户从标准输入键入的交互命令做出响应。在这种情况下,服务器必须响应两个相互独立的I/O事件:
1)网络客户端发起连接请求;
2)用户在键盘上键入命令行。
如果accept中等待每一个连接请求,那么无法响应输入命令。如果在read中等待一个输入命令,我们就不能响应任何连接请求。针对这种困境的一个解决办法就是I/O多路复用技术。基本的思路就是使用select函数,要求内核挂起进程,只有在一个或者多个I/O事件发生后,才将控制返给应用程序。
事件驱动设计的优点:
- 它比基于进程的设计给了程序员更好的对程序行为的控制
- 一个基于I/O多路复用的时间驱动服务器是运行在单一进程上下文中的
事件驱动设计的缺点:
- 编码复杂,我们的事件驱动的并发echo服务器需要的代码比基于进程的代码多三倍。
12.3 基于线程的并发编程
线程就是运行在进程上下文中的逻辑流。每个线程都有自己的线程上下文,包括一个线程ID、栈、栈指针、程序计数器、通用目的寄存器和条件码。多个线程运行在单一进程的上下文中,因此共享这个进程虚拟地址空间的整个内容,包括它的代码、数据、堆、共享库和打开的文件。
基于线程是两种方法的混合:
- 每个流使用单独的进程
- 穿件自己的逻辑流,并利用I/O多路复用来显示地调度流
线程通过调用pthread_create函数来创建其他进程。
一个线程是以一下方式之一来终止的:
- 当顶层的线程例程返回时,线程会隐式地终止
- 通过调用pthread_exit函数时,线程会显式地终止。如果主线程调用pthread_exit,它会等待所有其他对线程终止,然后再终止主线程和整个进程,返回值为thread_return.
- 某个对等线程调用Unix的exit函数,该函数终止进程以及所有与该进程相关的线程
- 另一个对等线程通过以当前线程ID作为参数调用pthread_cancle函数来终止当前线程
12.4 多线程程序中的共享变量
线程化的C程序中变量根据它们的存储类型被映射到虚拟存储器:
- 全局变量。全局变量是定义在函数之外的变量。
- 本地自动变量。本地自动变量就是定义在函数内部但是没有static属性的变量。
- 本地静态变量。本地静态变量是定义在函数内部并有static属性的变量。
12.5 用信号量同步线程
信号量:
- P(s):如果s是非零的,那么P将s减1,并且立即返回。如果s为零,那么久挂起这个线程,知道s变为非零,而一个V操作会重启这个线程。在重启之后,P嘈操作将s减1,并将控制返回给调用者。
- V(s):V操作将s加1.如果有任何线程阻塞在p操作等待s变成非零,那么V操作会重启这些线程中的
一个,然后该线程将s减1,完成它的P操作。
使用信号量来实现互斥:信号量提供了一种很方便的方法来确保对共享变量的互斥访问。基本思想是将每个共享变量与一个信号量s(初始为1)联系起来 ,然后用P(s)和V(s)操作将相应的临界区包围起来。以这种方式来保护共享变量的信号量叫做二元信号量,因为它的值总是0或者1。以提供互斥为目的的二元信号量常常也称为互斥锁。
一个函数被称为线程安全的,当且仅当被多个并发线程反复调用时,它会一直产生正确的结果。如果一个函数不是线程安全的,我们就说它是线程不安全的。定义出四个线程不安全函数类:
1. 不保护共享变量的函数。利用P和V操作这样的同步操作来保护共享的变量。
2. 保持跨越多个调用的状态函数。
3. 返回指向静态变量的指针的函数。
4. 调用线程不安全函数的函数
当一个程序的正确性依赖于一个线程要在另一个线程到达y点之前到达它的控制流中的x点时,就会发生竞争。
互相锁加锁顺序规则:
如果对于程序中每对互斥锁(s,t),每个同时占用s和t的线程都按照相同的顺序对它们加锁,那么这个程序就是无死锁的。
教材学习中的问题和解决过程
代码调试中的问题和解决过程
-
问题1:运行书上的代码时,出现下图错误:
-
解决:想起来老师上课讲过,pthread库不是linux系统默认的库,因此在编译的时候需要加上-lpthread参数。运行成功如下:
代码托管
(statistics.sh脚本的运行结果截图)
上周考试错题总结
其他(感悟、思考等,可选)
学习进度条
代码行数(新增/累积) | 博客量(新增/累积) | 学习时间(新增/累积) | 重要成长 | |
---|---|---|---|---|
目标 | 5000行 | 30篇 | 400小时 | |
第一周 | 20/20 | 1/2 | 10/15 | 第一章 |
第三周 | 130/210 | 1/2 | 21/36 | 第二章 |
第四周 | 70/ 280 | 1/4 | 10/46 | 第十章 |
第五周 | 91 / 371 | 1/6 | 23/69 | 第三章 |
第六周 | 308 / 648 | 1/8 | 31/100 | 第八、十章 |
第七周 | 2200 / 2848 | 1/10 | 25/125 | 第四章 |
第八周 | 1072 / 3492 | 1/12 | 41/166 | 第十一,十二章 |
尝试一下记录「计划学习时间」和「实际学习时间」,到期末看看能不能改进自己的计划能力。这个工作学习中很重要,也很有用。
耗时估计的公式
:Y=X+X/N ,Y=X-X/N,训练次数多了,X、Y就接近了。
-
计划学习时间:41小时
-
实际学习时间:35小时
-
改进情况:
(有空多看看现代软件工程 课件
软件工程师能力自我评价表)