Lin 程序设计教程 答案_第1页
Lin 程序设计教程 答案_第2页
Lin 程序设计教程 答案_第3页
Lin 程序设计教程 答案_第4页
Lin 程序设计教程 答案_第5页
已阅读5页,还剩23页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第1章一、选择题题号答案题号答案1B7C2C8D3A9D4B10A5A11C6B12B二、简答题1.简述Linux系统的各种版本的命名方式。第一种方式用于1.0版本之前(包括1.0)。第一个版本是0.01,紧接着是0.02、0.03、0.10、0.11、0.12、0.95、0.96、0.97、0.98、0.99和之后的1.0。第二种方式用于1.0版本之后到2.6版本,数字由3部分“A.B.C”组成,A代表主版本号,B代表次主版本号,C代表较小的末版本号。第三种方式从2004年的2.6.0版本开始使用。2.6版本采用“A.B.C.D”形式;C随着新版本的发布而增加,D代表一些bug修复、安全更新、新特性和驱动的次数。3.0版本之后采用“A.B.C”格式,B随着新版本的发布而增加,C代表一些bug修复、安全更新、新特性和驱动的次数。第三种方式中不再使用偶数代表稳定版本、奇数代表开发版本的命名方式。2.简述Linux系统的特点。(1)开放性。(2)多用户。(3)多任务。(4)良好的用户界面(5)设备独立性(6)丰富的网络功能(7)可靠的系统安全(8)良好的可移植性3.简述系统调用与库函数的区别和联系。联系:系统调用和库函数都以C函数形式出现,提供给用户一种功能实现的接口,需要用户输入指定的参数,调用结束得到指定的返回值。区别:系统调用是程序获得内核服务的接口,库函数是在系统调用上层的函数,有的库函数是需要调用一个或多个系统调用来实现的。4.完成如下命令(1)新建用户tom和用户组student#useraddtom#passwdtom#groupaddstudent(2)新建文件file#touchfile(3)将文件file改名为test,然后将test拷贝到/home#mvfiletest#cptest/home(4)将/home/test文件的拥有着修改为tom,将文件所属组该为student#chowntom:student/home/test第2章一、填空题1.插入模式、命令模式、末行模式。2.预处理、编译、汇编、链接。3.Makefile4.make5.静态库,共享库二、选择题题号答案题号答案1B7A2D8C3B9A4D10C5B11C6C12B三、简答题1.静态库与共享库有什么区别?(1)静态库文件以.a结尾,共享库文件以.so结尾。(2)静态库的代码在编译时就已连接到应用程序中,共享库只是在程序开始运行时才载入,在编译时,只是简单地指定需要使用的库函数。(3)静态库生成的可执行文件可以直接运行,共享库生成的可执行文件需要提供共享库才能运行。(4)静态库生成的可执行文件相对比较大,共享库生成的可执行文件相对比较小。2.Makefile文件的显式规则是什么?目标文件:依赖文件列表<tab>更新目标文件使用的命令四、编程题1.编写makefile:当前目录下有文件a1.ca2.ca3.c,其中a1.c中带有main函数,其他文件为用户自定义函数供main函数调用,编写完成对这几个文件的编译工作生成可执行文件aCC=gccBIN=a$(BIN):a1.oa2.oa3.o$(CC)-o$(BIN)$^a1.o:a1.c$(CC)-ca1.ca2.o:a2.c$(CC)-ca2.ca3.o:a3.c$(CC)-ca3.cclean:rm-f*.o$(BIN)2.编写makefile:当前目录下有很多独立的程序文件:aa.cbb.Ccc.c(即每个文件中都有main函数),分别要生成对应的我可执行文件aabbcc,为了方便用户操作,写一个makefile使得调用make命令会重新编译最新修改的程序文件CC=gccALL:aabbccaa:aa.c$(CC)-oaaaa.cbb:bb.c$(CC)-obbbb.ccc:cc.c$(CC)-occcc.cclean:rm-faabbcc第3章一、选择题题号答案题号答案题号答案题号答案题号答案1C7B13B19D25C2A8C14B20D26B3B9D15C21A4C10C16B22B5B11C17C23D6A12A18D24A二、填空题main命令行参数个数,指向各命令行参数字符串的指针数组time_t类型、structtm类型、字符串形式time_t,1970年1月1日零时到当前时间的秒数localtimectimestructtm,time_t“-f”三、编程题1.如果一个用户输入一个参数,则打印“noargs”,如果输入两个参数并且第二个命令行参数是-a,则打印“Iwilldealwith-a”,如果是-l则打印“Iwilldealwith-l”#include<stdio.h>intmain(intargc,char*argv[]){ if(argc==1) printf("noargs\n"); elseif(argc==2) { if(strcmp(argv[1],"-a")==0) printf("Iwilldealwith-a\n"); if(strcmp(argv[1],"-l")==0) printf("Iwilldealwith-l\n"); } return0;}2.获取当前系统的时间,并按命令date的显示方式显示出来。#include<stdio.h>#include<stdlib.h>#include<time.h>/**调用localtime获取Linux系统日期时间*/intmain(intargc,char*argv[]){ time_tt; structtm*p_tm; time(&t); p_tm=localtime(&t); printf("%d年%d月%d日%d时%d分%d秒\n", p_tm->tm_year+1900, p_tm->tm_mon+1, p_tm->tm_mday, p_tm->tm_hour, p_tm->tm_min, p_tm->tm_sec); return0;}3.由用户输入年、月、日、时、分、秒,并将该时间设置为系统时间。#include<stdio.h>#include<stdlib.h>#include<time.h>/**此例程为调用stime设置Linux系统日期时间*注意:stime需要root权限*/chartip[]="需要输入年月日时分秒6个参数\n";intmain(intargc,char*argv[]){ if(argc==7){ time_tt; structtm*p_tm; time(&t); p_tm=localtime(&t); intyear=strtol(argv[1],NULL,10); intmon=strtol(argv[2],NULL,10); intday=strtol(argv[3],NULL,10); inthour=strtol(argv[4],NULL,10); intmin=strtol(argv[5],NULL,10); intsec=strtol(argv[6],NULL,10); printf("%d%d%d%d%d%d",year,mon,day,hour,min,sec); p_tm->tm_year=year-1900; p_tm->tm_mon=mon-1; p_tm->tm_mday=day-1; p_tm->tm_hour=hour; p_tm->tm_min=min; p_tm->tm_sec=sec; t=mktime(p_tm); stime(&t); }else{ printf("%s\n",tip); } return0;}第4章一、选择题题号答案题号答案题号答案1B7C13B2B8C14C3C9A4C10B5A11D6B12B二、填空题STDIN_FILENO、STDOUT_FILENO、STDERR_FILENO,0,1,2rw--wxr-x,S_IRUSR|S_IWUSR|S_IWGRP|S_IXGRP|S_IROTH|S_IXOTH打开或创建文件O_RDONLY、O_WRONLY、O_RDWR。下一次读或写的位置-4,SEEK_CURO_TRUNC,truncate644,755642,7530724,O_RUSR|O_WUSR|O_XUSR|O_WGRP|O_ROTHr---w---x,0421三、简答题1.Linux文件类型主要有哪七类?常规文件、目录文件、字符设备文件、块设备文件、管道文件、链接文件、套接字文件2.简述文件、inode、文件名、目录之间的关系。每个存在磁盘上的文件都由i节点和数据块两部分组成,i节点和文件一一对应,一个i节点可以对应多个文件名,文件名和i节点的对应关系叫做文件的硬链接,文件名和i节点的对应关系保存在目录文件中。3.什么是文件描述符?(1)一个非负整数,内核以此来标识一个特定进程正在操作的文件。(2)012代表三个标准的文件描述符,分别为标准输入、标准输出、标准错误输出4.使用符号方式表示rwxrwxrwx权限S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH5.写出open以下6种打开标志:只读、只写、读写、追加、文件不存在创建、截断为0O_RDONLYO_WRONLYO_RDWRO_APPENDO_CREATO_TRUNC6.读程序,写出执行结果并解释得到该结果的原因main(){ intfd1,fd2; fd1=open(“/etc/passwd”,O_RDONLY); fd2=open(“/etc/passwd”,O_RDWR); printf(“fd1=%d,fd2=%d\n”,fd1,fd2); close(fd1); close(fd2);}结果:fd1=3fd2=4原因:open返回的文件描述符为最小可用的非负整数,012是三个标准的文件描述符默认已经被占用,所以第一个open的返回值为3,第二个open返回的是4。四、编程题1.向文件f1中写入“helloworld!”,然后再将f1中的内容读出并显示在屏幕上。(注意必要的错误判断)#include<unistd.h>#include<sys/stat.h>#include<sys/fcntl.h>intmain(){ intfd; charbuf1[13]={"helloworld!"}; charbuf2[12]; intnum; fd=open("f1",O_RDWR|O_CREAT|O_TRUNC,0644); if(fd==-1) {perror("f1notopen"); exit(1); } num=write(fd,buf1,sizeof(buf1)-1); if(num!=(sizeof(buf1)-1))printf("writelessthanwant\n"); lseek(fd,0,SEEK_SET); num=read(fd,buf2,12); if(num!=12) printf("readlessthan12\n"); write(1,buf2,12); close(fd);}2.向文件f2中写入“aabbccddee”,然后将偏移量移到绝对值偏移为4的位置处,读6个字符,并将结果显示在屏幕上#include<unistd.h>#include<sys/stat.h>#include<sys/fcntl.h>intmain(){ intfd; charbuf1[11]={"aabbccddee"}; charbuf2[10]; intnum; fd=open("f2",O_RDWR|O_CREAT|O_TRUNC,0644); if(fd==-1) {perror("f2notopen"); exit(1); } num=write(fd,buf1,sizeof(buf1)-1); if(num!=(sizeof(buf1)-1)) printf("writelessthanwant\n"); lseek(fd,4,SEEK_SET); num=read(fd,buf2,6); if(num!=6) printf("readlessthan6\n"); write(1,buf2,6); close(fd);}3.向文件f3中写入“aabbccddeeffgghh”,然后将文件截短后的文件内容读出并显示在屏幕上#include<unistd.h>#include<sys/stat.h>#include<sys/fcntl.h>intmain(){ intfd; charbuf1[17]={"aabbccddeeffgghh"}; charbuf2[8]; intnum; fd=open("f3",O_RDWR|O_CREAT|O_TRUNC,0644); if(fd==-1) {perror("f3notopen"); exit(1); } num=write(fd,buf1,sizeof(buf1)-1); if(num!=(sizeof(buf1)-1)) printf("writelessthanwant\n"); lseek(fd,0,SEEK_SET); ftruncate(fd,8); num=read(fd,buf2,8); if(num!=8) printf("readlessthan8\n"); write(1,buf2,8); close(fd);}4.在程序中将umask改至044,创建文件f4#include<unistd.h>#include<sys/stat.h>#include<sys/fcntl.h>intmain(){ intfd; umask(044); creat("f4",S_IRUSR|S_IWUSR);}5.实现“cat文件名”显示文件内容#include<fcntl.h>main(intargc,char*argv[]){intfd;intnum;charbuf[10];if(argc!=2){printf("missfilename\n");exit(1);}fd=open(argv[1],O_RDONLY);if(fd==-1){perror("erroropen");exit(1);}while((num=read(fd,buf,10))!=0)write(1,buf,num); close(fd);}6.实现“cp原文件目标文件”#include<sys/stat.h>#include<fcntl.h>main(intargc,char*argv[]){intfrom,to;intnum;charbuf[10];if(argc!=3){printf("argumenterror\n");exit(1);}from=open(argv[1],O_RDONLY);to=open(argv[2],O_WRONLY|O_CREAT|O_TRUNC,0644);num=read(from,buf,10);while(num!=0){ write(to,buf,num); num=read(from,buf,10);}close(from);close(to);}第5章一、选择题题号答案题号答案1C7B2A8A3B9C4C10A5B11D6C12A二、填空题umasklink,symlinkgetcwdstat或fstat或lstat更改文件权限,更改文件所有者和所属组,更改文件访问时间和修改时间dup2(6,1)三、判断并解释原因1.错2.错3.错4.错5.错四、简答题1.回答stat、fstat、latat三个系统调用的区别stat根据路径获得文件元数据信息fstat根据文件描述符获得文件元数据信息前两者如果遇到符号链接文件则会一直引用至非符号链接文件lstat获得符号链接文件本身的文件元数据信息2.dup和dup2的区别和联系联系:dup与dup2都用来将新文件描述符指向原来文件描述符指向的打开文件描述。区别:dup返回的新文件描述符为最小可用的文件描述符,dup2返回的新文件描述符可以通过第二个参数指定。3.硬链接和符号链接的区别(1)命令ln原文件硬链接文件(不能对目录创建硬链接)ln–s原文件/目录符号链接文件(2)是否新增文件:硬链接不增文件,符号链接增加文件。(3)删除原文件/目录硬链接:对应i节点链接数-1。符号链接:符号链接文件失效。(4)删除链接文件删除硬链接文件,使对应i节点的链接数-1。删除符号链接文件,对原文件/目录无任何影响(5)是否跨文件系统:硬链接不可以,符号链接可以五、编程题1.编写程序pro3.c,将字符串“helloworld”通过输出重定向方式写入文件f1中#include<stdio.h>#include<unistd.h>#include<fcntl.h>#include<sys/stat.h>#include<sys/types.h>main(){ intfd; if((fd=open("f1",O_WRONLY|O_CREAT,0644))==-1) perror("openfail"); if(dup2(fd,1)==-1) perror("Redirectfailed"); printf("Helloworld\n"); close(fd);}3.实现“ls–l文件名功能”参考5.6第6章一、填空题unlink,文件名和文件i节点的对应关系opendir,closedir,readdir改变当前目录mkdir,rmdir二、选择题题号答案1B2A3B4A5D6C7A三、编程题代码略,编程思路:1-4参考案例5和案例6。5参考例6-26-9需要结合第四章、第五章、第六章内容完成。第7章一、选择题题号答案1D2C3CACA二、简答题1.fork与vfork区别?(1)fork创建的子进程复制父进程的整个地址空间(或写时复制),vfork不创建这一副本,子进程借用父进程的地址空间,直到其调用exec族函数或终止;(2)fork创建的子进程和父进程相互独立地运行,而vfork创建子进程后挂起父进程,直到子进程终止或调用exec族函数。2.阅读以下代码,若execlp调用成功的话,“Done!”会打印输出吗?为什么?#include<stdio.h>intmain(){ printf(“Runningpswithexeclp\n”); execlp(“ps”,”ps”,”-af”,0); printf(“Done!\n”); exit(0);}不会输出“Done!”。原因:执行execlp(“ps”,”ps”,”-af”,0)调用成功后,当前进程的地址空间被新的程序ps所替代,将执行“ps-af”三、编程题1.使用fork创建进程,在子进程中打印“Iamthechild”和子进程pid,在父进程中打印“Iamthefather”和父进程pid#include<sys/types.h>#include<stdlib.h>#include<stdio.h>intmain(){pid_tpid;pid=fork();if(pid<0){perror("fork");exit(1);}elseif(pid==0)printf("Iamthechild\n");elseprintf("Iamthefather\n");exit(0);}2.创建子进程,在子进程中执行“ps-A”命令,父进程等待子进程结束后打印“childover”及所处理的子进程进程号#include<sys/types.h>#include<stdlib.h>main(){ pid_tpid,cpid; inti; char*args[64]; args[0]=”ps”; args[1]=”-A”; args[2]=NULL; pid=fork(); if(pid<0) { perror(“fork”); exit(1); } elseif(pid==0) { execvp(args[0],args); exit(0); } else { cpid=wait(NULL); printf(“childover!cpid=%d\n”,cpid); }}第8章一、选择题题号答案题号答案1B7B2C8C3A9C4C10C5B11C6C12B二、编程题1.编程:由用户键盘输入次数n和字符串str,要求在新线程中显示n次str字符串。#include<pthread.h>#include<stdio.h>#include<stdlib.h>#include<unistd.h>structst{ intn; charstr[10];};void*fun(void*arg){ structst*q=(structst*)arg; while(q->n--) puts(q->str); pthread_exit(0);}intmain(){ pthread_ttid; interr; structsts; scanf("%d",&s.n); scanf("%s",s.str); err=pthread_create(&tid,NULL,fun,(void*)&s); if(err) { perror("pthread_create()"); exit(1); } pthread_join(tid,NULL); exit(0);}2.参考答案:Thisispthread1.thesentense1Thisispthread2.thesentense1Thisispthread1.thesentense2Thisispthread2.thesentense2x=11,y=15原因:(1)线程1先运行,线程2后运行。线程1执行sleep(1);后阻塞,线程2继续执行,线程2执行到sleep(1);时线程2阻塞,线程1阻塞结束继续执行,线程1执行结束后线程继续执行到结束。(2)线程1和线程2共享进程的数据段,因此共享变量x,y。第9章一、选择题题号答案题号答案1D7C2B8B3A9B4D10A5A11C6A二、简答题1.进程间通信的6种方式是什么?简述它们的通信原理。(1)信号:用于通知接收进程有某种事件发生。(2)管道:连接一个进程的输出至另一个进程的输入的一种方法。(3)信号量:一个计数器,用来记录对某个资源的使用情况。(4)共享内存:允许多个进程访问同一块内存空间。(5)消息队列:消息的链表,链表中每个节点包括消息类型和正文两部分。(6)套接字:在网络上主机间进程进行通信的方式。2.简述pipe与FIFO的区别与联系。pipe为未命名管道,FIFO为命名管道。联系:pipe和FIFO都是单向传输,一端为读,另一端为写,字符在管道中先进先出。管道空间在内存中。区别:pipe只能在有亲缘关系的进程中使用,如父子进程;FIFO有名字,所以只要知道该名字,无关进程之间也可以使用。3.什么是信号?说明产生信号的几种方式以及进程对信号的处理方式。信号:软中断,被发送给一个正在执行的进程,通知该进程有某一特定事件发生。产生信号的方式有:(1)用户操作。如键盘操作Ctrl-C,最终使得内核产生信号SIGINT。(2)进程执行出错。如浮点数溢出,内核也会产生信号。(3)进程执行某个系统调用。如调用kill向某个进程或进程组发送信号。进程对信号的处理方式有:忽略,捕捉,执行系统默认动作。4.说明信号传递的过程。(1)生成(generating)。内核要更新目标进程的数据结构,表示一个新的信号已经被发送给此进程。此时,进程并没有对信号做出任何响应。(2)传递(delivery)。强迫目标进程对信号做出响应。三、编程题1.编写程序处理SIGINT信号,当程序接收到SIGINT信号后输出“SIGINTiscaught”#include<stdio.h>#include<signal.h>voidsignal_handler(intsignum){switch(signum){caseSIGINT:printf("SIGINTiscaught!\n");break;}}intmain(){signal(SIGINT,signal_handler);pause();return0;}2.略,参考sigprocmask系统调用。3.使用PIPE实现父子进程向子进程发送1234567890,子进程接收并显示#include<sys/types.h>#include<stdio.h>main(){intpfd[2];charbuf[32];pid_tpid;pipe(pfd);if((pid=fork())<0)perror("fork");elseif(pid>0){close(pfd[0]);write(pfd[1],"1234567890",11);}else{close(pfd[1]);read(pfd[0],buf,11);printf("childread:%s\n",buf);}}4.略,主要使用FIFO管道实现。5.略,涉及对SIGALRM信号的捕捉,文件的写入。6.略,使用FIFO管道实现。第10章一、选择题题号答案1C2B3C4A5B二、编程题1.利用信号量时限“生产者-消费者”问题#include<semaphore.h>#include<pthread.h>#include<stdio.h>#defineBUFSIZE50sem_tmutex;sem_tempty;sem_tfull;intbuffer[BUFSIZE];intin=0;intout=0;intproduction=0;intconsume=0;void*producer(){while(1){sem_wait(&empty);sem_wait(&mutex);printf("producer%d\n",production);buffer[in%BUFSIZE]=production;production++;in++;sem_post(&mutex);sem_post(&full);sleep(1);}}void*consumer(){while(1){sem_wait(&full);sem_wait(&mutex);consume=buffer[out%BUFSIZE];out++;printf("consumer%d\n",consume);sem_post(&mutex);sem_post(&empty);}}voidinit_sems(){sem_init(&mutex,0,1);sem_init(&empty,0,50);sem_init(&full,0,0);}voiddestroy_sems(){sem_destroy(&mutex);sem_destroy(&empty);sem_destroy(&full);}intmain(intargc,char*argv[]){init_sems();pthread_tproc;pthread_tcons;pthread_create(&proc,NULL,producer,NULL);pthread_create(&cons,NULL,consumer,NULL);pthread_join(proc,NULL);pthread_join(cons,NULL);destroy_sems();return0;}2.分别利用共享内存和消息队列实现进程Sender向Recesive发送“helloIPC!”。共享内存方式:a)接收端#include<stdio.h>#include<stdlib.h>#include<unistd.h>#include<string.h>#include<sys/types.h>#include<sys/ipc.h>#include<sys/shm.h>#defineSHMSIZE4096intmain(intargc,char*argv[]){intshmid;key_tkey;void*shmptr;key=ftok("key",1);if(argc!=2){printf("shmsrvneedsastring.$shmsrv\"123456\"\n");return1;}if(key==-1){perror("ftokfailed");return-1;}shmid=shmget(key,SHMSIZE,IPC_CREAT|IPC_EXCL|0600);if(shmid==-1){perror("shmgetfailed");return1;}printf("%d\n",shmid);shmptr=shmat(shmid,0,0);if(shmptr==(void*)-1){perror("shmaterror");return1;}memcpy(shmptr,argv[1],strlen(argv[1])+1);if(shmdt(shmptr)==-1){perror("shmdtfailed");return1;}return0;}b)发送端#include<stdio.h>#include<stdlib.h>#include<unistd.h>#include<string.h>#include<sys/types.h>#include<sys/ipc.h>#include<sys/shm.h>#defineSHMSIZE4096intmain(intargc,char*argv[]){ intshmid; key_tkey; void*shmptr; charbuf[SHMSIZE]; key=ftok("key",1); shmid=shmget(key,SHMSIZE,SHM_R|SHM_W); if(shmid==-1) { perror("shmgetfailed"); return1; } shmptr=shmat(shmid,0,0); if(shmptr==(void*)-1) { perror("shmaterror"); return1; } memcpy(buf,shmptr,strlen(shmptr)+1); printf("%s\n",buf); if( shmdt(shmptr)==-1) { perror("shmdtfailed"); return1; } return0;}消息队列方式:略。3.略,使用信号量和共享内存来实现。第11章一、选择题题号答案1C2B3A4D5A6A7B二、简答题1.文字:服务器先启动(1)调用socket函数创建一个套接字s。(2)调用bind函数将s绑定一个地址和端口号。(3)调用listen函数使s成为一个监听套接字。(4)调用accept阻塞等待接收客户端请求,建立与某客户端的连接套接字ns。(5)通过ns,调用读写函数处理某客户端请求(6)终止连接ns。客户端(1)调用socket函数创建一个套接字s1。(2)填写服务器的地址和端口号。(3)调用connect函数与服务器建立连接。(4)调用读写函数与服务器发送或接收数据。(5)终止连接s1。图示:2.文字:服务器(1)调用socket函数创建一个套接字s。(2)调用bind函数将s绑定一个地址和端口号。(3)等待并接收客户端请求。(4)调用读写函数处理客户端请求(5)关闭套接字。客户端(1)调用socket函数创建一个套接字s1。(2)调用读写函数发送或接收数据给服务器。(3)关闭套接字。图示:3.简述监听套接字和连接套接字的区别。监听套接字和连接套接字都是由服务器端产生的。监听套接字可以接受来自客户端的连接请求,socket创建的是主动套接字,listen将主动套接字转换为监听套接字。连接套接字是由accept返回,作用是与客户端通信。三、编程题略,思路:按照TCP套接字通信图示过程完成,服务器根据客户端发来的文件名,查找文件是否存在,如果存在则读取文件,发送给客户端,客户端接收数据,创建文件,并保存内容。第12章1.使用多线程方式编程完成本章的综合案例。以下给出多线程方式完成多客户端与服务器通信的功能,客户端能看到彼此的消息,类似简易聊天室。服务器端://server.c

