一.文件
1.常见的API
打开:open 读/写:read/write 光标定位:lseek 关闭:close
Flag:
O_RDONLY 只读打开 O_WRONLY 只写打开 O_RDWR 可读可写打开
当我们附上权限后,打开文件只能按照这种权限操作
以上三个常数中应当只指定一个,打开的文件就只能按照这种操作。
O_CREAT:若文件不存在就创建他,使用此选项时,需要同时说明参数的第三个mode,用其说明该新文件的存取许可权限。
O_EXCL: 如果同时指定了O_CREAT,而文件已存在,则出错。
O_APPEND :每次写时都要加到文件的尾端。
O_TRUNC : 属性去打开文件时,如果这个文件本来是有内容的,而且为只读或者只写成功打开,则其长度截短为0。
Mode:一定是在flag中使用了O_CREAT标志,mode记录带创建的文件的访问标志。
open
打开文件失败会返回-1,我们可以创建这个文件
write
注:用strlen比较好,用sizeof 可能写不全
read
注:在write后,光标停在了末端,可能读不到内容,此时有两种方案解决。1.在write完之后关闭文件重新打开。2.用lseek将光标移到开头。
lseek
2.文件原理简述
0:标志输入 1:标准输出 2:标准错误
静态文件:存在磁盘的文件
动态文件:open静态文件后,会在Linux内核产生结构体,记录buff等,称为动态文件
3.实现cp指令小练习
源文件 src.c 目标文件 des.c
思路:
a.打开src.c
b.读src.c到buff
c.打开/创建 des.c
d.将buff 写入到 des.c
e.close 两个文件
4.open与fopen的区别
fgetc fputc feof
mode 打开模式
r 只读方式打开文本文件
rb 只读方式打开二进制文本文件
w 只写方式打开文本文件
wb 只写方式打开二进制文本文件
a 追加方式打开文本文件
ab 追加方式打二进制开文本文件
r+ 可读可写打开
rb+
w+ 可读可写创建
wb+
a+ 可读可写追加打开
ab+
二.进程
1.什么是程序,什么是进程,有什么区别?
答:程序是静态的概念,如gcc xxx.c -o pro,这个 pro叫程序。
而进程是程序的一次运行活动,相当于程序跑起来,系统就多了一个进程。
2.如何查看系统有哪些进程?
答:a.用ps指令,配合grep查看(ps -aux |grep ) b.用top指令查看(top)
3.什么是进程标识符?
答:每一个进程都有一个非负整数表示唯一的ID,叫做pid(可用 getpid()获得父进程)
pid=0,称为交换进程(s'wapper)
作用——进程调度
pid=1,init进程
作用——系统初始化
4.c程序的存储空间如何分配?
5.使用fork创建一个进程
pid_t fork(void);
如果是父进程,则会返回新子进程的进程ID。如果是子进程 则会返回0。失败返回-1.
vfork也可以创建进程,yufork的区别
a.vfork 直接使用父进程存储空间,不拷贝。
b.vfork保证子进程先运行,当子进程调用exit退出后,父进程才执行。
6.进程退出
正常退出
a.main 调用 return
b.进程调用exit(),标准c库
c.进程调用_exit 或者_Exit,标准c库
d.进程最后一个线程返回
e.最后一个线程调用pthread_exit
异常退出
a.调用abort
b.当进程收到某个信号,比如ctrl+c
c.最后一个进程对取消进程做出响应
7.父进程等待子进程退出
a.父进程等待子进程退出并收集子进程退出状态
b.父进程等待子进程退出不被收集,变成死进程
8.exec族函数
ht三
tps:/
三.进程间的通信
进程中的五种通信方式介绍_mulinsen77的博客-CSDN博客_进程中的通信方式
进程间通信(InterProcess Communication)是指在不同的进程之间传播或者交换信息。
IPC的方式通常有管道(无名和有名)、消息队列、共享存储、信号量、Socket以及Streams等。
其中Socket和Streams支持不同主机之间的两个进程IPC。
依赖于内核,无法实现多机通讯
1.管道
特点:
- 半双工通信,即数据流只能在一个方向上流动
- 父进程和子进程之前的通信
- 特殊的一种文件,不属于任何文件系统,只存在于在内存
- 管道中的数据读走就没有了
当一个管道建立时,它会创建两个文件描述符:fd[0]为读而打开,fd[1]为写而打开
2.FIFO
特点
(1)可在无关进程间通信
(2)关联路径名,是一种存在于文件系统中的设备文件
创建一个管道mkfifo
命名管道的打开规则
(1)只读且阻塞方式
open(const char *pathname, O_RDONLY);
(2)只读且非阻塞方式
open(const char *pathname, O_RDONLY | O_NONBLOCK);
(3)只写且阻塞方式
open(const char *pathname, O_WRONLY);
(4)只写且非阻塞方式
open(const char *pathname, O_WRONLY | O_NONBLOCK);
3.消息队列
特点:
1.消息队列是面向记录的,其中的消息队列有特定的格式和特定的优先级
2.消息队列独立于接受和发送进程,进程终止时,消息队列及其内容不会被删除
3.消息队列可以实现的消息的随机查询,消息不一定要以先进先出的顺序读取,也可以按照消息的类型读取。
相关函数
ftok——系统IPC键值的格式转换函数
key_t ftok( const char * fname, int id )
fname就是你指定的文件名(已经存在的文件名),一般使用当前目录,如:
key_t key;
key = ftok(".", 1); 这样就是将fname设为当前目录
如指定文件的索引节点号为65538,换算成16进制为0x010002,而你指定的ID值为38,换算成16进制为0x26,则最后的key_t返回值为0x26010002。
4.共享内存
特点
共享内存是最快的一种 IPC,因为进程是直接对内存进行存取。
因为多个进程可以同时操作,所以需要进行同步。
信号量+共享内存通常结合在一起使用,信号量用来同步对共享内存的访问。
ipcs -m 查看系统中有哪些共享内存
ipcrm -m id 删除系统中的共享内存
5.信号
信号的名字和编号:
每个信号都有一个名字和编号,这些名字都以“SIG”开头,例如“SIGIO ”、“SIGCHLD”等等。
信号定义在signal.h
头文件中,信号名都定义为正整数。
具体的信号名称可以使用kill -l
来查看信号的名字以及序号,信号是从1开始编号的,不存在0号信号。kill对于信号0又特殊的应用。
kill -l 查看系统中的信号
信号的处理有三种方法,分别是:忽略、捕捉和默认动作
我们已经成功完成了信号的收发,那么为什么会有高级版出现呢?其实之前的信号存在一个问题就是,虽然发送和接收到了信号,可是总感觉少些什么,既然都已经把信号发送过去了,为何不能再携带一些数据呢?
正是如此,我们需要另外的函数来通过信号传递的过程中,携带一些数据。咱么先来看看发送的函数吧
#include <signal.h>
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
struct sigaction {
void (*sa_handler)(int); //信号处理程序,不接受额外数据,SIG_IGN 为忽略,SIG_DFL 为默认动作
void (*sa_sigaction)(int, siginfo_t *, void *); //信号处理程序,能够接受额外数据和sigqueue配合使用
sigset_t sa_mask;//阻塞关键字的信号集,可以再调用捕捉函数之前,把信号添加到信号阻塞字,信号捕捉函数返回之前恢复为原先的值。
int sa_flags;//影响信号的行为SA_SIGINFO表示能够接受数据
};
//回调函数句柄sa_handler、sa_sigaction只能任选其一
6.信号量
1、信号量本质上是一个计数器(不设置全局变量是因为进程间是相互独立的,而这不一定能看到,看到也不能保证++引用计数为原子操作),用于多进程对共享数据对象的读取,它和管道有所不同,它不以传送数据为主要目的,它主要是用来保护共享资源(信号量也属于临界资源),使得资源在一个时刻只有一个进程独享。
2、特点
-
信号量用于进程间同步,若要在进程间传递数据需要结合共享内存。
-
信号量基于操作系统的 PV 操作,程序对信号量的操作都是原子操作。
-
每次对信号量的 PV 操作不仅限于对信号量值加 1 或减 1,而且可以加减任意正整数。
-
支持信号量组。
四.线程
进程——资源分配的最小单位,线程——程序执行的最小单位
但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。
如果用进程会涉及到进程间的通信,比较麻烦。
使用线程的理由:
a.使用多线程的理由之一是和进程相比,它是一种非常"节俭"的多任务操作方式。启动一个新的进程必须分配给它独立的地址空间,建立众多的数据表来维护它的代码段、堆栈段和数据段,而运行于一个进程中的多个线程,它们彼此之间使用相同的地址空间,共享大部分数据,启动一个线程所花费的空间远远小于启动一个进程所花费的空间,而且,线程间彼此切换所需的时间也远远小于进程间切换所需要的时间。
b.线程间方便的通信机制。进程需要用进程间的通信进行数据的传递,这种方式不仅费时,而且很不方便。线程则不然,由于同一进程下的线程之间共享数据空间,所以一个线程的数据可以直接为其它线程所用,这不仅快捷,而且方便。
除了以上所说的优点外,不和进程比较,多线程程序作为一种多任务、并发的工作方式,当然有以下的优点:
- 提高应用程序响应。这对图形界面的程序尤其有意义,当一个操作耗时很长时,整个系统都会等待这个操作,此时程序不会响应键盘、鼠标、菜单的操作,而使用多线程技术,将耗时长的操作(time consuming)置于一个新的线程,可以避免这种尴尬的情况。
- 使多CPU系统更加有效。操作系统会保证当线程数不大于CPU数目时,不同的线程运行于不同的CPU上。
- 改善程序结构。一个既长又复杂的进程可以考虑分为多个线程,成为几个独立或半独立的运行部分,这样的程序会利于理解和修改。
1.线程相关api
线程的创建
线程的退出
单个线程可以通过以下三种方式退出,在不终止整个进程的情况下停止它的控制流:
1)线程只是从启动例程中返回,返回值是线程的退出码。
2)线程可以被同一进程中的其他线程取消。
3)线程调用pthread_exit:
线程的等待
线程的脱离
线程ID获取比较
2.互斥锁相关api
互斥量(mutex)从本质上来说是一把锁,在访问共享资源前对互斥量进行加锁,在访问完成后释放互斥量上的锁。对互斥量进行加锁后,任何其他试图再次对互斥量加锁的线程将会被阻塞直到当前线程释放该互斥锁。如果释放互斥锁时有多个线程阻塞,所有在该互斥锁上的阻塞线程都会变成可运行状态,第一个变为可运行状态的线程可以对互斥量加锁,其他线程将会看到互斥锁依然被锁住,只能回去等待它重新变为可用。在这种方式下,每次只有一个线程可以向前运行。
注:加锁与解锁穿的参数应该是指针
3.什么情况下会造成死锁
有两把锁,当线程A获得一把锁的时候想获得另一把锁,线程B有A想要的那把锁,同时想要获得线程A手里的锁。这样 线程A和线程B 都想获得对方手里的那把锁。
4.条件
注:用宏为静态初始化
五.网络编程
1.字节序
2.socket
补充:socket tcp http
最全的socket,tcp,http三者之间的区别和原理_y15201653575的博客-CSDN博客_socket通信和tcp通信的区别
深入浅出-网络七层模型_z_anonymou的博客-CSDN博客
http 应用层
socket 会话层
TCP、UDP 传输层
IP 网络层
Linux进阶之TCP三次握手四次挥手_m0_52467164的博客-CSDN博客
/wwwnblogs.com/NickyYe/p/5497659.html
O_
Flags:
O_RDONLY 只读打开 O_WRONLY 只写打开 O_RDWR 可读可写打开
Flags:1111
O_RONLY 只读打开 O_WRONLY 只写打开 O_RDWR 可读可写打开