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