#include<stdio.h>

#include<string.h>

#include<stdlib.h>

#include<unistd.h>

#include<netinet/in.h>

#include<arpa/inet.h>

#include<sys/socket.h>

#include<pthread.h>

#include<time.h>

#include<fcntl.h>

#include<sys/types.h>

intsockfd;

intcsfd[50];//客户端的socketfd

intsize=50;//聊天室的人数最多为50

char*IP="0.0.0.0";

shortPORT=1888;

typedefstructsockaddrSA;

voidwritefile(intfd,char*str){

time_tt1;

structtm*t2;

charwtxt[100];

t1=time(NULL);

t2=localtime(&t1);

sprintf(wtxt,"%d-%d-%d-%d:%d:%d",t2->tm_year+1900,t2->tm_mon+1,t2->tm_mday,t2->tm_hour,t2->tm_min,t2->tm_sec);

sprintf(wtxt,"%s%s\n",wtxt,str);

write(fd,wtxt,strlen(wtxt));

}

voidsendEach(char*msg){

inti;

for(i=0;i<size;i++){

if(csfd[i]!=0){

printf("sendto%d\n",csfd[i]);

send(csfd[i],msg,strlen(msg),0);

}

}

}

void*service_thread(void*p){

intsfd=*(int*)p;

intfdfile=open("./serverlog",O_WRONLY|O_CREAT|O_APPEND,0644);if(fdfile==-1)perror("openserverlog");

printf("pthread=%d\n",sfd);

while(1){

charbuf[100]={};

if(recv(sfd,buf,sizeof(buf),0)<=0){

inti;

for(i=0;i<size;i++){

if(sfd==csfd[i]){

csfd[i]=0;

break;

}

}

printf("exit:sfd=%dquit\n",sfd);

pthread_exit((void*)i);

}

sendEach(buf);

writefile(fdfile,buf);

}

}

