2018-2019-1 20165325 《信息安全系统设计基础》第八周学习总结
一、学习笔记——网络编程
1、三种并发方式
构造并发程序的方法有三种:
- 进程
- 线程
- I/O多路复用
进程:用内核来调用和维护,有独立的虚拟地址空间,显式的进程间通信机制。
线程:运行在一个单一进程上下文中的逻辑流。由内核进行调度,共享同一个虚拟地址空间。
I/O多路复用:应用程序在一个进程的上下文中显式地调度控制流。逻辑流被模型化为状态机。
2、C/S编程模型
客户端和服务器都是进程,C/S编程模型由一个服务器进程和一个或多个客户端进程组成
服务器进程管理某种资源,通过操作这种资源来为它的客户端提供某种服务。基本操作为事务,一个客户端-服务器事务由四步组成:
客户端向服务器发送请求,发起一个事务;
服务器收到请求,操作资源;
服务器给客户端发送一个响应,并等待下一个请求。
客户端收到响应并处理它。
3、线程控制及相关系统调用
在上一次的socket编程中,服务器持续listen,如果有客户端进程请求,服务器父进程就会派生一个子进程来处理新的连接请求。这便存在基于进程的并发编程。
线程:运行子进程上下文中的逻辑流
线程与进程的不同:
线程的上下文切换要比进程的上下文切换快得多;
和一个进程相关的线程组成对等,独立于其他线程创建的线程。
主线程和其他线程的区别仅在于它总是进程中第一个运行的线程。
创建线程
pthread create
:创建一个新的线程,在新线程的上下文中运行线程例程f。
新线程可以通过pthread _self
获得自己的线程ID。
终止线程
一个线程的终止方式:
当顶层的线程例程返回,线程会隐式地终止;
pthread_exit
:线程显式地终止。
注:如果主线程调用pthread _exit
,它会等待所有其他对等线程终止,然后再终止主线程和整个进程。
回收已终止线程的资源
pthread _join
:阻塞,直到线程tid终止,回收已终止线程占用的所有存储器资源。
注:pthread _join
只能等待一个指定的线程终止。
分离线程
在任何一个时间点上,线程是可结合的或者是分离的。一个可结合的线程能够被其他线程收回其资源和杀死;一个可分离的线程是不能被其他线程回收或杀死的。它的存储器资源在它终止时有系统自动释放。
默认情况下,线程被创建成可结合的,为了避免存储器漏洞,每个可集合的线程都应该要么被其他进程显式的回收,要么通过调用
pthread _detach
被分离。
初始化线程
pthread _once
允许初始化与线程例程相关的状态。once _control
变量是一个全局或者静态变量,总是被初始化为PTHREAD _ONCE _INIT
。
二、Linux实现命令——mypwd
1、pwd命令学习
在Linux中使用man命令查看pwd:
实际操作使用pwd命令:
pwd命令的作用是查看当前所在的工作路径。
2、思路
基本原理:
每个目录下都至少有两个内容‘.’和’..’,其中‘.’代表当前目录,’..’代表父目录。每个目录或文件都有对应的i-节点号。
$ ls -1ia
(数字1,不是字母l):查看当前目录下的文件名和对应的i-节点号。
伪代码不会写(写出来不规范,可能只有自己看得懂),思路大概是:
查看本目录的i-节点,找到父目录;
进入父目录,输出其i-节点对应的文件夹名;
循环以上过程直到到达根目录;
注:首先找到的目录是较小的子目录,最后才读取到根目录。但是输出是从根目录开始的。
典型的输入输出逆序问题,一般两种解决方案:一是用栈,二是用递归。
这里我使用递归实现。
判断是否抵达根目录
根目录的‘.’和’..’相同,i-节点号相同。
用到的核心函数
stat(char* fname, struct stat* bufp);
把文件fname的信息复制到bufp所指结构体里(stat结构体包含了文件的信息,在/user/include/sys/stat.h中可以看到struct stat的成员变量。);readdir(DIR* dir_ptr)
读取dir_ptr目录的所有文件和目录,返回值是struct dirent结构体;每次调用都会指向下一个文件,遍历完后返回值为NULL;chdir
3、实现mypwd
代码:
///
//mypwd.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
void mypwd(ino_t this_inode);
void inum_to_name(ino_t inode_to_find,char* namebuf,int buflen);
ino_t get_inode(char* fname);
//返回文件的i节点
ino_t get_inode(char* fname)
{
struct stat info;
if (stat(fname, &info) == -1){
fprintf( stderr , "Cannot stat ");
perror(fname);
exit (1);
}
return info.st_ino;
}
void mypwd(ino_t this_inode)
{
ino_t my_inode;
char its_name[BUFSIZ];
//检查本目录是不是根目录
if (get_inode("..")!=this_inode)
{
//进入上级目录
chdir("..");
inum_to_name(this_inode,its_name,BUFSIZ);
my_inode = get_inode(".");
mypwd(my_inode);
printf("/%s",its_name);
}
}
//找到i节点对应的文件名,并放在字符数组里
void inum_to_name(ino_t inode_to_find,char* namebuf,int buflen)
{
DIR* dir_ptr;
struct dirent* direntp;
dir_ptr = opendir(".");
if (dir_ptr == NULL)
{
perror(".");
exit(1);
}
//寻找指定i节点的目录,将目录名复制到namebuf中。
while((direntp = readdir(dir_ptr)) != NULL)
{
if(direntp->d_ino == inode_to_find)
{
strncpy(namebuf,direntp->d_name,buflen);
namebuf[buflen-1] = '\0';
closedir(dir_ptr);
return;
}
}
fprintf( stderr , "ERROR while looking for inum %d : NOT FOUND!\n",(int)inode_to_find);
exit (1);
}
int main()
{
//显示路径
mypwd(get_inode("."));
putchar('\n');
return 0;
}