嵌入式Linux应用程序开发详解

时间:2021-07-11 18:47:45
第二章 Linux基础命令 这一章没什么好说的,记录几个自己以前不知道的。 1.常见环境变量: HOME 根目录 HISTSIZE 保存历史命令记录的条数 LOGNAME 当前用户的登录名 HOSTNAME 主机名 2.设置环境变量的几种方法 echo, export, env(显示所有环境变量),set(显示所有本地定义的Shell变量),(unset清除所有环境变量) 3. id命令用来显示用户ID,组ID及用户所属组列表 4. Linux常见系统管理命令 setup 系统图形化界面配置 uptime 系统已经运行的时间长 crontab 循环执行例行性命令,这个没看明白 du 统计目录(或文件)所占磁盘空间的大小 du –h 以人性化显示,K,M等 ls –hl也可以打印出文件的大小。 5. diff与patch        diff hello1.c hello2.c > hello1.patch        patch hello1 < hello1.patch 6. Linux启动过程 打开电源(实模式),BIOS自检,启动设备及设备上的引导程序。 内核和引导(磁盘引导,实模与保护模式转换,段寄存器加载等)主要实现文件是bootsect->setup.S->head.S->main.c init程序(rc.sysinit和rc等程序返回init) init启动mingetty,打开终端供用户登录系统,成功后启动shell     BIOSàGrub/liloàKernel bootàinitàmingettyàshell                             |                        rc.sysinit, rc         第三章 Linux下的C编程基础 使用autotools步骤: 1.       autoscan: 检查目录树搜索源文件,生成configure.scan文件 2.       将configure.scan文件改为configure.in并修改(以hello.c为例): 1) 修改AC_INIT(hello, 1.0) 2) 增加AM_INIT_AUTOMAKE(hello,1.0) 3) AC_OUTPUT(Makefile) 3.       aclocal 处理本地宏定义,生成aclocal.m4文件 4.       autoconf: 生成配置文件configure 5.       autoheader: 负责生成config.h.in文件 6.       编写Makefile.am文件如下: AUTOMAKE_OPTIONS = foreign bin_PROGRAMS=hello hello_SOURCES=hello.c hello.h 7.       automake创建Makefile,些命令依赖上一步创建的Makefile.am 8.       ./configure; make       第六章 文件I/O编程 off_t lseek(int fd, off_t offset, int whence) 其中offset = 0如何理解? fcntl函数: fcntl(int fd, int cmd, flock* lock):        fcntl(fd, F_SETLK, &lock)―――根据lock.l_type决定上锁或解锁?        fcntl(fd, F_GETLK, &lock)―――根据lock.ltype判断是否可上锁? select函数主要负责I/O复用, 通过在循环测试读写集合中文件描述符是否可读写,并执行相关操作。   嵌入式Linux串口应用开发 1.       保存原串口配置 tcgetattr(fd,&oldtio) 2.       激活本地连接和接收使能。CLOCAL&CREAD 3.       设置波特率:cfsetispeed(&newtio, B115200) 4.       设置字符大小: options.c_cflag &=~CSIZE optinss.c_cflag |= CS8 5.       设置奇偶校验位: newtio.c_cflag |= PARENB; newtio.c_cflag |= PARODD; newtio.c_iflag |= (INPCK | ISTRIP) 6.       设置停止位CSTOPB:此位1则清除,0则置位 此处不太明白 newtio.c_cflag &= CSTOPB 7.       设置最少字符和等待时间c_cc[VTIME] and c_cc[V_MIN] 8.       处理要写入的引用对象。一种常用方法是 tcflush(fd,TCIFLUSH) 9.       激活配置:tcsetattr (fd, OPTION, &newtio)   使用串口: 1.       打开串口 fd = open( “/dev/ttyS0”, O_RDWR|O_NOCTTY|O_NDELAY); fcntl (fd, F_SETFL,0) //恢复串口为阻塞状态,用于等待串口数据输入 isatty(STDIN_FILENO) //打开的文件的描述符是否引用了一个终端设备 2.       读写串口 read and write function   重难点        fgets(gets), fgetc(getc), fread, fwrite, fdopen, frepopen, read, write         第七章:进程控制开发 pid_t fork(): 子进程返回0,父进程返回子进程的ID exec的几种形式 execl, execle, execlp: l表示参数传递方式为列举式,形式为const char*, e表示环境变量,p表示可执行文件查找方式为文件名 execv,execve, execvp: v表示参数传递方式为构造指针数据方式,char * const exit与_exit:        exit:检查文件找开状态,把缓冲区的内容写入文件        _exit则直接退出,不写缓冲到文件。 wait, waitpid        wait阻塞等待一个子进程结束。        waitpid提供一个非阻塞版本的wait, wait只是其一个特例。 Linux守护进程编写步骤: 1.       创建子进程,父进程退出    if (pid>0) exit(0); 2.       在子进程中创建新会话        setsid(); 3.       改变当前目录为根目录        chdir(“/”); 4.       重设文件权限掩码        umask(0); 5.       关闭文件描述符   for(i;;) close(i);   守护进程的出错处理方法:<-----------------有待进一步研究        在setsid创建新会话前用opnelog打开系统日志服务。        在setsid函数中启用syslog进行错误登记        关闭文件描述符后打开守护进程的日志文件,并写入open的日志记录。 用到三个函数:        openlog打开日志文件的一个连接。        syslog向日志文件中写入消息。        closelog:关闭日志文件连接。         第八章 进程间通信 无名管道创建与使用: 1.       创建前需定义有两个元素的int型文件描述符数组,形如fds[2] 2.       创建管道,传入的参数为上面定义的fds,这样就创建了两个文件描述符,其中fds[0]是管道的读端,fds[1]是写端。 3.       使用管道后关闭两个文件描述符 无名管道用于父子进程间的通信。 通常父进程fork子进程后,子进程继承了父进程的管道,通过将父子进程的管道某一不需要的端关闭实现通信。如父进程关闭读端,子进程关闭写端就可以实现父进程写子进程读。        if((pid=fork())==0) //子进程        {               close(fd[1]); sleep(2); //关闭子进程写,睡眠等待父进程写入               read(fd[0], buf, size) } else if(pid>0) //父进程 {        close(fd[0]) //关闭父进程读端        write(fd[1], “Hello”, 5); //写入管道供子进程读 } 无名管道也可以实现各个子进程间的通信,原理同上。   标准流管道:popen()将管道的一系列创建过程合并。例popen(“ps –ef”,”r”)   有名管道FIFO:        创建有名管道fd = mkfifo(const char* filename, mode_t mode)        读写同文件读写open , write   信号        信号发送与捕捉kill(), raise(), alarm(), pause()        简单信号处理void (*signal(int signum, void(*handler)(int)))(int) 例:               signal(sigint, my_func); //my_func是自定义的处理函数        信号集处理:
      

