《linux操作系统下c语言编程入门.ppt》由会员分享,可在线阅读,更多相关《linux操作系统下c语言编程入门.ppt(37页珍藏版)》请在三一文库上搜索。
1、Linux操作系统下 C语言编程入门,CNT,Linux操作系统简介 基础知识 进程介绍 文件操作 时间概念 消息管理 线程操作 网络编程 Linux下C开发工具介绍,一.Linux操作系统简介,发展历史 1969年,Ken Thompson ,UNIX MINIX 1991年,芬兰赫尔辛基大学 LINUS 现状和前景 大型计算机系统、PC、手持电脑 主要特点 多用户、多任务、稳定性、安全性、开放性、网络功能 应用领域 Internet(WEB、FTP、邮件、DNS服务器,TCP/IP路由、防火墙)、LAN、嵌入式系统、办公桌面 发行版本 RedHat、Debian、红旗,二.基础知识,源程序
2、的编译 gcc 编译器 g+ 编译器 例:gcc -o hello hello.c g+ -g -o hello.o hello.cpp 编写makefile文件 对某个Project编译时,需要编写makefile文件。 一般的格式是: Target : components (依赖关系) TAB rule (规则) makefile 有三个非常有用的变量,分别是:$、$ 、$ $ 代表目标文件 $ 代表所有的依赖文件 $ 代表第一个依赖文件的名称,Makefile实例: #This is the makefile CC = g+ CFLAG = -Wall -O plcMain: src/
3、main.cpp obj/com.o obj/msgware.o obj/process.o obj/rtu.o obj/lmasrtu.o obj/schedule.o obj/rs232.o obj/linkcheck.o obj/msgqueue.o obj/ping.o obj/pid.o obj/paramfile.o $(CC) $(CFLAG) -lpthread -o $ src/main.cpp obj/com.o obj/msgware.o obj/process.o obj/rtu.o obj/lmasrtu.o obj/schedule.o obj/rs232.o ob
4、j/linkcheck.o obj/msgqueue.o obj/ping.o obj/pid.o obj/paramfile.o obj/com.o:src/Communication.cpp $(CC) $(CFLAG) -c -o $ $ obj/msgware.o:src/MsgWare.cpp $(CC) $(CFLAG) -c -o $ $ clean: rm -fr *.o,程序的调试 打印调试 GDB调试 头文件和系统求助 man 例:man write man 2 write “2”表示我们用的write函数是系统调用函数 “3”表示函数是C的库函数,三.进程介绍,进程的概念
5、 程序和进程 程序是一个包含可以执行代码的文件,是一个静态的文件;而进程是一个开始执行但是还没有结束的程序的实例,就是可执行文件的具体实现。当程序被系统调用到内存以后,系统会给程序分配一定的资源(内存、设备等等),然后进行一系列的复杂操作,使程序变成进程以供系统调用。 进程的状态 新建、运行、阻塞、就绪和完成,进程的标志 为了区分各个不同的进程,系统给每一个进程分配了一个ID。 系统调用getpid函数可以得到进程的ID,而调用getppid函数可以得到父进程(创建调用该函数进程的进程)的ID。getuid可以得到进程所有者的ID,getgid可以得到组ID。 进程的创建 调用fork函数就可
6、以创建一个进程的系统调用。 pid_t fork();,四.文件操作,文件的创建和读写 int open(const char *pathname,int flags); int open(const char *pathname,int flags,mode_t mode); open函数有两个形式。其中pathname是我们要打开的文件名(包含路径名称,缺省是认为在当前路径下面);flags 可以是下面的一个值或者是几个值的组合: O_RDONLY、O_WRONLY、O_RDWR、 O_CREAT、 O_APPEND(追加)、O_TRUNC(如果文件已经存在,则删除文件的内容)、O_NOB
7、LOCK(非阻塞方式) *前面三个标志只能使用任意的一个,*如果使用了O_CREATE标志,那么我们可以使用open的第二种形式。还要指定mode 标志,用来表示文件的访问权限。mode 可以是以下情况的组合: - S_IRUSR 用户可以读 S_IWUSR 用户可以写 S_IXUSR 用户可以执行 S_IRWXU 用户可以读写执行 - S_IRGRP 组可以读 S_IWGRP 组可以写 S_IXGRP 组可以执行 S_IRWXG 组可以读写执行 - S_IROTH 其他人可以读 S_IWOTH 其他人可以写 S_IXOTH其他人可以执行 S_IRWXO 其他人可以读写执行 - S_ISUID
8、 设置用户执行ID S_ISGID 设置组的执行ID - 例:fd=open(“mnt/mtd/tb.data” , O_RDWR|O_CREAT|O_TRUNC ); fd=open(“temp” , O_CREAT, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IXOTH);,文件打开以后,我们就可以调用write和read函数对文件进 行读写操作了。 ssize_t read(int fd, void *buffer,size_t count); ssize_t write(int fd,
9、 const void *buffer,size_t count); fd是我们要进行读写操作的文件描述符,buffer是我们要 写入文件内容或读出文件内容的内存地址,count是我们要读 写的字节数。 read 从指定的文件 fd 中读取count字节到buffer 缓冲区 中,同时返回count。当读到了文件的结尾或者被一个信号所 中断,返回值会小于count;如果是由信号中断引起返回,而且 没有返回数据,read会返回-1,且设置errno为EINTR;当程 序读到了文件结尾的时候,read 会返回0。 write 从buffer 中写count字节到文件 fd 中,成功时返回实 际所写
10、的字节数。 关闭文件时,只要调用close函数就可以了。,while(bytes_read=read(from_fd,buffer,BUFFER_SIZE) if(bytes_read=-1 ) ,文件的属性 int access(const char *pathname,int mode); 判断文件是否可以进行某种操作(读,写等等),mode可以是以下值的组合: R_OK 文件可以读; W_OK 文件可以写; X_OK 文件可以执行; F_OK 文件存在 测试成功时,函数返回0;当有一项不符合时,返回-1。 要获得文件的其他属性,我们可以使用函数stat 或者fstat。 int stat
11、(const char *pathname, struct stat * buf); int fstat(int filedes, struct stat * buf); 返回的文件特性保存在类型为stat的结构体中(包含设备、节点、模式、用户ID、组ID、文件字节数、最后一次访问、修改的时间等信息),参数buf指向该结构。 在该结构中,我们感兴趣的成员之一是st_mode,它包含了文件类型和文件权限。,目录文件的操作 C库函数中提供了getcwd函数,可以得到当前工作路径。 char *getcwd(char *buffer , size_t size); Linux下的目录操作函数: in
12、t mkdir(const char *path,mode_t mode); /创建目录 DIR *opendir(const char *path); /打开目录 struct dirent *readdir(DIR *dir); /读取目录 int closedir(DIR *dir); /关闭目录,其他函数 int unlink(const char *pathname); /删除文件 int rmdir(const char *pathname); /删除目录 int remove(const char *pathname); /删除文件或目录 int rename(const cha
13、r *oldname, const char *newname); /文件或目录更名 int chmod(const char *filename, mode_t mode); int fchmod(int filedes, mode_t mode); chmod和fchmod用于改变文件的访问权限。成功则返回0,否则返回-1。,五.时间概念,时间表示和测量 time_t time(time_t *tloc); 返回自1970年1月1日0点以来的秒数 char *ctime(const time_t *clock); 将秒数转化成字符串,例:Sat Dec 31 10:00:00 2005 l
14、ocaltime 取得当地目前的时间和日期 mktime 将时间结构数据转换成经过的秒数 settimeofday 设置目前的时间 gettimeofday 取得目前的时间,可以用作时间的测量,六.消息管理,POSIX 无名信号量 用主要是用来保护共享资源,使得资源在一个时刻只为一 个进程所拥有。 信号灯(semaphore)是进程间共享的资源计数器。 int sem_init(sem_t *sem,int pshared,unsigned int value); int sem_destroy(sem_t *sem); /删除信号灯 int sem_wait(sem_t *sem); /阻塞
15、进程,直到信号灯 值大于0,返回时自动将信号灯的值减1 int sem_post(sem_t *sem); /与sem_wait相反,将 信号灯的值加1,同时发出信号唤醒等待的进程 int sem_trywait(sem_t *sem);/与sem_wait相似,但不阻塞 int sem_getvalue(sem_t *sem); /得到信号灯的值,System V 信号量 System V的信号量是信号量集,可以包括多个信号灯,每个操作可以同时操作多个信号灯 ; POSIX是单个信号灯,POSIX有名信号灯支持进程间通信,无名信号灯放在共享内存中时可以用于进程间通信。,七.线程操作,线程 线
16、程是比进程更小的能独立运行的基本单位。 共享程序代码 节省资源 线程的创建和使用 int pthread_create(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *), void *arg); pthread_create 创建一个线程,thread 是用来表明创建 线程的ID,attr 指出线程创建时候的属性,我们用NULL 来表明使用缺省属性。start_routine 函数指针是线程创 建成功后开始执行的函数,arg是这个函数的唯一一个参 数,表明传递给start_routine 的参数。,例
17、: if(pthread_create(&m_threadID,NULL,ThreadQueryData,(void*)this) != 0) if(pthread_create(&UpdateThreadId, NULL, ThreadDownLoadBaseSchedule, (void*)this) != 0) if(pthread_create(&SpanUpdateThreadId, NULL, ThreadUpdateSpanTimeTableToPlc, (void*)this) != 0),void pthread_exit(void *retval); int pthread
18、_join(pthread *thread,void *thread_return); pthread_exit 函数和exit 函数类似,用来退出线程。这个 函数结束线程,释放函数的资源,并在最后阻塞,直到 其他线程使用pthread_join 函数等待它,然后将*retval 的值传递给*thread_return。 *多线程中共同占用某一资源时,注意信号锁机制。,八.网络编程,Linux 网络知识介绍 1.客户端程序和服务端程序 网络程序和普通的程序有一个最大的区别是网络程 序是由两个部分组成的客户端和服务器端。 网络程序是先有服务器程序启动,等待客户端的程 序运行并建立连接。一般的来说
19、是服务端的程序在一个 端口上监听,直到有一个客户端的程序发来了请求。 2.常用的命令 netstat 显示网络的连接、路由表和接口等信息。 telnet用于远程控制的程序,可以用来调试服务端程序。,3. TCP/UDP 介绍 TCP(Transfer Control Protocol)传输控制协议是一种面 向连接的协议,当我们的网络程序使用这个协议的时 候,网络可以保证我们的客户端和服务端的连接是可靠 的,安全的。 UDP(User Datagram Protocol)用户数据报协议是一种非 面向连接的协议,这种协议并不能保证我们的网络程序 的连接是可靠的,所以我们现在编写的程序一般是采用 T
20、CP 协议的。,初等网络函数介绍(TCP) Socket(套接字) 套接字是一个通信端口,是一种使用标准UNIX文件描述 字和其他程序通信的方法。从程序员的角度来看,它很象 文件描述字,因为它同文件和管道一样使用write/read来读 写数据。但是套接字和普通文件描述字又有不同: 首先,套接字除了可以有一个地址以外,还明显包含着 关于通信的3个属性域、类型和协议; 其次,套接字的使用可以是非对称的,它通常明确的区 分通信的两个进程为客户进程和服务进程,并且允许不同 系统或机器上的多个客户与单个服务相连; 最后,套接字的创建和各种操作与文件描述字也有所不 同。,socket (创建套接字) i
21、nt socket(int domain, int type, int protocol); domain: 说明网络程序所在的主机采用的通信协议族(AF_UNIX(UNIX域) 和AF_INET(Internet域) 等); type:网络程序所采用的通讯协议(SOCK_STREAM、SOCK_DGRAM等) ,SOCK_STREAM表示我们使用的是TCP协议, SOCK_DGRAM表示我们使用的是UDP协议。 protocol: TCP/UDP,由于已指定协议,这里设置为0。 socket调用成功时,返回值为0;否则返回-1。 例:skConnectSocket = socket(AF_I
22、NET,SOCK_DGRAM,0);,bind (命名套接字) int bind(int sockfd, struct sockaddr *my_addr, int addrlen); sockfd: 是由socket 调用返回的文件描述符. my_addr: 是一个指向结构类型sockaddr 对象的指针,该对象包含了要指定给socket的地址。 addlen: socketaddr结构对象的长度。 函数调用成功时返回0,否则返回-1。 listen (创建连接队列) int listen(int sockfd,int backlog); sockfd: 是bind返回的文件描述符。 bac
23、klog: 设置请求排队的最大长度。 listen 函数将bind 的文件描述符变为监听套接字,返回的情况和bind 一样。,accept (创建新的面向特定客户的套接字) int accept(int sockfd, struct sockaddr *addr,int *addrlen); sockfd: 是listen 后的文件描述符。 addr, addrlen 是用来给客户端的程序填写的,服务器端只要传递指针就可以了。 bind、listen和accept 服务器端用的函数,accept 调用 时,服务器端的程序会一直阻塞到有一个客户程序发出了 连接。accept 成功时返回最后的服务
24、器端的文件描述符, 这个时候服务器端可以向该描述符写信息了,失败时返 回-1。,connect (与服务器建立连接) int connect(int sockfd, struct sockaddr * serv_addr,int addrlen); sockfd:socket返回的、同服务端通讯的文件描述符。 serv_addr:储存了服务器端的连接信息。其中包含了服务端的地址。 addrlen:serv_addr结构对象的长度。 connect 函数是客户端用来同服务端连接的。成功时返回0,失败时返回-1。,套接字连接示意图 服务端 客户端,socket(),bind(),accept(),
25、listen(),阻塞直到收到来自 客户的数据报,socket(),connect(),建立连接,write(),read(),数据(请求),read(),进程请求,write(),数据(回答),read(),close(),close(),文件结束,读写函数 写函数write ssize_t write(int fd,const void *buf,size_t nbytes); write 函数将buf中的nbytes字节内容写入文件描述符 fd。成功时返回写的字节数,失败时返回-1,并设置 errno 变量。如果错误为EINTR,表示在写的时候出现了 中断错误;如果为EPIPE,表示网络
26、连接出现了问题(对 方已经关闭了连接)。,读函数 read ssize_t read(int fd,void *buf,size_t nbyte) ; read 函数是负责从fd 中读取内容。当读成功时,read 返回实际所读的字节数,如果返回的值是0 表示已经读 到文件的结束了,小于0表示出现了错误。如果错误为 EINTR 说明读是由中断引起的, 如果是ECONNREST 表 示网络连接出了问题。,数据的传递 /* 客户端向服务端写 */ struct my_struct my_struct_client; write(fd,(void *),用户数据报发送(UDP) 两个常用的函数 int
27、 recvfrom(int sockfd,void *buf,int len,unsigned int flags,struct sockaddr * from, int *fromlen); int sendto(int sockfd,const void *msg,int len,unsigned int flags,struct sockaddr *to, int tolen); sockfd,buf,len 的意义和read、write 一样,分别表示套 接字描述符、发送或接收的缓冲区及大小。recvfrom 负 责从sockfd 接收数据,如果from不是NULL,那么from 里面
28、存储了信息来源的情况;如果对信息的来源不感兴 趣,可以将from 和fromlen 设置为NULL。sendto 负责 向to 发送信息,此时在to 里面存储了收信息方的详细资 料。 例: int iRetVal = sendto(skConnectSocket, pszData, len, 0, (struct sockaddr *),九. Linux 下C开发工具介绍,GNU C 编译器(GCC) GNU C 编译器(GCC)是一个全功能的ANSI C 兼容编译器。 使用GCC gcc options filenames 不用任何选项编译一个程序时,GCC 将会生成(假定编 译成功)一个名
29、为 a.out 的可执行文件。-o 编译选项来 为将产生的可执行文件指定一个文件名来代替 a.out。 -O -O2 优化选项 -g 输出调试信息,用GDB调试GCC程序 Linux 包含了一个叫 gdb 的 GNU 调试程序。gdb 是一个 用来调试 C 和 C+ 程序的强力调试器, 它使你能在程序运 行时观察程序的内部结构和内存的使用情况。 gdb可以提供的以下功能: 监视程序中变量的值 能设置断点以使程序在指定的代码行上停止执行 能一行行的执行你的代码 在命令行上键入 gdb 并按回车键就可以运行 gdb 了,或 者键入 gdb 直接指定想要调试的程序。,gdb 基本命令 file 装入想要调试的可执行文件 kill 终止正在调试的程序 list 列出产生执行文件的源代码的一部分 next 执行一行源代码但不进入函数内部 step 执行一行源代码而且进入函数内部 run 执行当前被调试的程序 quit 终止 gdb watch 使你能监视一个变量的值而不管它何时被改变 print 显示表达式的值 break 在代码里设置断点, 这将使程序执行到这里时被挂起 make 使你能不退出 gdb 就可以重新产生可执行文件 shell 使你能不离开 gdb 就执行 UNIX shell 命令,谢 谢 ! 祝 新 年 快 乐 !,
链接地址:https://www.31doc.com/p-3407006.html