嵌入式Linux学习笔记(三)Linux系统编程

Linux系统编程是介于驱动层和应用层之间的编程方法,一般编程形式为:

int main(int argc, char *argv[])

{
    //argc为参数个数
    //argv为命令行中的参数
    return 0;
}

文件IO函数

文件open函数

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
/*
pathname为文件名;
flag为打开文件的状态:0_RDONLY-可读,0_WRONLY-可写,0_RDWR-可读可写等;
当flag为O_CREAT创建文件时,需加入第三个参数mode-文件的权限
*/

函数返回值为int型文件描述符:0-标准输入;1-标准输出;3-标准出错;-1-读不到文件。若创建新文件返回值将从3递增。

文件close函数

#include <unistd.h>

int close(int fd);
//关闭一个文件描述符-open函数的返回值

 文件read函数

#include <unistd.h>

ssize_t read(int fd, void *buf, size_t count);
//从文件描述符fd中读取count长度的字符到buf缓冲区中,返回值为实际读取到的字节数

文件write函数

#include <unistd.h>

ssize_t write(int fd, const void *buf, size_t count);
/*
把count长度的字符从buf缓冲区中写到文件描述符为fd的文件中,
返回值为实际写入的字节数,写入失败返回-1
*/

设置文件位置指针lseek函数

#include <sys/types.h>
#include <unistd.h>

off_t lseek(int fd, off_t offset, int whence);
/*
fd-文件描述符;
offset-相对于whence的偏移量,负数向前移动,正数向后移动;
whence-当前位置的基点
    SEEK_SET:相对于文件开头
    SEEK_CUR:相对于当前文件读写指针的位置
    SEEK_END:相对于文件末尾
返回值,成功后范围位移值,失败返回-1
*/

目录IO函数 

创建目录mkdir函数

#include <sys/stat.h>
#include <sys/types.h>

int mkdir(const char *pathname, mode_t mode);
//pathname-创建的路径;mode-文件夹的权限
//创建成功返回0,失败返回-1

打开目录opendir函数

#include <dirent.h>
#include <sys/types.h>

DIR *opendir(const char *name);
//name-打开的路径目录,返回值为目录流指针

关闭目录opendir函数

#include <dirent.h>
#include <sys/types.h>

int closedir(DIR *dirp);
//dirp-对应目录流指针,成功返回0,失败返回-1

读目录readdir函数

#include <dirent.h>

struct dirent *readdir(DIR *dirp);
//dirp-对应目录流指针,返回dirent结构体
//如果读取到文件尾或读取失败返回NULL

struct dirent{
    ino_t     d_ino; // 文件inode
    off_t     d_off; 
    unsigned  short d_reclen;
    unsigned  char d_type;
    char      d_name[256]; // 文件名
}


Linux下的库

种类分为静态库和动态库

静态库:静态库在程序编译时会被链接到目标代码里。程序运行时不再需要动态库了。因此编译出来的体积较大。

        特点:以lib开头,以.a结尾

动态库(共享库):动态库态库在程序编译时不会被链接到目标代码里。程序运行时还需要动态库。因此编译出来的体积较小

        特点:以lib开头,以.so结尾

静态库制作步骤:

①编写库的源代码

②将源代码的.c文件编译生成.o文件

gcc -c mylib.c

③使用ar命令创建静态库

ar cr libmylib.a mylib.o # libmylib.a-库文件名,mylib-库名

④使用静态库中的函数后,在编译时要链接静态库

gcc test.c -lmylib -L . # -l指定库名,-L指定路径

动态库制作步骤:

 ①编写库的源代码

②将源代码的.c文件编译生成.o文件

gcc -c -fpic mylib.c # -fpic:产生位置无关代码

③使用gcc命令创建动态库

gcc -shared -o libmylib.so mylib.o # libmylib.so-库文件名,mylib-库名

④使用动态库中的函数后,我们在编译时需要链接库。系统默认会在/lib或者/usr/lib中找库文件,或者在编译的时候指定库文件的路径

