国嵌linux视频课件整理(1)

来源:互联网 发布:数据库软件工程师 编辑:程序博客网 时间:2024/05/19 18:11

Linux系统管理

Linux与Linux之间通过NFS(network file system)实现共享;
windows与windows之间通过共享目录实现共享;
Linux与windows之间通过Samba实现共享。
Wireshark抓包软件,分析网络协议。
shell编程:
1)#!/bin/bash ,符号#!用来指定该脚本文件的解析程序。
2)# 开头表示该行是注释。
3)所有变量都是由字符串组成,并且不需要预先对变量进行声明。使用变量需在变量名前$。有时候变量名很容易与其他文字混淆,这时需要用{}将变量名括起来。
4)默认变量:
$#:传入脚本的命令行参数个数
$*:所有命令行参数值,在各个参数之间留有空格
$0:命令本身(shell文件名)
$1:第一个命令行参数
$2:第二个命令行参数
5)局部变量,在变量首次赋值时加local可以声明一个局部变量。
6)变量注意事项:
变量赋值时“=”号左右两边都不能空格
语句结尾不加“;”
7)if语句
if [ expression ]
then
#code block
fi 
if [ expression ]
then
#code block
else
#code block
fi
比较操作 整数 字符串
相同 -eq =
不同 -ne !=
大于 -gt >
小于 -lt <
小于等于 -le 
大于等于 -ge
为空 -z
不为空 -n 
注意:
在“[”和“]”符号的左右都留有空格
“=”左右都有空格
判断:
-e 文件已经存在
-f 文件是普通文件
-s 文件大小不为0
-d 文件是一个目录
-r 文件对当前用户可以读取
-w 文件对当前用户可以写入
-x 文件对当前用户可以执行
8)for循环和while循环
for var in [list]
do
# code
done
注意:
for所在那行变量是没有加“$”的,而在循环体内,变量是要加“$”的
list如果用“”括起来是被当作一个值赋给var
while [ condition ]
do
#code
done
until [ condition ] 条件为假时执行
do
#code
done
9)case语句
case "$var" in
condition1)
;;
condition2)

;;
*)
#default statments;;
esac

gcc学习

Linux系统下的gcc(GNU C Compiler)是GNU推出的功能强大、性
能优越的多平台编译器,是GNU的代表作之一。gcc可以在多种硬体平台上编译出可执行程序,其执行效率与一般的编译器相比平均效率要高20%~30%。
GCC编译器能将C,C++语言源程序,汇编程序编译,链接成可执行文件。Linux通过属性来决定文件的可执行性。
GCC编译4个阶段:
预处理(pre-processing),编译(compling),汇编(assembing),
链接(linking)
处理的输入文件类别:.c.a.C.h.i.ii.o.s.S
gcc最基本的用法是:
gcc [options] [filename]
options:
-o output_filename:指定输出的可执行文件名称。
-c:只编译,不连接成为可执行文件,编译器只是由输入的.c等源代码文件生成.o为后缀的目标文件。
-g:产生调试工具(GNU的gdb)所必要的符号信息,要想对编译出的程序进行调试,就必须加入这个选项。
-O:对程序进行优化编译、链接,采用这个选项,整个源代码会在编译、连接过程中进行优化处理,这样产生的可执行文件的执行效率可以提高,但是,编译、连接的速度就相应地要慢一些。
-O2,比-O更好的优化编译、连接,当然整个编译、连接过程会更慢。
-I dirname: 将dirname所指出的目录加入到程序头文件目录列表
中。C程序中的头文件包含两种情况∶
#include <A.h>和#include “B.h”对于<>,预处理程序cpp在系统预设的头文件目录(如/usr/include)中搜寻相应的文件;而对于””,cpp在当前目录中搜寻头文件。这个选项的作用是告诉cpp,如果在当前目录
中没有找到需要的文件,就到指定的dirname目录中去寻找。
-L dirname:将dirname所指出的目录加入到库文件的目录列表中。在默认状态下,连接程序ld在系统的预设路径中(如/usr/lib)寻找所需要的库文件,这个选项告诉连接程序,首先到-L指定的目录中去寻找,然后再到系统预设路径中寻找。
-l name:在连接时,装载名字为“libname.a”的函数库,该函数库位于
系统预设的目录或者由-L选项确定的目录下。例如,-l m表示连接名为
“libm.a”的数学函数库。
-static:静态链接库文件 例:gcc –static hello.c -o hello
库有动态与静态两种,动态通常用.so为后缀,静态用.a为后缀。例如:libhello.so libhello.a。当使用静态库时,连接器找出程序所需的函数,然后将它们拷贝到可执行文件,一旦连接成功,静态程序库也就不再需要了。然 而,对动态库而言,就不是这样,动态库会在执行程序内留下一个标记‘指明当程序执行时,首先必须载入这个库。由于动态库节省空间,linux下进行连接的缺省操作是首先连接动态库。
-Wall:生成所有警告信息
-w:不生成任何警告信息
-DMACRO: 定义 MACRO 宏,等效于在程序中使用#define MACRO

