第二章 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 |
定义信号处理函数 if (sigismember(…)) {sa_mask; sa_handler; Sigaction} |
共享内存:
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占用资源大的问题。