在1981年之前,计算机是大型企业和政府部门才能使用的昂贵设备,IBM公司在1981年推出个人计算机IBM PC,从此个人计算机得以发展。当时大型机上面跑的是UNix系统,但是unix收费昂贵且不开源,为了在个人计算机上使用操作系统,后面出现了Minix,再后来出现了Linux。
对Linux的发展起到重要帮助的有:Unix操作系统,minix操作系统,GNU计划,POSIX标准,Internet网络。posxi标准是IEEE和ISO\IEC为Unix制定的标准,但是制定的时候,linux刚刚诞生,因此linux系统的接口与Posix完全兼容。
Linux系统分为内核空间和用户空间,内核空间由5个子系统组成:
①进程调度 ②内存管理 ③虚拟文件系统 ④网络接口 ⑤进程间通信。
一、shell命令
1.普通用户和超级用户视图
su: 进入超级用户,需要输入root密码
sudo passwd root :设置root用户密码
exit: 退回普通用户
2.文件系统
fdisk -l :查看当前磁盘的情况
ls -li hello.c:可以查看hello.c文件索引号
ln hello.c hello2.c:创建一个硬链接,hello.c和hello2.c使用同一个索引号,改变一个hello.c中的内容hello2.c的内容也会改变。但是删除hello.c,hello2.c不会被删除。只有文件才能创建硬链接,目录不能。但是目录可以使用ln-s创建软链接。
3.查看进程树pstree。
二、进程调度scheding
1.定义:进程调度是指系统对进程的多种状态之间的转换策略。Linux下的进程调度策略有三种:
①SHCHED_OTHETR ②SCHED_FIFO ③SCHED_RR
a.SHCHED_OTHETR :普通进程的时间片轮转调度策略,这种策略中,系统给所以运行状态的进程分配时间片,在当前进程的时间片用完之后,系统从剩下的进程中选择优先级高的进程运行。
b.SCHED_FIFO : 是针对实时性要求高但是运行时间短的进程,这种策略中系统按照进入队列的先后顺序进行进程的调度,在没有高优先级进程中断和阻塞的情况下,会一直运行。
c.SCHED_RR: 是针对实时性要求高且运行时间长的进程,与SHCHED_OTHETR 的策略类似,只不过RR进程的优先级高很多,系统分配给RR进程时间片,然后轮询运行这些进程,将时间片用完的进程放入队列的末尾。
三、内存管理MMU
内存管理是多个进程之间的内存共享策略,Linux系统中的内存是指虚拟内存,每个进程拥有相同的内存空间,通常虚拟内存是物理内存的两倍。
四、虚拟文件系统VRF
在Linux下支持多种文件系统,如ext、ext2、ext3、minix等等,目前常用的是ext2和ext3,ext2文件系统用于固定文件系统和可活动文件系统,是ext系统的扩展,ext3文件系统是在ext2上增加日志功能扩展后的扩展,兼容ext2,可以互相转换。
unix下一切皆文件,在linux下对磁盘进行操作的工具是fdisk,与windows下面的fdisk功能类似,但是命令格式不同,通过fdisk -l可以查看当前磁盘的情况。
a.文件分类:
①普通文件: 这种文件的特性是数据在存储设备上,内核提供对数据的抽象访问,此文件为一种字节流,访问接口完全独立于磁盘上的存储数据。例如C文件,可执行文件,目录等。
操作:对文件进行打开,读出数据,写入数据,关闭,删除。
②字符设备文件c:是一种能够像文件一样能够被访问的设备,例如控制台,串口
设备文件都有三个属性:①设备类型(字符设备c,块设备b)②主设备号 ③次设备号
③块设备文件b:与普通文件的区别是操作系统对数据的访问格式会重新设计,例如磁盘。
④socket文件:是为了实现网络通信的一种文件,对网络的访问可以通过文件描述符的抽象实现,访问与普通文件类似。
文件的两个属性:索引节点inode和块block,将一个文件比喻成一本书的话,inode相当于书的目录,block相当于书的内容。inode在linux系统中是唯一的。命令ls -li hello.c可以查看hello.c的索引号。
Linux文件系统用一组通用对象表示:
①超级块(superblock)②节点索引(inode)③目录结构(dentry) ④文件(file)
b.文件描述符:
Linux用文件描述符表示作为唯一识别一个文件的ID号,文件描述符是一个int的整数。文件描述符的取值范围为0---Open_Max,所以打开了文件后需要调用close()函数释放。如果打开的文件数量超过了Open_Max,则会造成打开失败。经过测试在ubuntu上Open_Max=1023,最多从3-1023可用
文件描述符只在一个进程中有效,因此用一个描述符在不同进程之间,可能描述的是不同的文件。
Linux下有三个已经分配了的文件描述符,标准输入stdin=0,标准输出stdout=1,标准错误stderr=2
因此第一个被打开的文件的文件描述符是3。
c.常用文件操作函数
1.打开文件open
int open(const char *pathname,int flags,mode_t mode);
打开成功则返回整形文件描述符fd,失败返回-1。
flags:用于打开后运行对文件操作的方式,只读,只写,可读可写,是在宏定义号了的。 只读O_RDONLY=0,只写O_WRONLY=1,读写O_RDWR=2。
mode:表示用户、组用户、其他用户对文件的读写权限,可以省略。
2.关闭文件close
int close(int f);
关闭文件描述符后,此文件描述符不在指向任何文件,因此此文件描述符可以再次使用,close调用成功返回0,失败返回-1,
3.读文件内容
ssize_t read(int fd, void *buff, size_t count);
执行成功返回实际读取到的字节数,可能会小于请求字节数count,失败返回-1,如果读到文件末尾返回0。
ssize_t:可能是long,int,表示实际读取到的字节数。
形参fd:表示通常是open().creat()返回的值。
形参buff:指向缓冲区的起始地址,读入的数据保持在这个缓冲区中。
形参count:表示请求读取的字节数。count需要小于buff的大小,否者会产生溢出。
4.向文件写内容
ssize_t write(int fd, void *buff, size_t count);
向文件描述符fd写入count字节数的数据,数据来源于buff指针指向的数据。
写操作并不能保证将数据成功的将数据写入磁盘中,这在异步操作中经常出现,write函数通常将数据写入缓冲区,在合适的实际由系统写入实际的设备,可以调用fsync函数,显示将输入写入设备。
5.文件偏移函数
off _t lseek(int fildes,off_t offset ,int whence)
offset: 偏移量 whence: 来源
调用成功,则返回新的文件偏移量的值,失败则返回-1,由于offset可以为负值,所以判断是否调用成功,可以使用是否等于-1来判断,而不是小于0来判断。
6.获取文件状态的函数
int stat (const char *path, struct stat *buff);
int fstat(int filedes, struct stat *buff);
int lstat(const char *path, struct stat *buff);
函数的第一个参数是文件描述符或者文件的路径,buff为指向struct stat的指针,获得的状态从这个参数中传回。调用成功返回0,失败返回-1。
7.内存映射函数
void *mmap(void *start, size_t length, int prot, int flags, int fd off_t offset);
函数功能:是将文件或者设备空间映射到内存中去,因此在磁盘上存取文件的操作转换为内存上存取文件的操作,由于内存比磁盘快,因此提高了读写速度。
参数说明:start通常为NULL,由系统自己决定映射到什么地址。length表示被映射数据的长度,
port表示映射区保护方式,flags用于设定映射对象的类型、选项、和是否可以对映射对象进行读写等。port和flags均为组合值。fd表示文件的文件描述符,表示要映射到内存中的文件,offset表示开始于offset大小为length的区域。
int munmap(void *start, size_t lenght);
函数功能:取消mmap函数的映射关系,start为mmap函数成功后返回的值,即内存的地址,length为映射的长度。
8.文件属性函数fcntl()
int fcntl(int fd, int cmd)
int fcntl(int fd, int cmd, long arg)
int fcntl(int fd, int cmd, struct flock *lock);
函数fcntl向已经打开的文件fd发送命令,更改其属性。
9.文件输入输出函数ioctl()
int ioctl(int d, int request, ......)
ioctl像其他函数一样,打开文件,发送命令,查询结果,ioctl函数像一个杂货铺一样,对设备的控制通常都是通过这个函数来实现的。对设备的具体操作方式,由设备的驱动程序决定。
五、网络接口
网络接口是为了物理设备通信而产生的,网络接口包括驱动程序和网络协议,驱动程序是对硬件设备的驱动,网络协议是网络传输的通信标准。所以目前的网络设备几乎都有驱动程序。
六、进程间通信
Linux支持多进程,进程之间需要通信,Linux的进程间通信是从Unix继承过来的,Linux下的进程间通信主要有:①管道pipe ②信号signal ③消息队列queque ④共享内存 ⑤套接字socket
①半双工管道:和RX和TX串口通信类似,都是半双工通信,A---内核——B
特点:具有阻塞性和原子性
函数:
①pipe:创建管道
②命令管道FIFO:和半双工管道的在IO操作上是一样的,只是FIFO需要调用一个open函数。
③ 消息队列:消息是内核地址空间中的内部链表,消息顺序的发送到消息队列中去,并以几种不同方式从队列中获取,每个消息队列可以用IPC标识符唯一的进行标识。
④信号量:是一种计数器,用来控制多个进程共享的资源所进行的访问,通常用做锁lock/unlock机制,典型模型是生产者和消费者模型。
函数:①semget:新建信号量函数
②semop:信号量操作函数
③semctl: 信号量控制函数
⑤共享内存:是多个进程之间共享内存区域的的通信方式,是进程通过对内存段进行映射的方实现内存共享的。这是IPC最快捷的方式,因为没有中间过程,多个进程的共享内存是同一块物理空间,仅仅是地址不同而已,因此不需要复制,就可以直接操作此段空间。
函数:①shmget:创建共享内存函数
②shmat:获得共享内存地址的函数
③shmdt:删除共享内存的函数
④shmctl:共享内存控制函数
⑥信号:信号机制是UNIX中最古老的通信方式之一,它作用于在多个进程之间传递异步信号,信号可以由各种中断产生,shell也可以使用信号将作业控制命令传递给它的子进程。
七、常识概念
1.GNU通用许可证(简称GPL),是由自由软件基金会发行的用于计算机软件的一种许可制度。
2.Linux的文件结构:是以/为根的树结构,每增加一个为文件,就将其加入到这个树中来。
3.gcc编译器四大步骤:①预编译 ②编译和优化 ③汇编 ④链接
4.makefile文件简绍: 当项目有多个文件时,gcc显得不方便,gcc对单个文件方便,借助Linux下的make工具,去解释makefile文件。
5.应用程序、进程、线程
应用程序:是源程序经过编译后的可执行程序,是存放在磁盘上的,还没有运行。
进程:从用户的角度看是应用程序的执行过程。从操作系统来看是操作系统分配内存、cpu时间片等资源的最小单位,是为正在运行的程序提供运行环境。
线程:是为了节约资源可以在同一个进程中共享资源的执行单位。
进程和线程的区别:
进程是操作系统进行资源分配的基本单位,拥有完整的虚拟空间。线程操作系统只分配cpu资源,其余内存等资源需要共享。多线程之间的共享方式比多进程之间的共享方式多。进程有进程控制表PCB,系统通过PCB对进程进行调度,线程有线程控制表TCB,系统通过TCB对进程进行调度,但是TCB所表示的状态比PCB少很多。
6.进程号:操作系统为每一个进程分配一个进程号,用于唯一标识一个进程,称为PID,类型为pid_t。
7.线程:和进程相比,线程由三点优势:①系统资源消耗低,②速度快,③线程间数据共享比进程容易得多。linux下的多线程遵循POSIX标准,叫做pthread,编写linux下的线程需要包含头文件pthread.h,在生成可执行文件的时候,需要链接库libpthread.或者libpthread.so.
函数:①pthread_create:创建线程
②pthread_join:等待一个线程运行的结束
③pthread_exit:结束线程
相关概念:①线程的属性结构
②线程的优先级
③线程的绑定状态
④线程的分离状态
⑤线程间的互斥
线程中使用信号量:函数①sem_init:初始化一个信号量
②sem_post:增加信号量的值,每次增加1,当有线程等待这个信号的时候,等待的线程将返回。
③sem_wait:减少信号量的值,如果信号量的值为0,则线程会一直阻塞到信号量的值大于0为止。
④sem_destroy:线程信号量销毁函数。
8.对程序、进程、线程的总结:程序和进程之间的区分在于程序是静态的,进程和线程的动态的。线程是轻量级的进程。进程的产生和消亡对操作系统来说,就是占用资源和释放资源。LInux进程中没有POSXI规定的挂起,恢复运行等机制。
八、干活工具
1.编辑器:VIM是vi的扩展,vi是unix下最通用的文本编辑器。
2.编译器:gcc\g++:c/c++语言编译器,输入源文件,输出可执行文件.
支持交叉编译。www.gun.org见详情
3.调试器:gdb,用于调试c和c++程序
4.构建大项目时libtools和cmake:
九、进程操作
linux系统进程图是一个树结构,所有进程有一个共同的祖先init进程,这是树结构的根。其余的进程是父子,兄弟,堂兄弟的关系。新的进程不是被全新的创建,通常是从一个原有的进程进行复制或者克隆。可以在终端中使用pstree查看进程树。
linux下对进程的操作方式主要有①产生进程 ②终止进程 ③进程间通信 ④进程间数据同步
①产生进程:可以调用函数fork()、system()、exec()创建进程。
a.获取进程号函数
getpid(): 获取当前进程的进程号。
getppid():获取当前进程的父进程的ID号
b.①进程函数函数fork
pid_t fork(void): 以父进程为蓝本复制一个进程,父进程与子进程ID号不同,父进程与子进程只有内存不同,其余共享。fork函数是执行一次返回两次,父进程中返回子进程的ID号,在子进程中返回0;
②int system(cosnt chat *command)
system调用/bin/sh-c command 执行特定的的命令,阻塞当前进程直到command命令执行完毕。
执行system函数时,会调用fork、execve、waitpid函数,其中任一个调用失败,将导致system函数调用失败。失败返回-1,当sh不能执行的时候返回127,成功时返回进程状态值。
③exec函数族
extern char **environ;
int execl(const char *path, const char *arg, ..);
int execlp(const char *file, const *arg, ...);
int execle(const char *path, const char *arg, ..char *const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(cost char *file, char *cosnt argv[]);
六个函数,只有execve函数是真正的被系统调用,其余五个都是在其基础上经过包装的库函数。
九、网络编程基础
1.TCP/IP协议:应用层协议HTTP:用于Web访问、FTP:用于文件传输协议、Telnet:用于远程主机的登录。这三种协议都是基于TCP协议的。NFS:是linux上经常使用的一种协议,用于主机之间共享文件,由于NFS协议是基于UDP协议的,所以速度快很多,NFS协议在嵌入式设备开发的时候进程使用,用于设备和主机之间共享文件系统。