GDB程序调试

GDB是GNU发布的一款功能强大的程序调试工具。GDB主要完成下面三个方面的功能:

1、启动被调试程序。

2、让被调试的程序在指定的位置停住。

3、当程序被停住时,可以检查程序状态

(如变量值)。

GDB调试的一般步骤:

1.编译生成可执行文件:

gcc -g tst.c -o tst

2.启动GDB

gdb tst

3. 在main函数处设置断点

break main

4. 运行程序

run

5. 单步运行

next

6. 继续运行

continue

常用GDB命令:

list(l) 查看程序

break(b) 函数名 在某函数入口处添加断点

break(b) 行号 在指定行添加断点

break(b) 文件名:行号在指定文件的指定行添加断点

break(b) 行号 if 条件当条件为真时,指定行号处断点生效,例b 5 if i=10,当i等于10时第5行断点生效

info break 查看所有设置的断点

delete 断点编号 删除断点

run(r) 开始运行程序

next(n) 单步运行程序(不进入子函数)

step(s) 单步运行程序(进入子函数)

continue(c) 继续运行程序

print(p) 变量名 查看指定变量值

finish 运行程序,直到当前函数结束

watch 变量名 对指定变量进行监控

quit(q) 退出gdb


Makefile工程管理

Linux程序员必须学会使用GNU make来构建和管理自己的软件工程。GNU 的make能够使整个软件工程的编译、链接只需要一个命令就可

以完成。

make在执行时, 需要一个命名为Makefile的文件。Makefile文件描述了整个工程的编译,连接等规则。其中包括:工程中的哪些源文件需要编译以及如何编译;需要创建那些库文件以及如何创建这些库文件、如何最后产生我们想要得可执行文件。

makefile规则:用于说明如何生成一个或多个目标文件,

规则格式如下:

targets :prerequisites

command

目标 依赖 命令

main.o : main.c

gcc –c main.c

**命令需要以【TAB】键开始**

目标:在Makefile 中,规则的顺序是很重要的,因为,Makefile中只应该有一个最终目标,其它的目标都是被这个目标所连带出来的,所以一定要让make知道你的最终目标是什么。一般来说,定义在Makefile中的目标可能会有很多,但是第一条规则中的目标将被确立为最终的目标。

文件名:make命令默认在当前目录下寻找名字为makefile或者Makefile的工程文件,当名字不为这两者之一时,可以使用如下方法指定:

make –f 文件名

伪目标:Makefile中把那些没有任何依赖只有执行动作的目标称为“伪目标”(phony targets)。

.PHONY : clean

clean :

rm –f hello main.ofunc1.o func2.o

“.PHONY” 将“clean”目标声明为伪目标。

