函数原型
char *gets(char *buf) char *fgets(char *buf,int n,FILE *fp)
gets标准输入读,fgets从指定流中读。
gets是一个不推荐使用的函数,理由是可能造成缓冲区的溢出。
fgets从指定流中一直读到换行符为止,读入的数据放入buf中。缓冲区的数据以NULL字符结尾!也就是说会多写一个字符(NULL)。如果待读的数据比n要大,则只读取n-1个字节的数据,最后以NULL结尾,下次调用会继续读该行。
说明,因为读到的数据以NULL结尾,那么就可以使用strlen(buf)获得所读取的数据的大小。strlen接受一个char*类型的指针,计算出从这个地址开始直到NULL(即 )的长度,不包括NULL。
2 puts与fputs函数原型
int puts(const char *str) int fputs(const chat *str,FILE *fp)
fputs将一个以NULL(即 )字符终止的字符串写入指定的流,尾端的NULL不输出。
puts将一个以NULL结尾的字符串写到标准输出,终止符不写出。但是,与fputs不同的是,随后puts又将一个换行符写到标准输出。
puts()和 printf的用法一样,puts()函数的作用与语句“printf("%sn",s);的作用相同。注意:puts在输出字 符串后会自动输出一个回车符。
虽然这是每行IO,但是他的输出和行却一点关系没有,puts和fputs可以看作仅仅是一个字符串输出工具。
3 snprintfint snprintf(char *str, size_t size, const char *format, ...);
将可变个参数(…)按照format格式化成字符串,然后将其复制到str中
(1) 如果格式化后的字符串长度 < size,则将此字符串全部复制到str中,并给其后添加一个字符串结束符(’ ’);
(2) 如果格式化后的字符串长度 => size,则只将其中的(size-1)个字符复制到str中,并给其后添加一个字符串结束符(’ ’)
函数返回值:若成功则返回欲写入的字符串长度,若出错则返回负值。
4 read读文件,结束符是什么,当read遇到‘ ’会怎么样 ?注意:read和write是不区分’ ’的!他们读写只会按照给定的字节读写,没有结束标志符。停止读写的原因只能是缓冲区超出,或者缓冲区为零!总之不受’ ’的影响。
其实,可以把文件的内容看做是字符串!读写文件就是读写里面的字符(一个字节大小).
这里结合socket,给出一个实例,验证linux中输入输出函数的特性:
这个例子是回射程序,客户端在终端上中输出一行数据,然后服务器接受这个数据,再将其返回,客户端收到后再显示在终端上。
//echo_client.c #include#include #include #include #include #include #include #include #include #define BUFSIZE 512 void str_cli(FILE * fp,int sockfd); int main (int argc,char **argv) { int sd; int n; struct sockaddr_in servaddr; char buf[BUFSIZ]; if (argc!=2) { printf("argc is not 2n"); exit(1); } bzero(&servaddr,sizeof(servaddr)); servaddr.sin_family=AF_INET; servaddr.sin_port=htons(2222); if(inet_pton(AF_INET,argv[1],&servaddr.sin_addr)<0) { perror("inet_pton errorn"); exit(1); } sd=socket(AF_INET,SOCK_STREAM,0); if(connect(sd,(struct sockaddr*)&servaddr,sizeof(servaddr))<0) { perror("connect is errorn"); exit(1); } str_cli(stdin,sd); exit(0); } void str_cli(FILE * fp,int sockfd) { char sendline[BUFSIZE]; char receline[BUFSIZE]; char a; int n,n2; sendline[8]='8'; sendline[9]='9'; while(1) { fgets(sendline,BUFSIZE,fp);//输入123后回车,实际写入5个字节:"123n ",因为fgets不会丢弃换行符! printf("strlen of senline is %ld",strlen(sendline));//结果是4,strlen遇到NUll就结束 printf("the neirong of sendline is %s",sendline);//此时可知sendline中的内容是:“123n xxxxxxxx...” x指的是系统的随机数。,但这里输出是123n,因为%s遇到NULL就结束 n=write(sockfd,sendline,strlen(sendline)+1);//写进去5个字节,也就是“123n ”,这里不能写strlen(senline),因为没有将结束符写进去,这样会导致后面服务器发来的消息也没有结束符,所以后面的fputs就会找不到在哪结束!!! printf("the n write is %d",n);//n=5 n2=read(sockfd,receline,BUFSIZE); printf("the num read n2 is %d",n2); fputs(receline1,stdout); } return ; }
//echo_server.c #include#include #include #include #include #include #include #include #include #include #define BUFSIZE 1024 void str_echo(int confd); int main() { int sd; pid_t pid; int confd; socklen_t len; time_t tick; char buf[BUFSIZE]; char buf_addr[BUFSIZE]; struct sockaddr_in cliaddr,servaddr; bzero(&servaddr,sizeof(servaddr)); servaddr.sin_family=AF_INET; servaddr.sin_port=htons(2222); //servaddr.sin_addr.s_addr=htonl(INADDR_ANY); inet_pton(AF_INET,"0.0.0.0",&servaddr.sin_addr.s_addr);//带或不带s_addr都可以 sd=socket(AF_INET,SOCK_STREAM,0); if(sd<0) { perror("socket is errorn"); exit(1); } if(bind(sd,(struct sockaddr *)&servaddr,sizeof(servaddr))<0) { perror("bind errorn"); close(sd);//实际上exit会自动关闭所有的文件描述符,所以不写这一步也可以 exit(1); } if(listen(sd,5)<0) { perror("listen is errorn"); close(sd); exit(1); } while(1) { len=sizeof(cliaddr); confd=accept(sd,(struct sockaddr *)&cliaddr,&len); //打印对端客户端信息,IP地址和端口 printf("connection from :%s,port is %dn", inet_ntop(AF_INET,&cliaddr.sin_addr.s_addr,buf_addr,sizeof(buf_addr)),ntohs(cliaddr.sin_port)); pid=fork(); if(pid==0) { close(sd); str_echo(confd); exit(0); } close(confd); } } void str_echo(int confd) { int n; char buf[BUFSIZE]; while(1) { n=read(confd,buf,BUFSIZE);//会读到5个字节,因为客户端只写入了5个字节,read读完缓冲区就返回。 printf("n is %dn",n);//n=5 print("read byte is %s",buf);//此时buf中的内容会是“123n xxxxxxxx...”,但是这一行的输出会是123n,因为%s遇到NULL就停下 if(n<0 && errno==EINTR) { continue; } else if(n>0) { //write(confd,buf,BUFSIZE);//这个地方一定不能写入BUFSIZE个数据!!!,否则客户端的read会把这1024(BUFSIZE的大小)全部读出!!! write(confd,buf,n);//这才是正确的,读到几个字节,返回几个字节 } else { perror("read error:n"); exit(1); } } return ; }
注意:
-
这里牵涉待的一个点就是,读的时候可以读BUFSIZE个字节的数据,但是写的时候最好加上结束符,这样的话,就是写入固定大小的数据,read不用读完BUFSIZE个字节就能读完缓冲区返回!
-
所以,以后规定,读可以读BUFSZIE,但是写的内容要严格规范,不能简单的写进BUFSZIE个字节,否则,read会没完没了的读!



