前言:Linux是一套免费使用和自由传播的类Unix操作系统,是一个基于POSIX和UNIX的多用户、多任务、支持多线程和多CPU的操作系统。它能运行主要的UNIX工具软件、应用程序和网络协议。
Linux系统一般有四个主要部分:内核、shell、文件系统、应用程序。前三者一起构成了基本的操作系统,应用程序则是在这个基础上运行的。
Part 1: 标准IO
I/O:input & output,是一切实现的基础
stdio 标准IO
sysio 系统调用IO(文件IO)
stdio: FILE类型贯穿始终
fopen();
fclose();
fgetc();
fputc();
fgets();
fputs();
fread(); binary read
fwrite(); binary write
printf();
scanf();
fseek();
ftell();
int fseeko(FILE *stream, off_t offset, int whence);
node: On some architectures, both off_t and long are 32-bit types, but
defining _FILE_OFFSET_BITS 64
with the value 64 (before including any header files) will turn off_t into a 64-bit type.
off_t ftello(FILE *stream);
rewind();
fflush();
1. 缓冲区的作用:大多数情况下是好事,合并系统调用。
2. 行缓冲:换行时候刷新,满了的时候刷新,强制刷新(标准输出是这样的,因为是终端设备)
3. 全缓冲:满了的时候刷新,强制刷新(默认是全缓冲,只要不是终端设备)
4. 无缓冲:如stderr, 需要立即输出的内容
5. 更改缓冲模式的函数 setvbuf()--- 一般用不上
Part 2: 系统IO/文件IO
fd 是在文件IO中贯穿始终的类型
文件描述符的概念:

1. 实质:整形数---数组的下标,优先使用当前可用范围最小的。
2. 当前数组是在一个进程空间中的,不同进程不会共用。
3. 是进程用来访问操作系统对象的“指针”。
文件IO相关操作:
1. open(const char *pathname, int flags); flags --- 位图
2. flags must be: O_RDONLY, O_WRONLY, or O_RDWR.
3. or has O_CLOEXEC, O_CREAT, O_DIRECTORY, O_EXCL, O_NOCTTY,O_NOFOLLOW, O_TMPFILE, O_TRUNC... see man 2 open.
4. r --- O_RDONLY
5. r+ ---- O_RDWR
6. w ---- O_WRONLY|O_CREATE|O_TRUNC
7. w+ ---- O_RDWR|O_TRUNC|O_CREATE
8. read()
9. write()
10. close()
11. lseek
文件IO和标准IO的区别
1. 响应速度 & 吞吐量
2. 如何使一个程序变快?主要考虑上面两个方面进行回答。
3. 标准IO和系统IO 不可混用
IO的效率问题
bufsize 的大小会影响效率,但有一个最佳的bufsize 大小,需要测试。
文件共享
线程共享,在一个进程空间多次打开文件。
进程共享,在两个进程中去打开文件,利用进程间共享。
试题:写一个程序删除一个文件的第10行。
原子操作
1. 不可分割的操作
2. 不可分割的最小单位
3. 解决竞争和冲突
4. 如:tmpnam()
程序中的重定向:dup dup2
dup2(old_fd, new_fd) : 把old_fd 从定向到new_fd,第一,关闭new_fd。 第二,copy old_fd 到new_fd。第三,如果old_fd == new_fd时,什么都不做。
同步:sync fsync, fdatasysnc
1. sync - commit buffer cache to disk,同步内核层面的buf cache
2. 解除设备挂载时用到。 man 2 sync see the details.
fcntl()
1. 文件描述符所变的魔术几乎都来源与该函数。
ioctl()
1. 设备相关的内容
/dev/fd/目录
1. 虚目录
Part 3: File System
文件系统:
一、目录和文件
1. 获取文件属性
stat():通过文件路径获取属性,面对符号链接文件时获取的是所指向的属性。
fstat():通过文件描述符获取属性。
lstat():面对符号链接文件时获取的是符号链接文件的属性。
文件类型:7种 --- dcb-lsp d:目录文件 c:字符设备文件 b:块设备文件 -:常规文件
l:链接文件(符号链接文件)s:网络套接字socket 文件 p:管道文件
2. 文件访问权限
st_mode 是一个16位的位图,用于表示文件类型,文件访问权限,特殊权限位
3. umask
作用:防止产生权限过松的文件
4. 文件权限的更改/管理
chmod();
chmod a+x big.c --- a+x:所有可读可写可执行 rwxrwxrwx. u+x 代表user rwx.
g+x: group rwx. o+x :other x.
fchmod();
5. 粘住位
t 位 /tmp 目录有t位
6. 文件系统:FAT,UFS
文件或数据的存储和管理
7. 硬链接,符号链接
硬链接与目录项是同义词,且建立硬链接有限制:不能给目录建立,不能给分区建立。
符号链接优点:可跨分区,可以给目录建立。
link() ---> ln src dest/ln -s src dest.
unlink()
remove() ---> rm
rename() ---> mv
8. utime
change file last access and modification times.
9. 目录的创建和销毁
mkdir()
rmdir()
10. 更改当前工作路径
chdir(); ---> cd: change working directory.
fchdir();
getcwd();---> pwd: get current working directory.
11. 分析目录/读取目录内容
glob():解析模式/ 统配符 可以实现以下方法的集合。
opendir();
closedir();
readdir();
rewinddir();
fseekdir();
seekdir();
telldir();
二、系统数据文件和信息
1. /etc/passed
getpwuid();
getpwnam();
2. /etc/group
getgrgid();
getgrgnam();
3. /etc/shadow
getspnam();
crypt();
getpass();
4. 时间戳: time_t char * struct tm
time();
gmtime();
localtime();
mktime();
strftime();
三、进程环境
1. main() 函数
int main(int argc, char **argv);
2. 进程的终止
正常终止:
1)从main 函数返回
2)调用exit()
3) 调用_exit() 或_Exit()
4) 最后一个线程从其启动例程返回
5) 最后一个线程调用pthread_exit()
异常终止:
1)调用abort()
2) 接到一个信号并终止
3) 最后一个线程对其取消请求作出响应
atexit();
在进程正常结束时钩子函数逆序被调用,但是进程如果是调用_exit()或_Exit()不会执行钩子函数
3. 命令行参数的分析
getopt()
getopt_long()
4. 环境变量
key=value
getenv();
setenv();
putenv();
5. c程序的存储空间布局 (pmap p_id)