变量的使用:obj=main.o func1.o func2.o func3.o

hello: $(obj)

gcc $(obj) -o hello

在makefile中,存在系统默认的自动化变量

$^:代表所有的依赖文件

$@:代表目标

$<:代表第一个依赖文件

Makefile中“#”字符后的内容被视作注释。

@:取消回显

hello: hello.c

@gcc hello.c –ohello


linux文件编程

Linux系统调用

系统调用-创建

int creat(const char*filename,mode_t mode)

vfilename:要创建的文件名(包含路径,缺省为当前路径)

vmode:创建模式,常见创建模式:

S_IRUSR 可读

S_IWUSR 可写

S_IXUSR 可执行

S_IRWXU 可读、写、执行

除了可以使用上述宏以外,还可以直接使用数字来表示文件的访问权限:

v可执行 -> 1

v可写 -> 2

v可读 -> 4

v上述值的和,如可写可读 -> 6

v无任何权限 -> 0

文件描述

在Linux系统中,所有打开的文件都对应一个文件描述符。文件描述符的本质是一个非负整数。当打开一个文件时,该整数由系统来分

配。文件描述符的范围是0 - OPEN_MAX 。早期的UNIX版本OPEN_MAX =19,即允许每个进程同时打开20个文件,现在很多系统则将其增加至1024。

系统调用-打开

int open(const char*pathname, int flags)

int open(const char*pathname, int flags,mode_t mode)

pathname:要打开的文件名(包含路径,缺省为当前路径)

flags:打开标志,常见的打开标志:

O_RDONLY 只读方式打开

O_WRONLY 只写方式打开

O_RDWR 读写方式打开

O_APPEND 追加方式打开

O_CREAT 创建一个文件

O_NOBLOCK 非阻塞方式打开

如果使用了O_CREATE标志,则使用的函数是:

int open(const char*pathname,int flags,mode_t mode);

这时需要指定mode来表示文件的访问权限。

当我们操作完文件以后,需要关闭文件:

int close(int fd) ,fd: 文件描述符

系统调用-读

int read(int fd,const void *buf, size_t length)

功能:从文件描述符fd所指定的文件中读取length个字节到buf所指向的缓冲区中,返回值为实际读取的字节数。

系统调用-写

int write(int fd,const void *buf, size_t length)

功能:把length个字节从buf指向的缓冲区中写到文件描述符fd所指向的文件中,返回值为实际写入的字节数。

系统调用-定位

int lseek(int fd,offset_t offset, int whence)

功能:将文件读写指针相对whence移动offset个字节。操作成功时,返回文件指针相对于文件头的位置。

whence可使用下述值:

SEEK_SET:相对文件开头

SEEK_CUR:相对文件读写指针的当前位置

SEEK_END:相对文件末尾

offset可取负值,表示向前移动。例如下述调用可将文件指针相对当前位置向前移动5个字节:

lseek(fd, -5,SEEK_CUR)

由于lseek函数的返回值为文件指针相对于文件头的位置,因此下面调用的返回值就是文件的长度:

lseek(fd, 0,SEEK_END)

系统调用-访问判断

有时我们需要判断文件是否可以进行某种操作(读,写

等),这时可以使用access函数:

int access(constchar*pathname,int mode)

pathname:文件名称

mode:要判断的访问权限。可以取以下值或者是他们的组合。R_OK:文件可读,W_OK:文件可写,X_OK:文件可执行,F_OK文件存在。

返回值:当我们测试成功时,函数返回0,否则如果一个条件不符时,返回-1。

C语言库函数

C库函数的文件操作是独立于具体的操作系统平台的,不管是在DOS、Windows、Linux还是在VxWorks中都是这些函数。

库函数-创建和打开

FILE *fopen(constchar *filename, const char *mode)

filename:打开的文件名(包含路径,缺省为当前路径)

mode:打开模式

常见打开模式:

r, rb 只读方式打开

