Linux系统编程学习一
第一讲 基础知识
posix标准
portale operating system interface for compputing system
对Linux发展到今天很重要
man手册
善于使用man
开发工具
Windows IDE
Linux下emacs,vi,gcc的组合
gcc选项
-c
-o
-wall
posix定义的数据类型
在头文件sys/types.h中定义
dev_t 包涵一个什么什么的宏,不明白,
uid_t,gid_t
pid_t
off_t 有符号整数,以字节为单位的偏移值,以字节为单位度量文件的大小
size_t 无符号整数,度量一个内存对象大小,字符串,数组缓冲区
只要是遵守posix标准的程序在类Linux中移植是没有任何问题的
头文件大多都是在/usr/include下,如果没有也会链接到此目录
系统调用的返回码
全局变量errno
perror(string)
strerror(errno)
错误一般返回一个负数
第二讲 进程
进程是理解文件与信号,作业控制关系访问权限以及其他大部分主题的基础
定义:进程是正在执行的程序
是整个Linux系统编程的基础
要重要掌握关键的概念和函数
内核跟踪进程的以下信息
运行的位置
访问的文件
信用状(安全机制)
当前目录
访问的内存空间
2.1 进程的属性
pid
信用状
setuid/setgid和系统守护进程
uid和gid总结
中间两方面需要对shell了解,看来学习shell的强大功能是不可避免呀
pid
基本属性pid-进程标识符和ppid-父进程,是唯一标识运行的进程,是一个正整数
pid_t getpid()
pid_t getppid()
创建进程的进程,是新进程的父进程
当一个进程退出的时候,会通知父进程,进程的退出信息会被保存
起来,保存到内核的进程表当中,到父进程请求
如果一个进程的父进程退出,子进程就成为一个孤儿进程,
都会变成init进程的一个子进程,
init的作用,收集父进程消亡的进程以及其退出状态,并通知内核
将子进程的信息从进程表中删除
例子
vi getpid.c
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main(int argc,const char **argv)
{
pid_t id=getpid();
printf("this is num %d/n",id);
return 0;
}
pid_t 是相当于一个整形的类型,专门用于pid格式
安全机制
采用unix的安全机制
etc/passwd,etc/group
int setgroups(size_t num,const gid_t *list)
int getgroups(size_t num,gid_t *list)
计算机用数字标识用户和组,并不关心真正的名字
做开发的时候,如果进程只属于一个组,想要访问不属于本组成员的时候
权限问题,补充组来解决此问题,每个进程有组组标识符,属于本组也
属于补充组,访问别的组的时候就不会出现权限问题
上面两个函数是对补充组操作的函数,要有root权限
set list指向标识符为num的数组,
get 获得进程属于补充组的列表,list指向数组,系统编程2.3讲 进程相关信息
程序参数
资源使用
建立使用限制
1,程序参数
命令行参数:传递给程序的字符串 vi n.txt ls -l
环境变量 :
在启动的时候,就对程序可用
int main(int argc,char * argv[])
这是标准C,类Linux系统中标准main的原型
argv[] 数组或指针
返回码:
0,表示成功而退出
1-127,表示出错而退出
-1~-128内核异常终止保留的
extern char *environ[] 直接访问全局变量---尽量少用
const char * getenv(const char *name)----常用
改变环境变量的函数
int putenv(const char* string)----POSIX标准
int setenv(const char* name,const char *value,int overwrite)
------BSD 标准
如:
putenv("PATH=/bin;/usr/bin")-----存在,更新
setenv("PATH","/bin:/usr/bin",1)---表示修改
2,资源使用
一个程序的使用,是由内核所决定,如堆栈,代码段等。要对内核有深入的了解
获取资源使用情况的函数
int getrusage(int who,struct rusage *usage)
who: RUSAGE_SELF
RUSAGE_CHILDREN
RUSAGE_BOTH
#include<sys/resource.h>
struct rusage{
struct timeval ru_utime;//执行用户代码的时间,包括请求的时间
struct timeval ru_stime;//内核用来执行进程请求的全部时间,不包括阻塞时间
long int ru_minflt;//进程造成的次要缺陷数
long int ru_majflt;//进程造成的主要缺陷数
long int ru_nswap;//进程的访问而从从磁盘调用内存的页面处
.........
};//用到的不多
常用的就是这前五项
这个函数返回结构体中的各个参数
3,建立使用资源限制 了解
为了防止失控的进程,类Unix,设置限制,硬限制,软限制
两个函数
int getrlimit(int resource,struct rlimit *rlim)
int setrlimit(int resource,const struct rlimit *rlim)
struc rlimit
{
long int rlim_cur;//软限制
long int rlim_max;//硬限制
}
RLIMIT_AS//进程可用内存的最大数量,堆栈,全局变量 动态内存
RLIMIT_CORE//内核生成的CORE文件的最大大小
RLIMIT_CPU//所用全部CPU时间,以秒计
RLIMIT_DATA//数据存储的最大容量,以字节计
RLIMIT_FSIZE//打开文件的最大数目
RLIMIT_MEMMLOCK//
RLIMIT_NOFILE//打开文件的最大速度
RLIMIT_NPROC//进程可以产生的最大子进程数
RLIMIT_RSS//可以随时使用的内存的最大容量
RLIMIT_STACK//堆栈存储区的最大容量
堆栈,理解,系统原理
4,进程的基本元素:很有用
创建子进程
等待子进程结束
运行新程序
终止
回顾
#include <unistd.h>
pid_t fork();
特别之处:返回两次
子进程返回0
不为0,子进程ID
先后没有次序,是随机的
pid_t是整型的数据结构
例程:
/*forkd.c*/
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(void)
{
pid_t child;
if(!(child=fork()))
{
printf("in child /n");
_exit(0);
}
printf("in parent --child is %d/n",child);
return 0;
}
进程是一个正在执行程序
等待子进程结束
父进程当中,收集子进程的状态,称为等待
四种方法
内核调用 1
标准C函数库 3
pid_t wait4(pid_t pid,int *status,int options,struct rusage *rusage);
status//进程返回的状态,退出,Kill, 停止
以下宏测试其状态
WIFEXITED(status)//正常退出,内核返回,程序主动调用
WEXITSTUTUS(status)//进程退出代码
WIFSIGNALED(status)//进程被一个信号终止时 返回真值
WTERMSIG(status)//f返回信号的号
WIFSTOPPED(status)//为真,停止进程的信号
WSTOPSIG(status)//返回停止进程的信号
option 整形数据,控制调用怎样运行,运行的方式,
rusage 指向一个结构体指针,检验进程资源使用信息,如果为0则不返回状态信息
以下函数是wait4的子集
pid_t wait(int *status)//返回之前,一直阻塞
pid_t waitpid(pid_t pid ,int *status,int options)//
//不返回资源使用信息
pid_t wait3(int *status,int options,struct rusage *rusage)
//不允许调用哪一个子进程被调用
wait tomorrow 2.4 13min
运行新程序
exe函数簇
execl
execpl
execle
execv
execvp
execve
运行成功没有返回,失败,返回-1,把原来的程序置换掉
NULL表示结束, 没有NULL会造成段错误
例程:
终止:
void exit(int exitcode);//标准C函数库
void _exit(int exitcode);//系统调用
//exitcode退出返回码
int kill(pid_t pid,int signum);//signum信号,表示如何Kill
//pid 大于0 就发送给当前进程标示符,如果不是则退出,返回错误码,
如果小于-1,就返回给进程组ID及进程ID相反数的ID或组ID的所有进程
如果0,发送当前进程所属进程组的所有进程
如果是-1,信号就给发送给除了init进程的所有进程
2.5 进程4 简单子进程
system()
从进程读或写popen
通常创建一个子进程后,调用一个exec调用另外一个进程
system()
int sysytem (const char *cmd)
/bin/sh
示例
/*system*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
int main(void)
{
int result;
result = system("exec ls -l");
if(!WIFEXITED(result))
printf("abnormal exit/n");
_exit(0);
}
不正常退出,会返回fail
特殊权限使用应谨慎
不使用系统守护进程和setgid setuid还是相对安全
从进程读或写
FILE *popen(const char *cmd,const char *mode)
int pclose(FILE *stream)
解决system不能解决的问题,如system不能解决希望读入另一个进程的数据
写到另外的一个进程
总之是对另外进程的操作的问题解决
不可同时读写,本函数是做不到的
返回为FILE指针,
失败返回NULL
调用结束用pclose,从wait4返回子进程的状态
第5点 进程的会话和进程组
会话
控制终端
进程组
孤儿进程
会话
每个会话都关联到终端,可以是本地的控制台,或者是映射到X window的伪终端
进程组
UNIX的最初是建立工具的集合
孤儿进程组
多个进程组构成一个会话
当会话消失时,会话组长退出时,会话组不能使用标准输入输出,终端
已经退出了,
回顾