6. 库
动态库
静态库
手工装载库
dlopen();
dlerror();
dlsym();
dlclose();
7. 函数跳转
setjmp();
设置跳转点
longjmp();
安全跨函数的跳转
8. 资源的获取及控制
getrlimit();
setrlimit();
Part 4: Process
进程基本知识, 已经进入多进程。
1. 进程标识符 pid
1)类型pid_t 有符号16位整数(现在已经扩展根据机器环境有不同的大小)
2)命令ps (man ps) 例如: ps axf ps axm ps ax -L
3)进程号是顺次向下使用
4)getpid();
5)getppid();
2. 进程的产生
1)fork();
2)注意理解关键字:duplicating,意味着拷贝,克隆,一模一样等含义,代码从fork()的位置开始一式两份。
3)fork后父子进程的区别:fork的返回值不一样,pid不同,ppid也不同,未决信号和文件锁不继承,资源利用量清零。
4)init进程:是所有进程的祖先进程 进程号是1号
5)调度器的调度策略决定了哪个进程先运行,不可假设。
6)fork() 之前fflush() 的重要性。
7)子进程exit() 的重要性。
8)vfork()
3. 进程的消亡及释放资源
wait();
waitpid()
wait3();
wait4();
4. exec函数族
execl();
execlp();
execle();
execv();
execvp();
注意:exec组函数使用注意fflush 的使用。
5. 用户权限及组权限
u + s
g + s
getuid();
geteuid();
getgid();
getegid();
setuid();// 常用 例子:mysu.c
setgid();
setreuid();
setregid();
seteuid();
setguid();
chown root ./mysu
chmod u+s ./mysu
6. 解释器文件
#! /bin/bash
7. system();
理解:fork + exec + wait 封装
例子:
fork() + exec("/bin/sh", "sh", "date + %s < /dev/null", NULL) + wait()的一个简单封装
8. 进程会计
acct();
9. 进程时间
进程时间
times() ---> time ./myexec
10. 守护进程
会话 session
是一个容器,承载进程组。
标识sid
setsid()
creates a new session if the calling process is not a process
group leader.The calling process is the leader of the new session,
the process group leader of the new process group,
and has no controlling tty.
终端
输入和输出
setpgid();
getpgid();
getpgrp();
单实例的守护进程:用的是锁文件 /var/run/xxx.pid
启动脚本文件:/etc/rc1./xx
11. 系统日志
存放的位置: /var/log
rsyslogd 服务
openlog();
syslog();
closelog();
Part 5: Concurrency
同步
异步
异步事件的处理:查询法,通知法。
异步事件发生的很稀疏通知法是合适的,发生很频繁用查询法。
一、信号
1. 信号的概念
信号是软件层面的中断。
信号的响应依赖于中断。
2. signal();
kill -l 显示信号
SIGINT ---> ctrl + c
信号会打断阻塞的系统调用。
3. 信号的不可靠
指信号行为的不可靠
4. 可重入函数
所有的系统调用都是可重入的,一部分库函数也是可重入的。memcpy()可重入,rand()不可重入,
rand_r() 可重入。
5. 信号的响应过程
信号从受到到响应有一个不可避免的延迟
思考:信号如何忽略掉一个信号的?
标准信号为什么要丢失?
标准信号的响应没有严格的顺序。
不能从信号处理函数中随意的往外跳

