第06章 unix系统编程基础.ppt
一个简单的C程序示例程序代码:intmain(intargc,char*argv)printf(HelloLinuxn);编译过程:gcc-ohellohello.c程序的运行./hello多个文件组成的程序文件1:main.cvoidmytool1_print(char*print_str);voidmytool2_print(char*print_str);intmain(intargc,char*argv)mytool1_print(hello);mytool2_print(hello);文件2:mytool1.cvoidmytool1_print(char*print_str)printf(Thisismytool1print%sn,print_str);文件3:mytool2.cvoidmytool2_print(char*print_str)printf(Thisismytool2print%sn,print_str);编译和运行编译:gcc-cmain.cgcc-cmytool1.cgcc-cmytool2.cgcc-omainmain.omytool1.omytool2.o运行:./mainmakefilemakemakefilemakeflie文件内容:main:main.omytool1.omytool2.ogcc-omainmain.omytool1.omytool2.omain.o:main.cgcc-cmain.cmytool1.o:mytool1.cgcc-cmytool1.cmytool2.o:mytool2.cgcc-cmytool2.c与进程相关的apipid_tgetpid(void);pid_tgetppid(void);uid_tgetuid(void);uid_tgeteuid(void);gid_tgetgid(void);git_tgetegid(void);getpwuidstructpasswd*getpwuid(uid_tuid);passwd结构structpasswdchar*pw_name;/*登录名称*/char*pw_passwd;/*登录口令*/uid_tpw_uid;/*用户ID*/gid_tpw_gid;/*用户组ID*/char*pw_gecos;/*用户的真名*/char*pw_dir;/*用户的目录*/char*pw_shell;/*用户的SHELL*/;用户管理示例程序(1/2)intmain(intargc,char*argv)pid_tmy_pid,parent_pid;uid_tmy_uid,my_euid;gid_tmy_gid,my_egid;structpasswd*my_info;my_pid=getpid();parent_pid=getppid();my_uid=getuid();my_euid=geteuid();my_gid=getgid();my_egid=getegid();my_info=getpwuid(my_uid);用户管理示例程序(2/2)printf(ProcessID:%ldn,my_pid);printf(ParentID:%ldn,parent_pid);printf(UserID:%ldn,my_uid);printf(EffectiveUserID:%ldn,my_euid);printf(GroupID:%ldn,my_gid);printf(EffectiveGroupID:%ldn,my_egid);if(my_info)printf(MyLoginName:%sn,my_info-pw_name);printf(MyPassword:%sn,my_info-pw_passwd);printf(MyUserID:%ldn,my_info-pw_uid);printf(MyGroupID:%ldn,my_info-pw_gid);printf(MyRealName:%sn,my_info-pw_gecos);printf(MyHomeDir:%sn,my_info-pw_dir);printf(MyWorkShell:%sn,my_info-pw_shell);进程控制相关的APIpid_tfork();pid_twait(int*stat_loc);pid_twaitpid(pid_tpid,int*stat_loc,intoptions);exec族APIintexecl(constchar*path,constchar*arg,.);intexeclp(constchar*file,constchar*arg,.);intexecle(constchar*path,constchar*arg,.);intexecv(constchar*path,char*constargv);intexecvp(constchar*file,char*constargv):voidmain(void)pid_tchild;intstatus;printf(Thiswilldemostratehowtogetchildstatusn);if(child=fork()=-1)printf(ForkError:%sn,strerror(errno);exit(1);elseif(child=0)inti;printf(Iamthechild:%ldn,getpid();for(i=0;i0)while(1);if(kill(getppid(),SIGTERM)=-1)printf(KillParentError:%sn,strerror(errno);exit(1);intmailfd;while(1)if(mailfd=open(MAIL,O_RDONLY)!=-1)fprintf(stderr,%s,7);close(mailfd);sleep(SLEEP_TIME);文件相关的APIintopen(constchar*pathname,intflags);intopen(constchar*pathname,intflags,mode_tmode);intclose(intfd);ssize_tread(intfd,void*buffer,size_tcount);ssize_twrite(intfd,constvoid*buffer,size_tcount);文件复制示例#defineBUFFER_SIZE1024intmain(intargc,char*argv)intfrom_fd,to_fd;intbytes_read,bytes_write;charbufferBUFFER_SIZE;char*ptr;if(argc!=3)fprintf(stderr,Usage:%sfromfiletofilena,argv0);exit(1);/*打开源文件*/if(from_fd=open(argv1,O_RDONLY)=-1)fprintf(stderr,Open%sError:%sn,argv1,strerror(errno);exit(1);/*创建目的文件*/if(to_fd=open(argv2,O_WRONLY|O_CREAT,S_IRUSR|S_IWUSR)=-1)fprintf(stderr,Open%sError:%sn,argv2,strerror(errno);exit(1);/*以下代码是一个经典的拷贝文件的代码*/while(bytes_read=read(from_fd,buffer,BUFFER_SIZE)if(bytes_read=-1)&(errno!=EINTR)break;/*发生了错误*/elseif(bytes_read0)ptr=buffer;while(bytes_write=write(to_fd,ptr,bytes_read)if(bytes_write=-1)&(errno!=EINTR)break;/*发生了错误*/elseif(bytes_write=bytes_read)break;/*写完了所有读的字节*/elseif(bytes_write0)/*只写了一部分,继续写*/ptr+=bytes_write;bytes_read-=bytes_write;if(bytes_write=-1)break;/*发生了错误*/close(from_fd);close(to_fd);exit(0);取文件的属性intaccess(constchar*pathname,intmode);intstat(constchar*file_name,structstat*buf);intfstat(intfiledes,structstat*buf);文件的属性structstatdev_tst_dev;/*设备*/ino_tst_ino;/*节点*/mode_tst_mode;/*模式*/nlink_tst_nlink;/*硬连接*/uid_tst_uid;/*用户ID*/gid_tst_gid;/*组ID*/dev_tst_rdev;/*设备类型*/off_tst_off;/*文件字节数*/unsignedlongst_blksize;/*块大小*/unsignedlongst_blocks;/*块数*/time_tst_atime;/*最后一次访问时间*/time_tst_mtime;/*最后一次修改时间*/time_tst_ctime;/*最后一次改变时间(指属性)*/;目录文件的操作char*getcwd(char*buffer,size_tsize);intmkdir(constchar*path,mode_tmode);DIR*opendir(constchar*path);structdirent*readdir(DIR*dir);voidrewinddir(DIR*dir);off_ttelldir(DIR*dir);voidseekdir(DIR*dir,off_toff);intclosedir(DIR*dir);staticintget_file_size_time(constchar*filename)structstatstatbuf;if(stat(filename,&statbuf)=-1)printf(Getstaton%sError:%sn,filename,strerror(errno);return(-1);if(S_ISDIR(statbuf.st_mode)return(1);if(S_ISREG(statbuf.st_mode)printf(%ssize:%ldbytestmodifiedat%s,filename,statbuf.st_size,ctime(&statbuf.st_mtime);return(0);目录文件的操作示例intmain(intargc,char*argv)DIR*dirp;structdirent*direntp;intstats;if(argc!=2)printf(Usage:%sfilenamena,argv0);exit(1);if(stats=get_file_size_time(argv1)=0)|(stats=-1)exit(1);if(dirp=opendir(argv1)=NULL)printf(OpenDirectory%sError:%sn,argv1,strerror(errno);exit(1);while(direntp=readdir(dirp)!=NULL)if(get_file_size_time(direntp-d_name)closedir(dirp);exit(1);管道文件intpipe(intfildes2);intdup2(intoldfd,intnewfd);管道示例#defineBUFFER255intmain(intargc,char*argv)charbufferBUFFER+1;intfd2;if(argc!=2)fprintf(stderr,Usage:%sstringna,argv0);exit(1);if(pipe(fd)!=0)fprintf(stderr,PipeError:%sna,strerror(errno);exit(1);if(fork()=0)close(fd0);printf(Child%dWritetopipena,getpid();snprintf(buffer,BUFFER,%s,argv1);write(fd1,buffer,strlen(buffer);printf(Child%dQuitna,getpid();exit(0);elseclose(fd1);printf(Parent%dReadfrompipena,getpid();memset(buffer,BUFFER+1);read(fd0,buffer,BUFFER);printf(Parent%dRead:%sn,getpid(),buffer);exit(1);重定向示例#defineBUFFER_SIZE1024intmain(intargc,char*argv)intfd;charbufferBUFFER_SIZE;if(argc!=2)fprintf(stderr,Usage:%soutfilenamena,argv0);exit(1);if(fd=open(argv1,O_WRONLY|O_CREAT|O_TRUNC,S_IRUSR|S_IWUSR)=-1)fprintf(stderr,Open%sError:%sna,argv1,strerror(errno);exit(1);if(dup2(fd,STDOUT_FILENO)=-1)fprintf(stderr,RedirectStandardOutError:%sna,strerror(errno);exit(1);fprintf(stderr,Now,pleaseinputstring);fprintf(stderr,(ToquituseCTRL+D)n);while(1)fgets(buffer,BUFFER_SIZE,stdin);if(feof(stdin)break;write(STDOUT_FILENO,buffer,strlen(buffer);exit(0);unix中的信号1)SIGHUP2)SIGINT3)SIGQUIT4)SIGILL5)SIGTRAP6)SIGABRT7)SIGBUS8)SIGFPE9)SIGKILL10)SIGUSR111)SIGSEGV12)SIGUSR213)SIGPIPE14)SIGALRM15)SIGTERM17)SIGCHLD18)SIGCONT19)SIGSTOP20)SIGTSTP21)SIGTTIN22)SIGTTOU23)SIGURG24)SIGXCPU25)SIGXFSZ26)SIGVTALRM27)SIGPROF28)SIGWINCH29)SIGIO30)SIGPWR产生信号的APIintkill(pid_tpid,intsig);intraise(intsig);unisignedintalarm(unsignedintseconds);信号的处理方式默认:大多数情况下,收到信号的进程会结束忽略:忽略收到的信号,就像没有收到一样捕获:收到信号的进程暂停当前执行的语句,转向执行自己定义的一个函数屏蔽:暂时不理睬收到的信号,等到合适的时机再处理信号的一个简单示例main()unsignedinti;alarm(1);for(i=0;1;i+)printf(I=%d,i);屏蔽信号的相关APIintsigemptyset(sigset_t*set);intsigfillset(sigset_t*set);intsigaddset(sigset_t*set,intsigno);intsigdelset(sigset_t*set,intsigno);intsigismember(sigset_t*set,intsigno);intsigprocmask(inthow,constsigset_t*set,sigset_t*oset);信号屏蔽示例intmain(intargc,char*argv)doubley;sigset_tintmask;inti,repeat_factor;if(argc!=2)fprintf(stderr,Usage:%srepeat_factorna,argv0);exit(1);if(repeat_factor=atoi(argv1)1)repeat_factor=10;sigemptyset(&intmask);/*将信号集合设置为空*/sigaddset(&intmask,SIGINT);/*加入中断Ctrl+C信号*/while(1)/*阻塞信号,我们不希望保存原来的集合所以参数为NULL*/sigprocmask(SIG_BLOCK,&intmask,NULL);fprintf(stderr,SIGINTsignalblockedn);for(i=0;irepeat_factor;i+);fprintf(stderr,Blockedcalculationisfinishedn);/*取消阻塞*/sigprocmask(SIG_UNBLOCK,&intmask,NULL);fprintf(stderr,SIGINTsignalunblockedn);for(i=0;irepeat_factor;i+);fprintf(stderr,Unblockedcalculationisfinishedn);exit(0);改变信号的处置方式intsigaction(intsigno,conststructsigaction*act,structsigaction*oact);structsigactionvoid(*sa_handler)(intsigno);sigset_tsa_mask;intsa_flags;捕获信号示例#definePROMPT你想终止程序吗?char*prompt=PROMPT;voidctrl_c_op(intsigno)write(STDERR_FILENO,prompt,strlen(prompt);intmain()structsigactionact;act.sa_handler=ctrl_c_op;sigemptyset(&act.sa_mask);act.sa_flags=0;if(sigaction(SIGINT,&act,NULL)0)fprintf(stderr,InstallSignalActionError:%sna,strerror(errno);exit(1);while(1);intpause(void);intsigsuspend(constsigset_t*sigmask);intsigsetjmp(sigjmp_bufenv,intval);voidsiglongjmp(sigjmp_bufenv,intval);信号原子性问题检查邮件的后台程序/*Linux的默任个人的邮箱地址是/var/spool/mail/*/#defineMAIL_DIR/var/spool/mail/*睡眠10秒钟*/#defineSLEEP_TIME10#defineMAX_FILENAME255unsignedcharnotifyflag=1;longget_file_size(constchar*filename)structstatbuf;if(stat(filename,&buf)=-1)if(errno=ENOENT)return0;elsereturn-1;return(long)buf.st_size;voidsend_mail_notify(void)fprintf(stderr,Newmailhasarrived7n);voidturn_on_notify(intsigno)notifyflag=1;voidturn_off_notify(intsigno)notifyflag=0;intcheck_mail(constchar*filename)longold_mail_size,new_mail_size;sigset_tblockset,emptyset;sigemptyset(&blockset);sigemptyset(&emptyset);sigaddset(&blockset,SIGUSR1);sigaddset(&blockset,SIGUSR2);old_mail_size=get_file_size(filename);if(old_mail_size0)send_mail_notify();sleep(SLEEP_TIME);while(1)if(sigprocmask(SIG_BLOCK,&blockset,NULL)0)return1;while(notifyflag=0)sigsuspend(&emptyset);if(sigprocmask(SIG_SETMASK,&emptyset,NULL)old_mail_size)send_mail_notify;old_mail_size=new_mail_size;sleep(SLEEP_TIME);intmain(void)charmailfileMAX_FILENAME;structsigactionnewact;structpasswd*pw;if(pw=getpwuid(getuid()=NULL)fprintf(stderr,GetLoginNameError:%sna,strerror(errno);exit(1);strcpy(mailfile,MAIL_DIR);strcat(mailfile,pw-pw_name);newact.sa_handler=turn_on_notify;newact.sa_flags=0;sigemptyset(&newact.sa_mask);sigaddset(&newact.sa_mask,SIGUSR1);sigaddset(&newact.sa_mask,SIGUSR2);if(sigaction(SIGUSR1,&newact,NULL)0)fprintf(stderr,TurnOnError:%sna,strerror(errno);newact.sa_handler=turn_off_notify;if(sigaction(SIGUSR1,&newact,NULL)0)fprintf(stderr,TurnOffError:%sna,strerror(errno);check_mail(mailfile);exit(0);POSIX无名信号量intsem_init(sem_t*sem,intpshared,unsignedintvalue);/创建一个信号灯,并初始化其值为value.pshared决定了信号量能否在几个进程间共享.由于目前Linux还没有实现进程间共享信号灯,所以这个值只能够取0intsem_destroy(sem_t*sem);/删除信号灯intsem_wait(sem_t*sem);/阻塞进程,直到信号灯的值大于0intsem_trywait(sem_t*sem);intsem_post(sem_t*sem);/+1intsem_getvalue(sem_t*sem);SystemV信号量key_tftok(char*pathname,charproj);intsemget(key_tkey,intnsems,intsemflg);intsemctl(intsemid,intsemnum,intcmd,unionsemunarg);intsemop(intsemid,structsembuf*spos,intnspos);structsembufshortsem_num;/*使用那一个信号*/shortsem_op;/*进行什么操作*/shortsem_flg;/*操作的标志*/;用信号量机制解决哲学家进餐问题#definePhNum5#defineLEFT(PhNum+i-1)%PhNum#defineRIGHT(i+1)%PhNum#defineTHINKING0#defineHUNGRY1#defineEATING2#defineTHINKTIME4#defineEATTIME3unionsemunintval;structsemid_ds*buf;ushort*array;voiddown_op(intsid,ushortsn)structsembufop;op.sem_num=sn;op.sem_op=-1;op.sem_flg=0;semop(sid,&op,1);voidup_op(intsid,ushortsn)structsembufop;op.sem_num=sn;op.sem_op=1;op.sem_flg=0;semop(sid,&op,1);voidthink(inti)printf(Imphilosopher:%d,Imthinkingnow.n,i);sleep(rand()%11);voideat(inti)printf(Imphilosopher:%d,Iwilleat.n,i);sleep(rand()%11);voidtest(inti,char*state,intsid)if(statei=HUNGRY&stateLEFT!=EATING&stateRIGHT!=EATING)statei=EATING;printf(Imphilosopher:%d,Icaneatnown,i);up_op(sid,i);elseif(statei!=HUNGRY)printf(Imphilosopher:%d,Idontwanttoeatn,i);elseprintf(Imphilosopher:%d,Icanteatnow!n,i);voidtake_forks(inti,char*state,intsid)down_op(sid,PhNum);statei=HUNGRY;printf(Imphilosopher:%d,Imhungry.CanIeatnow?n,i);test(i,state,sid);up_op(sid,PhNum);down_op(sid,i);voidput_forks(inti,char*state,intsid)down_op(sid,PhNum);statei=THINKING;printf(Imphilosopher:%d,myeatingfinished,Somyneighbourscaneat.n,i);test(LEFT,state,sid);test(RIGHT,state,sid);up_op(sid,PhNum);voidphilosopher(inti,char*state,intsid)while(1)think(i);take_forks(i,state,sid);eat(i);put_forks(i,state,sid);intmain(intargc,char*argv)intsemid,shmid,i,pid,mynum;char*state;unionsemunse;/信号量集合sestructshmid_dssid_d;ushortarrayPhNum+1;key_tipc_key;ipc_key=ftok(.,s);/获取一个key_t类型的key/创建信号量集合if(semid=semget(ipc_key,PhNum+1,0600|IPC_CREAT)=-1)perror(Semgeterror!);/Createrror!exit(1);if(shmid=shmget(IPC_PRIVATE,PhNum,0600|IPC_CREAT)=-1)/创建一块共享内存,用于保存几位哲学家的状态semctl(semid,0,IPC_RMID,se);/删除信号量标识关联的信号集合perror(Shmgeterror!);exit(1);/*设置参数(union)到初始化向量的地址*/arrayPhNum=1;for(i=0;iPhNum;i+)arrayi=0;se.array=array;if(semctl(semid,PhNum+1,SETALL,se)=-1)/初始化信号集合se中所有信号量的值semctl(semid,0,IPC_RMID,se);/删除信号量标识关联的信号集合shmctl(shmid,IPC_RMID,&sid_d);/删除共享内存标识符shmid指向的系统数据结构perror(semctl:SETALL!);exit(3);/*共享内存操作*/if(state=shmat(shmid,0,0)=(char*)-1)/刚才创建好的共享内存附接到进程的地址空间semctl(semid,0,IPC_RMID,se);shmctl(shmid,IPC_RMID,&sid_d);perror(Shmaterror!);exit(1);for(i=0;iPhNum;i+)statei=THINKING;/*initializeallthephilospherarethinking.*/for(i=1;i=PhNum;i+)while(pid=fork()=-1);if(!pid)/子进程mynum=i-1;break;/回收IPC资源if(pid)wait(NULL);semctl(semid,0,IPC_RMID,se);shmdt(state);shmctl(shmid,IPC_RMID,&sid_d);printf(nAllisover.n);elsephilosopher(mynum,state,semid);return0;SystemV消息队列intmsgget(key_tkey,intmsgflg);intmsgsnd(intmsgid,structmsgbuf*msgp,intmsgsz,intmsgflg);intmsgrcv(intmsgid,structmsgbuf*msgp,intmsgsz,longmsgtype,intmsgflg);intmsgctl(Intmsgid,intcmd,structmsqid_ds*buf);structmsgbuflongmsgtype;/*消息类型*/./*其他数据类型*/服务器端#defineMSG_FILEserver.c#defineBUFFER255#definePERMS_IRUSR|S_IWUSRstructmsgtypelongmtype;charbufferBUFFER+1;intmain()structmsgtypemsg;key_tkey;intmsgid;if(key=ftok(MSG_FILE,a)=-1)fprintf(stderr,CreatKeyError:%san,strerror(errno);exit(1);服务器端if(msgid=msgget(key,PERM|IPC_CREAT|IPC_EXCL)=-1)fprintf(stderr,CreatMessageError:%san,strerror(errno);exit(1);while(1)msgrcv(msgid,&msg,sizeof(structmsgtype),1,0);fprintf(stderr,ServerReceive:%sn,msg.buffer);msg.mtype=2;msgsnd(msgid,&msg,sizeof(structmsgtype),0);exit(0);客户端(client.c)#defineMSG_FILEclient.c#defineBUFFER255#definePERMS_IRUSR|S_IWUSRstructmsgtypelongmtype;charbufferBUFFER+1;intmain(intargc,char*argv)structmsgtypemsg;key_tkey;intmsgid;if(argc!=2)fprintf(stderr,Usage:%sstringna,argv0);exit(1);客户端(client.c)if(key=ftok(MSG_FILE,a)=-1)fprintf(stderr,CreatKeyError:%san,strerror(errno);exit(1);if(msgid=msgget(key,PERM)=-1)fprintf(stderr,CreatMessageError:%san,strerror(errno);exit(1);msg.mtype=1;strncpy(msg.buffer,argv1,BUFFER);msgsnd(msgid,&msg,sizeof(structmsgtype),0);memset(&msg,sizeof(structmsgtype);msgrcv(msgid,&msg,sizeof(structmsgtype),2,0);fprintf(stderr,Clientreceive:%sn,msg.buffer);exit(0);