定义信号集 sigemptyset sigaddset
设置信号屏蔽位 sigprocmask
定义信号处理函数 if (sigismember(…)) {sa_mask; sa_handler; Sigaction}
测试信号 sigpending

共享内存:
       shmget(key_t key, int size, int shmflag)创建共享内存
       shmat(int shmid, void* shmaddr, int shmflg) 映射共享内存,shmflgl默认0可读写。        shmdt(const * shmaddr) 撤消共享内存        例:               shmid=shmget(IPC_PRIVATE, BUFSIZE, 0666)               shmaddr=shmat(shmid, 0, 0)                                                         <------使用共享内存,如何用,待学习补充               shmdt(shmaddr) 消息队列:        创建消息队列:qid = msgget(key, IPC_CREAT|0666)        添加消息到消息队列:msgsend(qid, &msg, BUFSIZE, 0,0)        从系统中移走消息队列:msgctl(qid, IPC_RMID,NULL)         第九章 多线程编程   gcc 编译时加上-pthread参数。 创建线程的过程: 1.       先定义线程函数 *start_routine 2.       ret = pthread_create((pthread_t *thread_id, pthread_attr_t *attr, void* (*start_routine),void* arg)创建一个线程,其中start_routine是线程函数的起始地址。 3.       pthread_join(thread_id, retvalue)   线程的分离属性:        用于决定线程以什么样的方式终止自己,而不需要pthread_join()才释放占有的资源。        带来的问题是,如果该线程很快,则它可能在pthread_create返回之前便终止了,终止后的线程号可能被其它线程所用,导致pthread_create得到错误的线程号。所用到的函数及步骤为: 1) 初始化线程pthread_attr_init(&attr) 2) 设置线程绑定属性pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM)。 3) 设置线程分离属性pthread_attr_setdetachstate(&attr, PTHREAD_CREATE,_DETATCHED); 4) pthread_create(…)创建线程   mutex互斥线程控制 互斥锁分为三种:快速(等待线程阻塞直至拥有的线程解锁),检错(快速锁的非阻塞版本),递归(返回,增加加锁的次数)。        互斥锁初始化pthread_mutex_init(&mutex,NULL)        线程一互斥锁上锁 pthread_mutex_lock(&mutex)        线程二测试线程是否上锁pthread_mutex_trylock(&mutex)        得到线程锁者解除线程锁pthread_mutex_unlock(&mutex)   信号量互斥控制(只需一个信号量):        sem_t sem;        sem_init(&sem, 0, 1)  //(信号量,pshare, 信号量初值)        sem_wait(&sem) //信号量获取,相当于P操作        sem_post(&sem)    //信号量加一,唤醒等待进程。        其它函数               sem_getvalue取得值,sem_destroy删除   信号量同步(两个信号量sem1,sem2)程序如下:        信号量初始化               sem_init(&sem1, 0, 1)  //sem1设为1,               sem_init(&sem2,0,0)  //sem2 设为0 thread1:               sem_wait(&sem1);               sem_post(&sem2); thread2:               sem_wait(&sem2);               sem_wait(&sem1); 这样,thread1线程首先获取sem1后,再post sem2唤醒thread2以达到同步。            第十章 嵌入式Linux网络编程 socket 基础编程 1. server: 1)建立socket连接sockfd= socket(AF_INET, SOCK_STREAM, 0),其中AF_INET 表示IPV4,SOCK_STREAM表示字节流套接字。 2)设置sockaddr_in结构体中的相关参数, 其中有port设置。 3)绑定本地IP地址绑定端口号(此端口供connect)。bind(sockfd, (struct sockaddr*)&server_sockaddr, sizeof(sockaddr) 4)侦听listen(sockfd, BACKLOG) BACKLOG是请求队列中最大请求数,默认20。 5)调用accept户端的连接。client_fd = accept(sockfd, (struct sockaddr *) &client_sockaddr, &sin_size) 6) recv接收数据。 7)关闭sockfd   2.客户端步骤基本同服务器,不同之处是后没有listen,且connect取代accept, send代recv   在高级网络编程中可以用fcntl设置sever非阻塞侦听,使用select函数解决循环测试CPU占用资源大的问题。