intmain(){

intopt=1;

sockfd=socket(PF_INET,SOCK_STREAM,0);

setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));

if(sockfd==-1){

perror("creatsocketfaild");

exit(-1);

}

structsockaddr_inaddr;

addr.sin_family=PF_INET;

addr.sin_port=htons(PORT);

addr.sin_addr.s_addr=inet_addr(IP);

if(bind(sockfd,(SA*)&addr,sizeof(addr))==-1){

perror("bindfaild");

exit(-1);

}

if(listen(sockfd,100)==-1){

perror("setlistenfaild");

exit(-1);

}

printf("serverstart!\n");

while(1){

structsockaddr_infromaddr;

socklen_tlen=sizeof(fromaddr);

intconnfd=accept(sockfd,(SA*)&fromaddr,&len);

if(connfd==-1){

printf("clientconnectfaild...\n");

continue;

}

inti=0;

for(i=0;i<size;i++){

if(csfd[i]==0){

csfd[i]=connfd;

printf("connfd=%d\n",connfd);

//启动线程给客户

pthread_ttid;

pthread_create(&tid,0,service_thread,&connfd);

break;

}

if(size==i){

//聊天室满

char*str="sorry,fillup!";

send(connfd,str,strlen(str),0);

close(connfd);

}

}

}

}客户端://client.c

#include<stdio.h>

#include<stdlib.h>

#include<string.h>

#include<unistd.h>

#include<sys/s

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论