w, wb 只写方式打开,如果文件不存在,则创建该文件

a, ab 追加方式打开,如果文件不存 在,则创建该文件

r+, r+b, rb+读写方式打开

w+, w+b, wh+ 读写方式打开,如果文件不存在,则创建该文件

a+, a+b, ab+读和追加方式打开。如果文件不存在,则创建该文件

b用于区分二进制文件和文本文件,这一点在DOS、Windows系统中是有区分的,但Linux不区分二进制文件和文本文件。

库函数-读

size_t fread(void*ptr, size_t size, size_t n, FILE *stream)

功能:从stream指向的文件中读取n个字段,每个字段为size字节,并将读取的数据放入ptr所指的字符数组中,返回实际已读取的字节数。

库函数-写

size_t fwrite (constvoid *ptr, size_t size, size_t n,FILE *stream)

功能:从缓冲区ptr所指的数组中把n个字段写到stream指向的文件中,每个字段长为size个字节,返回实际写入的字段数。

库函数-读字符

int fgetc(FILE*stream)

库函数-写字符

int fputc(int c,FILE *stream)

库函数-格式化读

fscanf(FILE *stream,char *format[,argument...])

从一个流中进行格式化输入,fscanf(stdin, "%d", &i)

库函数-格式化写

int fprintf(FILE*stream, char* format[,argument,...])

格式化输出到一个流中,printf( stream, "%d\n", i );

库函数-定位

int fseek(FILE*stream, long offset, int whence)

whence :

SEEK_SET 从文件的开始处开始搜索

SEEK_CUR 从当前位置开始搜索

SEEK_END 从文件的结束处开始搜索

路径获取

在编写程序的时候,有时候需要得到当前路径。C库函数提供了getcwd来解决这个问题。

char *getcwd(char*buffer,size_t size)

我们提供一个size大小的buffer,getcwd会把当前的路径名copy 到buffer中.如果buffer太小,函数会返回-1。

创建目录

#include<sys/stat.h>

int mkdir(char *dir, int mode)

功能:创建一个新目录。

返回值:0表示成功,-1表述出错。


linux时间编程

时间类型

CoordinatedUniversal Time(UTC):世界标准时间,也就是大家所熟知的格林威治标准时间(Greenwich Mean Time,GMT)。

Calendar Time:日历时间,是用“从一个标准时间点(如:1970年1月1日0点)到此时经过的秒数”来表示的时间。

时间获取

#include<time.h>

time_t time(time_t*tloc)

功能:获取日历时间,即从1970年1月1日0点到现在所经历的秒数。

/* typedef longtime_t */

时间转化

struct tm*gmtime(const time_t *timep)

功能:将日历时间转化为格林威治标准时间,并保存至TM结构。

struct tm*localtime(const time_t *timep)

功能:将日历时间转化为本地时间,并保存至TM结构。

时间保存

struct tm {

int tm_sec; //秒值

int tm_min;

//分钟值

int tm_hour; //小时值

int tm_mday; //本月第几日

int tm_mon;

//本年第几月

int tm_year;//tm_year + 1900 = 哪一年

int tm_wday; //本周第几日

int tm_yday; //本年第几日

int tm_isdst; //日光节约时间

};

时间显示

char *asctime(conststruct tm *tm)

功能:将tm格式的时间转化为字符串,如: Sat Jul 30 08:43:03 2005

char *ctime(consttime_t *timep)

功能:将日历时间转化为本地时间的字符串形式。

获取时间

intgettimeofday(struct timeval *tv,struct timezone *tz)

功能:获取从今日凌晨到现在的时间差,常用于计算事件耗时。

struct timeval {

int tv_sec; //秒数

int tv_usec; //微妙数

};

延时执行

unsigned intsleep(unsigned int seconds)

功能:使程序睡眠seconds秒。

void usleep(unsignedlong usec)

功能:使程序睡眠usec微秒。

进程控制

