您的位置:首页 > 运维架构 > Linux

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

2007-07-14 15:31 459 查看
[align=center]第二章 Linux基础命令[/align]
这一章没什么好说的,记录几个自己以前不知道的。
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
 
 
 
 
[align=center]第三章 Linux下的C编程基础[/align]
使用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
[align=center] [/align]
[align=center] [/align]
[align=center] [/align]
[align=center]第六章 文件I/O编程[/align]
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
 
 
 
 
[align=center]第七章:进程控制开发[/align]
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:关闭日志文件连接。
 
 
 
 
[align=center]第八章 进程间通信[/align]
无名管道创建与使用:
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)
 
 
 
 
[align=center]第九章 多线程编程[/align]
[align=center] [/align]
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占用资源大的问题。
 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息