2017-2018-1 20155324 《信息安全系统设计基础》第八周学习总结 2017-2018-1 20155324 《信息安全系统设计基础》第八周学习总结

第八周课下作业2(课上没完成的必做)

基于socket 使用教材的csapp.h csapp.c,实现daytime(13)服务器(端口我们使用13+后三位学号)和客户端
服务器响应消息格式是
“
客户端IP:XXXX
服务器实现者学号:XXXXXXXX
当前时间: XX:XX:XX
”
上方提交代码
提交一个客户端至少查询三次时间的截图测试截图
提交至少两个客户端查询时间的截图测试截图

书上相关代码

多线程
/* 
 * echoserveri.c - An iterative echo server 
 */ 
/* $begin echoserverimain */
#include "csapp.h"

void echo(int connfd);

int main(int argc, char **argv) 
{
    int listenfd, connfd, port, clientlen;
    struct sockaddr_in clientaddr;
    struct hostent *hp;
    char *haddrp;
    if (argc != 2) {
    fprintf(stderr, "usage: %s <port>
", argv[0]);
    exit(0);
    }
    port = atoi(argv[1]);

    listenfd = Open_listenfd(port);
    while (1) {
    clientlen = sizeof(clientaddr);
    connfd = Accept(listenfd, (SA *)&clientaddr, &clientlen);

    /* determine the domain name and IP address of the client */
    hp = Gethostbyaddr((const char *)&clientaddr.sin_addr.s_addr, 
               sizeof(clientaddr.sin_addr.s_addr), AF_INET);
    haddrp = inet_ntoa(clientaddr.sin_addr);
    printf("server connected to %s (%s)
", hp->h_name, haddrp);

    echo(connfd);
    Close(connfd);
    }
    exit(0);
}
/* $end echoserverimain */

echoclient.c:

/*
 * echoclient.c - An echo client
 */
/* $begin echoclientmain */
#include "csapp.h"

int main(int argc, char **argv) 
{
    int clientfd, port;
    char *host, buf[MAXLINE];
    rio_t rio;

    if (argc != 3) {
    fprintf(stderr, "usage: %s <host> <port>
", argv[0]);
    exit(0);
    }
    host = argv[1];
    port = atoi(argv[2]);

    clientfd = Open_clientfd(host, port);
    Rio_readinitb(&rio, clientfd);

    while (Fgets(buf, MAXLINE, stdin) != NULL) {
    Rio_writen(clientfd, buf, strlen(buf));
    Rio_readlineb(&rio, buf, MAXLINE);
    Fputs(buf, stdout);
    }
    Close(clientfd);
    exit(0);
}
/* $end echoclientmain */

2017-2018-1 20155324 《信息安全系统设计基础》第八周学习总结
2017-2018-1 20155324 《信息安全系统设计基础》第八周学习总结

2017-2018-1 20155324 《信息安全系统设计基础》第八周学习总结
2017-2018-1 20155324 《信息安全系统设计基础》第八周学习总结

遇到的问题:怎么导入csapp.h

下载并解压后(以 root 身份登录)应该是一个code的文件夹,在其子文件夹includesrc中分别可以找到csapp.hcsapp.c两个文件,把这两个文件拷贝到文件夹/usr/include里面,并在csapp.h文件中 #endif 之前加上一句 #include<csapp.h> ,然后编译时在最后加上 lpthread 例如:gcc main.c -lpthread 就可以编译了。

家庭作业4.47

取指阶段 icode:ifun = D:0
valP<-PC+1
译码阶段:valB<-R[%ebp]
执行阶段:valE<-valB+4
访存阶段:valM<-M4[valB]
写回阶段:R[%esp]<-valE R[%ebp]<-valM

家庭作业4.48

取指阶段:icode:ifun = M1[PC] = C:0 
rA:rB<-M1[PC+1]
valC<-M4[PC+2]
valP<-PC+6   
译码阶段:valB<-R[rB]   
执行阶段:valE<-valB+valC
SetCC
访存阶段:-  
写回阶段  R[rB]<-valE 

教材学习内容总结

教材第十二章学习

什么是进程(Process)?

进程就是一段程序的执行过程。

进程的概念主要有两点:

  • 第一,进程是一个实体。每一个进程都有它自己的地址空间,一般情况下,包括文本区域(text region)、数据区域(data region)和堆栈(stack region)。文本区域存储处理器执行的代码;数据区域存储变量和进程执行期间使用的动态分配的内存;堆栈区域存储着活动过程中调用的指令和本地变量。

  • 第二,进程是一个“执行中的程序”。程序是一个没有生命的实体,只有处理器赋予程序生命时,它才能成为一个活动的实体,我们称其为进程。

进程的状态: 进程有三个状态,就绪,运行和阻塞。

  • 就绪状态其实就是获取了除cpu外的所有资源,只要处理器分配资源马上就可以运行。

  • 运行态就是获取了处理器分配的资源,程序开始执行。

  • 阻塞态,当程序条件不够时,需要等待条件满足时候才能执行,如等待I/O操作的时候,此刻的状态就叫阻塞态。

进程的特征:

  • 动态性:进程是程序的一次执行过程,是临时的,有生命期的,是动态产生,动态消亡的;

  • 并发性:任何进程都可以同其他进程一起并发执行;

  • 独立性:进程是系统进行资源分配和调度的一个独立单位;

  • 结构性:进程由程序、数据和进程控制块三部分组成。

什么是线程(thread)?

定义:线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。

线程起源:

  • 在早期的操作系统中并没有线程的概念,进程是能拥有资源和独立运行的最小单位,也是程序执行的最小单位。任务调度采用的是时间片轮转的抢占式调度方式,而进程是任务调度的最小单位,每个进程有各自独立的一块内存,使得各个进程之间内存地址相互隔离。

  • 后来,随着计算机的发展,对CPU的要求越来越高,进程之间的切换开销较大,已经无法满足越来越复杂的程序的要求了,于是就发明了线程。

线程特征:

  • 线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),一个线程可以创建和撤销另一个线程;

  • 通常在一个进程中可以包含若干个线程,当然一个进程中至少有一个线程,不然没有存在的意义。线程可以利用进程所拥有的资源。在引入线程的操作系统中,通常都是把进程作为分配资源的基本单位,而把线程作为独立运行和独立调度的基本单位,由于线程比进程更小,基本上不拥有系统资源,故对它的调度所付出的开销就会小得多,能更高效的提高系统多个程序间并发执行的程度。

进程 和 线程的区别
1、一个程序至少有一个进程,一个进程至少有一个线程;

     进程是资源分配的最小单位,线程是CPU调度的最小单位。

2、资源(内存、寄存器等)分配给进程,进程在执行过程拥有独立的内存空间,而同一进程下的所有线程共享所有资源,从而提高程序的运行效率;

3、处理机分配给线程,即处理机真正运行的是线程;

4、线程在执行过程中,需要协作同步。不同线程间的要利用通信协议来实现同步。

I/O多路复用

2017-2018-1 20155324 《信息安全系统设计基础》第八周学习总结
2017-2018-1 20155324 《信息安全系统设计基础》第八周学习总结

I/O multiplexing 这里面的 multiplexing 指的其实是在单个线程通过记录跟踪每一个Sock(I/O流)的状态(对应空管塔里面的Fight progress strip槽)来同时管理多个I/O流. 发明它的原因,是尽量多的提高服务器的吞吐能力。

2017-2018-1 20155324 《信息安全系统设计基础》第八周学习总结
2017-2018-1 20155324 《信息安全系统设计基础》第八周学习总结

基于 I/O 多路复用的并发编程
  • I/O多路复用技术的基本思路:使用select函数,要求内核挂起进程,只有在一个或多个I/O事件发生后,才将控制返回给应用程序

  • 状态机就是一组状态、输入事件和转移,转移就是将状态和输入时间映射到状态,自循环是同一输入和输出状态之间的转移。

  • I/O 多路复用技术的优劣

优点:

  • 它比基于进程的设计给了程序员更多的对程序行为的控制。

  • 一个基于 I/O 多路复用的事件驱动服务器是运行在单一进程上下文中的,因 此每个逻辑流都能访问该进程的全部地址空间。

缺点:

  • 编码复杂且不能充分利用多核处理器。

2017-2018-1 20155324 《信息安全系统设计基础》第八周学习总结
2017-2018-1 20155324 《信息安全系统设计基础》第八周学习总结

线程控制及相关系统调用

  1. 内核级线程:切换由内核控制,当线程进行切换的时候,由用户态转化为内核态。切换完毕要从内核态返回用户态;可以很好的利用smp,即利用多核cpu。windows线程就是这样的。

  2. 用户级线程内核的切换由用户态程序自己控制内核切换,不需要内核干涉,少了进出内核态的消耗,但不能很好的利用多核Cpu,目前Linux pthread大体是这么做的。

线程的实现可以分为两类:用户级线程(User-Level Thread)和内核线线程(Kernel-Level Thread),后者又称为内核支持的线程或轻量级进程。在多线程操作系统中,各个系统的实现方式并不相同,在有的系统中实现了用户级线程,有的系统中实现了内核级线程。

用户进程的优点:

(1) 线程的调度不需要内核直接参与,控制简单。

(2) 可以在不支持线程的操作系统中实现。

(3) 创建和销毁线程、线程切换代价等线程管理的代价比内核线程少得多。

(4) 允许每个进程定制自己的调度算法,线程管理比较灵活。这就是必须自己写管理程序,与内核线程的区别

(5) 线程能够利用的表空间和堆栈空间比内核级线程多。

(6) 同一进程中只能同时有一个线程在运行,如果有一个线程使用了系统调用而阻塞,那么整个进程都会被挂起。另外,页面失效也会产生同样的问题。

多线程程序中的变量共享

每个线程和其他线程一起共享进程上下文的剩余部分。包括整个用户虚拟地址空间,是由只读文本、读/写数据、堆以及所有的共享库代码和数据区域组成的。线程也共享同样的打开文件的集合。

  • 全局变量:虚拟存储器的读/写区域只会包含每个全局变量的一个实例。

  • 本地自动变量:定义在函数内部但没有static属性的变量。

  • 本地静态变量:定义在函数内部并有static属性的变量。

用信号量同步线程

进度图是将n个并发线程的执行模型化为一条n维笛卡尔空间中的轨迹线,原点对应于没有任何线程完成一条指令的初始状态。

转换规则:
合法的转换是向右或者向上,即某一个线程中的一条指令完成
两条指令不能在同一时刻完成,即不允许出现对角线
程序不能反向运行,即不能出现向下或向左

信号量定义:

type semaphore=record
count: integer;
queue: list of process
end;
var s:semaphore;

读者—写者问题:
(1)读者优先,要求不让读者等待,除非已经把使用对象的权限赋予了一个写者。
(2)写者优先,要求一旦一个写者准备好可以写,它就会尽可能地完成它的写操作。
(3)饥饿就是一个线程无限期地阻塞,无法进展。

HTML静态化

效率最高、消耗最小的就是纯静态化的html页面,所以尽可能使网站上的页面采用静态页面来实现,这个最简单的方法其实也是最有效的方法。但是对于大量内容并且频繁更新的网站,无法全部手动去挨个实现,于是出现了常见的信息发布系统CMS,像常访问的各个门户站点的新闻频道,甚至他们的其他频道,都是通过信息发布系统来管理和实现的,信息发布系统可以实现最简单的信息录入自动生成静态页面,还能具备频道管理、权限管理、自动抓取等功能,对于一个大型网站来说,拥有一套高效、可管理的CMS是必不可少的。

阻塞 VS 非阻塞

阻塞/非阻塞, 它们是程序在等待消息(无所谓同步或者异步)时的状态。

阻塞

阻塞调用是指调用结果返回之前,当前线程会被挂起。函数只有在得到结果之后才会返回。
有人也许会把阻塞调用和同步调用等同起来,实际上他是不同的。
对于同步调用来说,很多时候当前线程还是激活的,只是从逻辑上当前函数没有返回而已。

socket接收数据函数recv是一个阻塞调用的例子。
当socket工作在阻塞模式的时候, 如果没有数据的情况下调用该函数,则当前线程就会被挂起,直到有数据为止。

非阻塞

非阻塞和阻塞的概念相对应,指在不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回。

教材学习中的问题和解决过程

  • 问题1:一个头文件csapp.h,编译代码时遇到csapp不存在的问题
  • 问题1解决方案:下载并解压后(以 root 身份登录)应该是一个code的文件夹,在其子文件夹includesrc中分别可以找到csapp.hcsapp.c两个文件,把这两个文件拷贝到文件夹/usr/include里面,并在csapp.h文件中 #endif 之前加上一句 #include<csapp.h> ,然后编译时在最后加上 lpthread 例如:gcc main.c -lpthread 就可以编译了。

代码托管

其他(感悟、思考等,可选)

学习了系统的输入、输出,了解了一些I/O函数,只看书的页数的话,本章的页数很少,相较于之前几周感觉轻松不少。但是,页数少并不意味着不重要或是用时少,认真去理解系统的输入、输出对于我们理解程序的运行至关重要,而每一个函数的参数、不同情况的返回值也需要我们仔细研读。

学习进度条

代码行数(新增/累积) 博客量(新增/累积) 学习时间(新增/累积) 重要成长
目标 5000行 30篇 400小时
第一周 85/85 1/1 5/5
第二周 150/230 1/2 10/15
第三周 50/280 1/3 7/22
第四周 70/350 1/4 5/27
第五周 100/450 2/6 5/32
第六周 50/500 1/7 10/42
第七周 70/570 2/9 10/55
第八周 80/650 1/10 8/63

尝试一下记录「计划学习时间」和「实际学习时间」,到期末看看能不能改进自己的计划能力。这个工作学习中很重要,也很有用。
耗时估计的公式
:Y=X+X/N ,Y=X-X/N,训练次数多了,X、Y就接近了。

参考:软件工程软件的估计为什么这么难软件工程 估计方法

  • 计划学习时间:XX小时

  • 实际学习时间:XX小时

  • 改进情况:

(有空多看看现代软件工程 课件
软件工程师能力自我评价表
)

参考资料