进程控制理论

定义:

进程是一个具有一定独立功能的程序的一次运行活动。

特点:

动态性

并发性

独立性

异步性

状态

进程ID

进程ID(PID):标识进程的唯一数字

父进程的ID(PPID)

启动进程的用户ID(UID)

进程互斥

进程互斥是指当有若干进程都要使用某一共享资源时,任何时刻最多允许一个

进程使用,其他要使用该资源的进程必须等待,直到占用该资源者释放了该资源

为止。

临界资源

操作系统中将一次只允许一个进程访问的资源称为临界资源。

临界区

进程中访问临界资源的那段程序代码称为临界区。为实现对临界资源的互斥访

问,应保证诸进程互斥地进入各自的临界区。

进程同步

一组并发进程按一定的顺序执行的过程称为进程间的同步。具有同步关系

的一组并发进程称为合作进程,合作进程间互相发送的信号称为消息或事件。

进程调度

概念:

按一定算法,从一组待运行的进程中选出一个来占有CPU运行。

调度方式:

• 抢占式

• 非抢占式

调度算法:

先来先服务调度算法

短进程优先调度算法

高优先级优先调度算法

时间片轮转法

死锁

多个进程因竞争资源而形成一种僵局,若无外力作用,这些进程都将永

远不能再向前推进。

进程创建

获取ID

#include<sys/types.h>

#include<unistd.h>

pid_t getpid(void) 获取本进程ID。

pid_t getppid(void) 获取父进程ID。

进程创建-fork

#include<unistd.h>

pid_t fork(void)

功能:创建子进程

fork的奇妙之处在于它被调用一次,却返回两次,它可能有三种不同的返回值:

1. 在父进程中,fork返回新创建的子进程的PID;

2. 在子进程中,fork返回0;

3. 如果出现错误,fork返回一个负值

在pid=fork()之前,只有一个进程在执行,但在这条语句执行之后,就变成两个

进程在执行了,这两个进程的共享代码段,将要执行的下一条语句都是if(pid==0)。

两个进程中,原来就存在的那个进程被称作“父进程”,新出现的那个进程被称作“子进程”,父子进程的区别在于进程标识符(PID)不同。

子进程的数据空间、堆栈空间都会从父进程得到一个拷贝,而不是共享。在子

进程中对count进行加1的操作,并没有影响到父进程中的count值,父进程中的

count值仍然为0。

进程创建-vfork

#include<sys/types.h>

#include<unistd.h>

pid_t vfork(void)

功能:创建子进程。

区别:

1. fork:子进程拷贝父进程的数据段

vfork:子进程与父进程共享数据段

2. fork:父、子进程的执行次序不确定

vfork:子进程先运行,父进程后运行

exec函数族

exec用被执行的程序替换调用它的程序。

区别:

fork创建一个新的进程,产生一个新的PID。exec启动一个新程序,替换原有的进程,因此进程的PID不会改变。

#include<unistd.h>

intexecl(const char * path,const char * arg1, ....)

参数:

path:被执行程序名(含完整路径)。

arg1 – argn: 被执行程序所需的命令行参数,含程序名。以空指针(NULL)结束。

例:execl.c

#include<unistd.h>

main()

{

execl(“/bin/ls”,”ls”,”-al”,”/etc/passwd”,(char* )0);

}

#include<unistd.h>

intexeclp(const char * path,const char * arg1, ...)

参数:

path:被执行程序名(不含路径,将从path环境变量中查找该程序)。

arg1 – argn: 被执行程序所需的命令行参数,含程序名。以空指针(NULL)结束。

例:execlp.c

#include<unistd.h>

main()

{

execlp(”ls”,”ls”,”-al”,”/etc/passwd”,(char*)0);

}

#include<unistd.h>

int execv(const char * path, char * const argv[ ])

参数:

path:被执行程序名(含完整路径)。

argv[]: 被执行程序所需的命令行参数数组。