编译时链接到库的三种方法:

        1.将生成的动态库拷贝到/lib或者/usr/lib中

        2.把动态库所在的路径添加到环境变量中

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/path/to/lib

        3.修改/etc/id.so.conf,在配置文件中加入动态库路径,然后使用ldconfig更新目录


Linux和进程 

每个进程都有唯一的标识符,即进程ID,简称pid

进程间通信:

        管道通信:有名管道,无名管道

        信号通信:信号的发送,信号的接收,信号的处理

        IPC通信:共享内存,消息队列,信号灯

        socket通信

进程的三种基本状态:就绪态、执行态、阻塞态

创建进程fork函数

#include <unistd.h>
pid_t fork(void)
//在父进程中,返回值为子进程的pid,在子进程中,返回值为0,错误返回值为负数

获得pid函数

getpid(); // 获得当前进程的pid
getppid(); // 获得当前进程的父进程的pid

使子进程执行不同于父进程的程序exec函数族

作用:①当一个进程不能再作出贡献时,可以使用exec函数使自己重生②如果一个进程想执行另一个程序,就可以调用exec函数使子进程重生。

#include <unistd.h>
int execl(const char *path, const char *arg, ...)
//path-文件路径,arg-进程名,“...”-进程的参数,以NULL结尾

ps命令

ps命令可以列出系统中当前运行的进程

格式:ps [参数](常用aux)

kill命令

kill命令用于杀死进程

格式:kill -9 pid

孤儿进程

父进程结束后,子进程还未结束,这个子进程就叫孤儿进程,它会被系统的init进程“领养”。

僵尸进程

子进程结束以后,父进程还在运行,但父进程未释放进程控制块,这个子进程就叫僵尸进程,可以通过kill命令杀死。

回收子进程wait函数

#include <sys/wait.h>

pid_t wait(int *status)
/*
返回值:成功返回子进程pid,失败返回-1
参数status有两个宏定义:
WIFEXITED(status):如果子进程正常退出,该宏定义为真
WEXITSTATUS(status):如果子进程正常退出,该宏定义为子进程的退出值
*/

守护进程

        1.是init进程的子进程

        2.不和控制终端交互

创建守护进程:1.使用fork函数创建一个进程,再推出父进程

                         2.调用setsid函数,摆脱控制终端

                         3.调用chdir函数,将当前工作目录改为根目录

                         4.重设umask文件掩码

                         5.关闭文件描述符

管道通信pipe函数:

无名管道-只能实现有亲缘关系进程之间的通信

#include <unistd.h>
int pipe(int pipefd[2]);
//得到的文件描述符pipefd[0]为读端,pipefd[1]为写端

有名管道-可以实现所有进程通信,通过对fifo文件的读和写进行通信

#include <sys/types.h>
#include <sys/stat.h>

int mkfifo(const char *pathname, mode_t mode);
//创建成功返回0,创建失败返回-1;pathname-创建文件名;mode-文件权限

信号发送函数

kill函数

#include <sys/types.h>
#include <signal.h>

int kill(pid_t pid, int sig);
//pid-进程号;sig-信号的种类

raise函数(等价于kill(getpid(), sig),给自己发信号)

#include <signal.h>

int raise(int sig);

信号中断函数

pause函数:使目前的进程暂停,直到被信号中断

#include <unistd.h>

int pause(void);//只返回-1

信号处理函数

#include <signal.h>

typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler)
//signum-要处理的信号;handler-处理的方式(SIG_DFL-系统默认、SIG_IGN-忽略、捕获)

捕获信号并自定义处理

void myfun(int sig)
{
    if(sig == SIGINT)
    {
        return -1;
    }
}

void main(void)
{
    signal(SIGINT, myfun);

    whlie(1){
        printf("wait\n");
        sleep(1);
    }
}

共享内存

创建共享内存shmget函数