6. 常用函数
kill(); -- send signal to a process
raise();-- send a signal to the caller
alarm();
setitimer();
例:使用单一计时器,setitimer()或alarm()构造一组函数,实现任意数量的计时器。
pause();-- wait a signal
abort();-- create a core dump file
system();
During execution of the command, SIGCHLD will
be blocked and SIGINT and SIGQUIT will be ignored,
in the process that calls system().
sleep();
usleep();
nanosleep();
select();
7. 信号集
类型:sigset_t
sigemptyset();
sigfillset();
sigaddset();
sigismember();
8. 信号屏蔽子/pending 集的处理
sigprocmask(); 例子:block.c
sigpending(); --- 不常用
9. 扩展集
sigsuspend(); -- wait for a signal
解除信号集马上进入等待一个信号
sigaction(); -- signal()
10. 实时信号
范围: [SIGRTMIN, SIGRTMAX]
不丢失排队,排队的多少查看ulimit -a
二、线程
1. 线程的概念
一个正在运行的函数
posix 线程是一套标准,而不是实现
openmp线程
线程标识:pthread_t
pthread_equal();
pthread_self(); -- obtain ID of the calling thread.
2. 线程的创建
pthread_create();
线程的调度取决于调度器策略
线程的终止
3种方式:
1)线程从启动例程返回,返回值就是线程的退出码
2)线程可以被同一进程中的其他线程取消
3)线程调用pthread_exit()函数
pthread_join() -- join with a terminated thread
栈的清理
pthread_cleanup_push();
pthread_cleanup_pop();
线程的取消选项
线程取消: pthread_cancel();
取消有2种状态: 允许和不允许
允许取消又分为:异步cancel,推迟cancel(默认),推迟至cancel点在响应。
cancel点:posix定义的cancel点,都是可能引发阻塞的系统调用。
pthread_setcancelstate(): 设置是否允许取消
pthread_setcanceltype(): 设置取消方式
pthread_testcancel(): 本函数什么都不做,就是一个取消点。
线程分离:
pthread_detach();
3. 线程的同步
互斥量:
pthread_mutex_t
pthread_mutex_init();
pthread_mutex_destroy();
pthread_mutex_lock();
pthread_mutex_trylock();
pthread_mutex_unlock();
pthread_once(); // 只执行一次
条件变量:
pthread_cond_t
pthread_cond_init();
pthread_cond_destroy();
pthread_cond_broadcast();
pthread_cond_signal();
pthread_cond_wait(); -- 解锁等待 被通知后抢锁
pthread_cond_timedwait();
信号量:
多写锁:读锁 ---> 共享锁 写锁 ---> 互斥锁
4. 线程属性
pthread_attr_t
pthread_attr_init();
pthread_attr_destroy();
pthread_attr_setstacksize();
见 man pthread_attr_init 的see also
线程同步的属性
互斥量属性:
pthread_mutexattr_init();
pthread_mutexattr_destroy();
pthread_mutexattr_setpshared();
pthread_mutexattr_getpshared();
clone();
pthread_mutexattr_gettype();
pthread_mutexattr_settype();
条件变量:
pthread_condattr_init();
pthread_condattr_destroy();
读写锁属性:
5. 重入
多线程中的IO
线程与信号
pthread_sigmask();
sigwait();
pthread_kill();
线程与fork
Part 6: Advanced IO
非阻塞IO – 阻塞IO
补充:有限状态机编程
1. 非阻塞IO
简单流程:自然流程是结构化的
复杂流程:自然流程不是结构化的
2. IO 多路转接
select(); --- 古老
以事件(读,写,异常)为单位,来组织文件描述符
缺陷:监视现场和监视结果是放在同一空间,只要select 有返回,除了你感兴趣的事件,
其他的集合都清空,需要重新布置监视现场。监视的事件太单一。
void FD_CLR(int fd, fd_set *set); ---> 删除
int FD_ISSET(int fd, fd_set *set); ---> 测试
void FD_SET(int fd, fd_set *set); ---> 添加
void FD_ZERO(fd_set *set); ---> 清空
poll(); --- 可移植,wait for some events on a fd.
以文件描述符为单位,来组织事件
epoll(); --- linux 方言
epoll_create();
epoll_ctl();
epoll_wait();
3. 其他读写函数
readv();
writev();
4. 存储映射IO
mmap(); ---> 映射
munmap(); ---> 解除映射
5. 文件锁
fcntl()
lockf()
flock()
Part 7: IPC
1.管道
内核提供,单工(一端为读,一端为写),自同步机制
匿名管道
pipe()
命名管道
mkfifo()
2. XSI -> SysV
IPC -> Inter-Process Communication
主动端:先发包的一方
被动端:先发包的一方(先运行)
key:ftok
Message Queues
Shared Memory Segments
Semaphore Arrays
以上创建方法都是:xxxget xxxop xxxctl for exmaple:man msgget msgop msgctl semget
semop semctl man shemget ...
3. 网络套接字socket
讨论:跨主机的传输要注意的问题
1 字节序问题:
大端模式:就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。
小端模式:就是低字节排放在内存的低地址端,高位字节排放在内存的高地址端。
主机字节序:host
网络字节序:network
解决:_to__: htons, htols, ntohs, ntohs


2 对齐:
1
2
3
4
5
6
struct
{
int i;
float f;
char ch;
}
解决:不对齐(让编译器不对齐)
3 类型长度问题:
int
char
解决:int32_t, uint32_t, int64_t int8_t uint8_t
Socket 是什么?
报式套接字:
被动端:(先运行)
1 取得socket
2 给socket 绑定地址(本地地址、端口)
3 收/发 消息
4 关闭socket
主动端:
1 取得socket
2 给socket 绑定地址(可省略,系统会自动分配一个端口)
3 发/收 消息
4 关闭socket
UDP 包的推荐长度是512byte, 报头长度为8byte.
socket()
bind()
sendto()
recvfrom()
inet_pton()
inet_ntop()
setsockopt()
getsockopt()
多点通讯:广播(全网广播,子网广播), 多播/组播
流式套接子:
C 端(主动端)
1 获得socket
2 给socket 绑定地址(可省略)
3 发送连接
4 收/发消息
5 关闭
S 端(被动端)
1 获得socket
2 给socket 绑定地址
3 将socket 置为监听模式
4 接受链接
5 收/发消息
6 关闭