例:execv.c

#include<unistd.h>

main()

{

char * argv[]={“ls”,”-al”,”/etc/passwd”,(char*)0};

execv(“/bin/ls”,argv);

}

#include<stdlib.h>

intsystem( const char* string )

功能:

调用fork产生子进程,由子进程来调用/bin/sh -c string来执行参数string所代表

的命令。

例:system.c

#include<stdlib.h>

void main()

{

system(“ls -al/etc/passwd”);

}

进程等待

#include<sys/types.h>

#include<sys/wait.h>

pid_t wait (int *status)

功能:阻塞该进程,直到其某个(任意)子进程退出。


进程通信

概述

为什么进程间需要通信?

1、数据传输

一个进程需要将它的数据发送给另一个进程。

2、资源共享

多个进程之间共享同样的资源。

3、通知事件

一个进程需要向另一个或一组进程发送消息,通知它们发生了某种事件。

4、进程控制

有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有操作,并能够及时知道它的状态改变。

Linux进程间通信(IPC)由以下几部分发展而来:

1、UNIX进程间通信

2、基于System V进程间通信

3、POSIX进程间通信

POSIX(PortableOperating System Interface)表示可移植操作系统接口。电气和电子工程师协会(Institute of Electrical and ElectronicsEngineers,IEEE)最初开发 POSIX 标准,是为了提高 UNIX 环境下应用程序的可移植性。然而,POSIX 并不局限于 UNIX,许多其它的操作系统,例如 DEC OpenVMS 和 Microsoft Windows,都支持 POSIX 标准。

System V,也被称为 AT&T System V,是Unix操作系统众多版本中的一支。

现在Linux使用的进程间通信方式包括:

1、管道(pipe)和有名管道(FIFO)

2、信号(signal)

3、消息队列

4、共享内存

5、信号量

6、套接字(socket)

管道通信

什么是管道?

管道是单向的、先进先出的,它把一个进程的输出和另一个进程的输入连接在一起。一个进程(写进程)在管道的尾部写入数据,另一个进程(读进程)从管道的头部读出数据。

数据被一个进程读出后,将被从管道中删除,其它读进程将不能再读到这些数据。管道提供了简单的流控制机制,进程试图读空管道时,进程将阻塞。同样,管道已经满时,进程再试图向管道写入数据,进程将阻塞。

管道创建

管道包括无名管道和有名管道两种,前者用于父进程和子进程间的通信,后者可用于运行于同一系统中的任意两个进程间的通信。

无名管道由pipe()函数创建:

int pipe(int filedis[2]);

当一个管道建立时,它会创建两个文件描述符:filedis[0] 用于读管道, filedis[1] 用于写管道。

关闭管道只需将这两个文件描述符关闭即可,可以使用普通的close函数逐个关闭。

管道读写

管道用于不同进程间通信。通常先创建一个管道,再通过fork函数创建一个子进程,该子进程会继承父进程所创建的管道。

注意事项

必须在系统调用fork( )前调用pipe( ),否则子进程将不会继承文件描述符。

命名管道(FIFO)

命名管道和无名管道基本相同,但也有不同点:无名管道只能由父子进程使用;但是通过命名管道,不相关的进程也能交换数据。

创建

#include<sys/types.h>

#include<sys/stat.h>

int mkfifo(constchar * pathname, mode_t mode)

pathname:FIFO文件名

mode:属性(见文件操作章节)

一旦创建了一个FIFO,就可用open打开它,一般的文件访问函数(close、read、write等)都可用于FIFO。

操作

当打开FIFO时,非阻塞标志(O_NONBLOCK)将对以后的读写产生如下影响:

1、没有使用O_NONBLOCK:访问要求无法满足时进程将阻塞。如试图读取空的FIFO,将导致进程阻塞。

2、使用O_NONBLOCK:访问要求无法满足时不阻塞,立刻出错返回,errno是ENXIO。