#include <sys/ipc.h>
#include <sys/shm.h>

int shmget(key_t key, size_t size, int shmflg);
/*
key_t key:IPC_PRIVATE或ftok函数返回值
size_t size:共享内存大小    
int shmflg:权限
成功返回共享内存标识符,失败返回-1
*/

key_t ftok(const char *pathname, int proj_id);
/*
pathname-文件名
proj_id-字符
成功返回key值,失败返回-1
*/

将共享内存映射到进程shmat函数

#include <sys/types.h>
#include <sys/shm.h>

void *shmat(int shmid, const void *shmaddr, int shmflg);
/*
shmid:共享内存标识符
shmaddr:映射到的地址,NULL-系统自动映射    
shmflg:权限,0-可读可写
成功返回共享内存映射到进程中的地址,失败返回-1
*/

删除共享地址映射shmdt函数

#include <sys/types.h>
#include <sys/shm.h>

int shmdt(const void *shmaddr);
/*
shmaddr:映射地址
成功返回0,失败返回-1
*/

操作共享内存shmctl函数

#include <sys/ipc.h>
#include <sys/shm.h>

int shmctl(int shmid, int cmd, struct shmid_ds *buf);
/*
shmid:要操作的共享内存标识符
cmd:IPC_STAT(获取对象属性),IPC_sET(设置对象属性),IPC_RMID(删除对象)
buf:指定要操作的对象属性
*/

消息队列

创建消息队列msgget函数

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgget(key_t key, int msgflg);
/*
key-消息队列的key值
msgflg-访问权限
成功返回消息队列ID,失败返回-1
*/

 操作消息队列msgctl函数

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgctl(int msqid, int cmd, struct shmsq_ds *buf);
/*
msqid:要操作的消息队列ID
cmd:IPC_STAT(获取消息队列属性),IPC_sET(设置消息队列属性),IPC_RMID(删除消息队列)
buf:消息队列缓冲区
成功返回0,失败返回-1
*/

  发送消息msgsnd函数

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
/*
msqid:消息队列ID
msgp:指向消息类型的指针
msgsz:发送消息的字节数
msgfig:0-直到发送完成才返回(阻塞发送);IPC_NOWAIT-消息没发送完成也会返回(非阻塞发送)
成功返回0,失败返回-1
*/
//msgp指向的格式
struct msgbuf{
        long mtype;    //消息的类型
        char mtext[1]; //消息的内容
};

接收消息msgrcv函数

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
/*
msqid:消息队列ID
msgp:接收消息的缓冲区
msgsz:接收消息的字节数
msgtyp:接收消息的标识
msgfig:0-阻塞读取;IPC_NOWAIT-非阻塞读取
成功返回接收消息的长度,失败返回-1
*/

信号量

获取信号量IDsemget函数

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

int semget(key_t key, int nsems, int semflg);
/*
key:信号量的键值
nsems:信号量的数量
semflg:标识
成功返回信号量的ID,失败返回-1
*/

 操作信号量semctl函数

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

int semctl(int semid, int semnum, int cmd, union semun arg);
/*
semid:信号量ID
semnum:信号量编号
cmd:IPC_STAT(获取信号量属性),IPC_sET(设置信号量属性),
    IPC_RMID(删除信号量),SETVAL(设置信号量的值)
arg:信号量结构体
*/

union semun{
        int val;
        struct semid_ds *buf;
        unsigned short *array;
        struct seminfo *__buf;
};

操作信号量数量semop函数

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

int semop(int semid, struct sembuf *sops, size_t nsops);
/*
semid:信号量ID
sops:信号量结构体数组 
nsops:要操作的信号量数量
*/

struct sembuf{
        unsigned short sem_num; //要操作的信号量编号
        short sem_op; // P/V操作。
              //1为V操作,释放资源;-1为P操作,分配资源,0为等待,知到信号量变为0
        short sem_fig; //0-阻塞,IPC_NOWAIT-非阻塞
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值