2017-2018-1 20155232 《信息安全系统设计基础》第八周学习总结以及课下补做
2017-2018-1 20155232 《信息安全系统设计基础》第八周学习总结以及课下补做
第八周课下作业1
-
完成家庭作业4.47,4.48,4.49
-
相应代码反汇编成X86-64汇编
-
把上述X86-64汇编翻译成Y86汇编,并给出相应机器码
-
4.47:
书写一个C版本的冒泡排序法,用指针引用数组元素,而不是数组索引。
书写并测试这个函数和测试代码组成的Y86-64程序。
编写4.47代码和测试代码,并且运行:
#include<stdio.h>
void bubble_a(int *data, int count){
int i,next;
for(next = 1; next < count; next++){
for(i = next - 1; i >= 0; i--)
if(*(data + i + 1) < *(data + i)){
int t = *(data + i + 1);
*(data + i + 1) = *(data + i);
*(data + i) = t;
}
}
}
void main()
{
int data[5]={4,90,2,6,0};
int i;
bubble_a(data,5);
for(i=0;i<5;i++)
{
printf("%2d\n",data[i]);
}
}
参考objdump使用使用命令将变成文本格式,我的电脑上安装了y86研究了好久,网上也没有教程,还是不会使用,总是有错误:
这是x-86:
所以找到了在线的y-86模拟器
0x0000: | Disassembly of section .text:
|
0x0000: | 0000000000000000 <bubble_a>:
0x0000: | 0: 83 fe 01 cmp $0x1,%esi
0x0000: | 3: 7e 41 jle 46 <bubble_a+0x46>
0x0000: | 5: 44 8d 4e fe lea -0x2(%rsi),%r9d
0x0000: | 9: 4c 8d 47 04 lea 0x4(%rdi),%r8
0x0000: | d: 31 f6 xor %esi,%esi
0x0000: | f: 49 83 c1 01 add $0x1,%r9
0x0000: | 13: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
0x0000: | 18: 85 f6 test %esi,%esi
0x0000: | 1a: 4c 89 c0 mov %r8,%rax
0x0000: | 1d: 78 18 js 37 <bubble_a+0x37>
0x0000: | 1f: 90 nop
0x0000: | 20: 8b 10 mov (%rax),%edx
0x0000: | 22: 8b 48 fc mov -0x4(%rax),%ecx
0x0000: | 25: 39 ca cmp %ecx,%edx
0x0000: | 27: 7d 05 jge 2e <bubble_a+0x2e>
0x0000: | 29: 89 08 mov %ecx,(%rax)
0x0000: | 2b: 89 50 fc mov %edx,-0x4(%rax)
0x0000: | 2e: 48 83 e8 04 sub $0x4,%rax
0x0000: | 32: 48 39 f8 cmp %rdi,%rax
0x0000: | 35: 75 e9 jne 20 <bubble_a+0x20>
0x0000: | 37: 48 83 c6 01 add $0x1,%rsi
0x0000: | 3b: 49 83 c0 04 add $0x4,%r8
0x0000: | 3f: 4c 39 ce cmp %r9,%rsi
0x0000: | 42: 75 d4 jne 18 <bubble_a+0x18>
|
|
0x0000: | Disassembly of section .text.startup:
|
0x0000: | 0000000000000000 <main>:
0x0000: | 0: 55 push %rbp
0x0000: | 1: 53 push %rbx
|
0x0000: | 7: 48 83 ec 28 sub $0x28,%rsp
0x0000: | b: 48 8d 6c 24 14 lea 0x14(%rsp),%rbp
0x0000: | 10: 48 89 e7 mov %rsp,%rdi
0x0000: | 13: 48 89 e3 mov %rsp,%rbx
0x0000: | 16: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax
0x0000: | 1d: 00 00
0x0000: | 1f: 48 89 44 24 18 mov %rax,0x18(%rsp)
0x0000: | 24: 31 c0 xor %eax,%eax
|
0x0000: | 34: 00
|
0x0000: | 3c: 00
|
0x0000: | 44: 00
|
0x0000: | 60: 48 83 c3 04 add $0x4,%rbx
|
0x0000: | 69: 48 39 eb cmp %rbp,%rbx
0x0000: | 6c: 75 e4 jne 52 <main+0x52>
0x0000: | 4c: 00
|
0x0000: | 52: 8b 13 mov (%rbx),%edx
0x0000: | 54: 31 c0 xor %eax,%eax
|
0x0000: | 6e: 48 8b 44 24 18 mov 0x18(%rsp),%rax
0x0000: | 73: 64 48 33 04 25 28 00 xor %fs:0x28,%rax
0x0000: | 7a: 00 00
0x0000: | 7c: 75 07 jne 85 <main+0x85>
0x0000: | 7e: 48 83 c4 28 add $0x28,%rsp
|
- 4.48:实现冒泡排序,要求不使用跳转,且最多使用3次条件传送。
0x0000: | Disassembly of section .text:
|
0x0000: | 0000000000000000 <bubble_a>:
0x0000: | 0: 83 fe 01 cmp $0x1,%esi
0x0000: | 3: 7e 48 jle 4d <bubble_a+0x4d>
0x0000: | 5: 44 8d 56 fe lea -0x2(%rsi),%r10d
0x0000: | 9: 4c 8d 47 fc lea -0x4(%rdi),%r8
0x0000: | d: 45 31 c9 xor %r9d,%r9d
0x0000: | 10: 49 83 c2 01 add $0x1,%r10
0x0000: | 14: 0f 1f 40 00 nopl 0x0(%rax)
0x0000: | 18: 45 85 c9 test %r9d,%r9d
0x0000: | 1b: 48 89 f8 mov %rdi,%rax
0x0000: | 1e: 78 1e js 3e <bubble_a+0x3e>
0x0000: | 20: 8b 10 mov (%rax),%edx
0x0000: | 22: 8b 48 04 mov 0x4(%rax),%ecx
0x0000: | 25: 39 ca cmp %ecx,%edx
0x0000: | 27: 89 ce mov %ecx,%esi
0x0000: | 29: 0f 4e f2 cmovle %edx,%esi
0x0000: | 2c: 0f 4c d1 cmovl %ecx,%edx
0x0000: | 2f: 48 83 e8 04 sub $0x4,%rax
0x0000: | 33: 89 70 04 mov %esi,0x4(%rax)
0x0000: | 36: 89 50 08 mov %edx,0x8(%rax)
0x0000: | 39: 4c 39 c0 cmp %r8,%rax
0x0000: | 3c: 75 e2 jne 20 <bubble_a+0x20>
0x0000: | 3e: 49 83 c1 01 add $0x1,%r9
0x0000: | 42: 48 83 c7 04 add $0x4,%rdi
0x0000: | 46: 4d 39 d1 cmp %r10,%r9
0x0000: | 49: 75 cd jne 18 <bubble_a+0x18>
|
0x0000: | Disassembly of section .text.startup:
|
0x0000: | 0000000000000000 <main>:
0x0000: | 0: 55 push %rbp
0x0000: | 1: 53 push %rbx
|
0x0000: | 7: 48 83 ec 28 sub $0x28,%rsp
0x0000: | b: 48 8d 6c 24 14 lea 0x14(%rsp),%rbp
0x0000: | 10: 48 89 e7 mov %rsp,%rdi
0x0000: | 13: 48 89 e3 mov %rsp,%rbx
0x0000: | 16: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax
0x0000: | 1d: 00 00
0x0000: | 1f: 48 89 44 24 18 mov %rax,0x18(%rsp)
0x0000: | 24: 31 c0 xor %eax,%eax
|
0x0000: | 34: 00
0x0000: | 35:
0x0000: | 3c: 00
0x0000: | 3d:
0x0000: | 44: 00
0x0000: | 45:
0x0000: | 4c: 00
|
0x0000: | 52: 8b 13 mov (%rbx),%edx
0x0000: | 54: 31 c0 xor %eax,%eax
|
0x0000: | 60: 48 83 c3 04 add $0x4,%rbx
|
0x0000: | 69: 48 39 eb cmp %rbp,%rbx
0x0000: | 6c: 75 e4 jne 52 <main+0x52>
0x0000: | 6e: 48 8b 44 24 18 mov 0x18(%rsp),%rax
0x0000: | 73: 64 48 33 04 25 28 00 xor %fs:0x28,%rax
0x0000: | 7a: 00 00
0x0000: | 7c: 75 07 jne 85 <main+0x85>
0x0000: | 7e: 48 83 c4 28 add $0x28,%rsp
0x0000: | 82: 5b pop %rbx
0x0000: | 83: 5d pop %rbp
- 4.49:实现冒泡排序,要求不使用跳转,且最多使用1次条件传送。
(所有的代码将在最后的码云链接中可查看)
第八周课下作业2
基于socket 使用教材的csapp.h csapp.c,实现daytime(13)服务器(端口我们使用13+后三位学号)和客户端
服务器响应消息格式是“
客户端IP:XXXX服务器实现者学号:XXXXXXXX
当前时间: XX:XX:XX
”上方提交代码
提交一个客户端至少查询三次时间的截图测试截图
提交至少两个客户端查询时间的截图测试截图
多进程实现daytime服务器
参考书上代码echoserverp.c:
多线程实现daytime
课下作业所有代码的码云链接
- 问题:
在使用命令
-lpthread
后即可解决。
- 问题
加上sudo,权限够了即可运行~
教材学习内容总结
本周学习第十一章和第十二章:
第十一章主要是网络编程的一些内容:
- 客户端-服务器模型
- 事务由四步构成的:
客户端发送请求
服务器处理请求
服务器发送响应
客户端处理响应
- 网络
对于一个主机而言,网络是一种I/O设备
- 一个IP地址就是一个32位无符号整数
- 因特网域名
- 使用HOSTNAME命令来确定自己主机的点分十进制:
-
使用HOSTNAME命令来确定自己主机的实际域
名:
-
套接字接口
用来创建网络应用的函数。
- 相关函数
1.socket
2.connect
3.bind
4.listen
5.accept
- web基础
web客户端和服务器之间的交互用的是一个基于文本的应用级协议,叫HTTP(超文本传输协议)。web服务和常规的文件检索服务(例如FTP)的区别在于,web内容可以用HTML(超文本标记语言)语言编写。
- 第12章 并发程序
- 基于进程的并发编程
在父进程中接受客户端连接请求,然后创建一个新的子进程来为每个新客户端提供服务。
- 基于I/O多路复用的并发编程
使用select函数
- 基于I/O多路复用的并发事件驱动服务器I/O
一个状态机就是:状态、输入事件和转移(状态机sk)
- 基于线程的并发编程
线程就是运行在进程上下文的逻辑流,由内核进行调度 。
- Posix线程
1.Posix线程是在C程序中处理线程的一个标准接口
2.Pthread允许程序创建、杀死和回收线程,与对等线程安全的共享数据
3.现成的代码和本地数据被封装在一个线程例程中
- 创建线程:通过调用
pthread_create
函数来创建其他线程
- 终止线程:通过调用
pthread_exit
函数
- 回收已终止线程的资源:调用
pthread_join
函数等待其他线程终止
- 分离线程
1.每个可结合线程可以被其他线程显式的收回
2.也通过调用pthread_detach函数被分离
-
初始化线程:pthread_once函数允许你初始化与线程例程相关的状态
-
用信号量同步线程
1.进度图
进度图是将n个并发线程的执行模型化为一条n维笛卡尔空间中的轨迹线,原点对应于没有任何线程完成一条指令的初始状态。
2.信号量是具有非负整数值的全局变量,只能由两种特殊的操作来处理,这两种操作称为P和V
3.信号量不变性:一个正在运行的程序绝不能进入这样一种状态,也就是一个正确初始化了的信号量有一个负值。
- 共享资源
1.生产者和消费者
2.读者和写者
在输入692页代码时:
第四行是主线程代码的开始,主线程通过调用pthread_create函数创建了一个新的对等线程,在pthread_join中主线程等待对等线程终止。在*thread中定义了对等的线程,只打印了一个字符串。
- 在运行hellosingle.c时
#include <stdio.h>
#define NUM 5
void print_msg(char *);
int main()
{
print_msg("hello");
print_msg("world\n");
}
void print_msg(char *m)
{
int i;
for(i=0 ; i<NUM ; i++){
printf("%s", m);
fflush(stdout);
sleep(1);
}
}
这个程序很简单,是一个单线程,对程序进行分析得到:调用了两遍print_msg函数,每次调用把传入的字符串打印了五遍。
- 在运行老师给的代码:
#include <stdlib.h>
#include <pthread.h>
#include <stdlib.h>
typedef struct _msg{
struct _msg * next;
int num;
} msg;
msg *head;
pthread_cond_t has_product = PTHREAD_COND_INITIALIZER;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
void *consumer ( void * p )
{
msg * mp;
for( ;; ) {
pthread_mutex_lock( &lock );
while ( head == NULL )
pthread_cond_wait( &has_product, &lock );
mp = head;
head = mp->next;
pthread_mutex_unlock ( &lock );
printf( "Consume %d tid: %d\n", mp->num, pthread_self());
free( mp );
sleep( rand() % 5 );
}
}
void *producer ( void * p )
{
msg * mp;
for ( ;; ) {
mp = malloc( sizeof(msg) );
pthread_mutex_lock( &lock );
mp->next = head;
mp->num = rand() % 1000;
head = mp;
printf( "Produce %d tid: %d\n", mp->num, pthread_self());
pthread_mutex_unlock( &lock );
pthread_cond_signal( &has_product );
sleep ( rand() % 5);
}
}
int main(int argc, char *argv[] )
{
pthread_t pid1, cid1;
pthread_t pid2, cid2;
srand(time(NULL));
pthread_create( &pid1, NULL, producer, NULL);
pthread_create( &pid2, NULL, producer, NULL);
pthread_create( &cid1, NULL, consumer, NULL);
pthread_create( &cid2, NULL, consumer, NULL);
pthread_join( pid1, NULL );
pthread_join( pid2, NULL );
pthread_join( cid1, NULL );
pthread_join( cid2, NULL );
return 0;
}
运行结果:
可以看出,wait函数用于等待信号,signal函数用于通知信号。其中wait函数中有一次对mutex的释放和重新获取操作,因此生产者和消费者并不会出现死锁。也就是消费者等待生产者产出产品后才打印,否则消费者阻塞等待生产者生产。
- 运行count.c代码
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#define NLOOP 5000
int counter;
void *doit( void * );
int main(int argc, char **argv)
{
pthread_t tidA, tidB;
pthread_create( &tidA ,NULL, &doit, NULL );
pthread_create( &tidB ,NULL, &doit, NULL );
pthread_join( tidA, NULL );
pthread_join( tidB, NULL );
return 0;
}
void * doit( void * vptr)
{
int i, val;
for ( i=0; i<NLOOP; i++ ) {
val = counter++;
printf("%x: %d \n", (unsigned int) pthread_self(), val + 1);
counter = val + 1;
}
}
运行结果:
运行creatthread.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
pthread_t ntid;
void printids( const char *s )
{
pid_t pid;
pthread_t tid;
pid = getpid();
tid = pthread_self();
printf("%s pid %u tid %u (0x%x) \n", s , ( unsigned int ) pid,
( unsigned int ) tid, (unsigned int ) tid);
}
void *thr_fn( void * arg )
{
printids( arg );
return NULL;
}
int main( void )
{
int err;
err = pthread_create( &ntid, NULL, thr_fn, "new thread: " );
if ( err != 0 ){
fprintf( stderr, "can't create thread: %s\n", strerror( err ) );
exit( 1 );
}
printids( "main threads: " );
sleep(1);
return 0;
}
运行结果:
通过此代码打印出了进程和线程ID。
教材学习中的问题和解决过程
-
问题1: 监听描述符和已连接描述符之间的区别?
-
因为,区分这两者是很有用的,因为它使得我们可以建立并发服务器,它能够同时处理多个客户端连接。比如,每次一个连接请求到达监听描述符时,我们可以派生(fork)一个新的进程,它通过已连接描述符与客户端通信。
-
问题2:为什么已经有了socket_addr_in还要设计socketaddr这样的类型,反而要在传参或者初始化过程中通过强制类型转换?
-
不同的系统或者说不同的网络协议族结构是不一样的,这样通过再加一层封装以后,可以是一个统一的结构。
代码调试中的问题和解决过程
-
问题1:在对课本11.2的代码进行运行时,出现如下错误:
-
解决
在编译时要使用
gcc *.c -o ** -lpthread
才可以编译成功。
-
在编译如下代码时出现错误
代码功能是统计两个文件的总字数 -
粗心导致在
./count...
代码中没有空格。
- 在输入课本p720页代码时出现如下错误:
- 在仔细检查后,发现时粗心所致,没有注意字母p的大小写,导致,在修改后,运行成功:
在720页代码和719页代码做一下对比,输出结果是大不一样的:
719页的输出是错误的,是由于每个对等线程和主线程之间的竞争引起的,所以为了消除这种错误,就在720页代码中加入了 动态的为每个整数ID分配一个独立的块。
代码托管
上周考试错题总结
无
结对及互评
点评模板:
暂无
本周结对学习情况
-
- 结对学习内容
- 共同学习课本第十一章和第十二章,实验楼内容
- 分析课本中代码遇到的问题
- 结对学习内容
思考
本周学习的主要内容是多线程和网络编程,首先学习了课本上的第十一章,因为刘念老师的课上讲过之后,在看书就很容易明白了,再看第十二章,书上了解并发的相关知识——进程、线程,使我对于并发是怎么进行的有了一个大概的理解,结合着代码就加深了印象。
学习进度条
学习进度条
代码行数(新增/累积) | 博客量(新增/累积) | 学习时间(新增/累积) | 重要成长 | |
---|---|---|---|---|
目标 | 5000行 | 30篇 | 400小时 | |
第四周 | 12/12 | 1/1 | 20/20 | |
第五周 | 271/283 | 1/2 | 15/15 | |
第6周 | 276/283 | 2/3 | 18/18 | |
第7周 | 150/283 | 4/4 | 21/23 | |
第8周 | 579/283 | 4/4 | 24/27 | |
尝试一下记录「计划学习时间」和「实际学习时间」,到期末看看能不能改进自己的计划能力。这个工作学习中很重要,也很有用。 | ||||
耗时估计的公式 | ||||
:Y=X+X/N ,Y=X-X/N,训练次数多了,X、Y就接近了。 |
-
计划学习时间:27小时
-
实际学习时间:24小时
(有空多看看现代软件工程 课件
软件工程师能力自我评价表)