第二章 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占用资源大的问题。