标准I/O的优点
标准I/O函数的两个优点
--标准I/O函数具有良好的移植性
--标准I/O函数可以利用缓冲提高性能
由上图可看到:使用标准I/O函数传输数据时,经过2个缓冲。例如:通过fputs函数传输字符串时,首先字符串传递到标准I/O函数的输出缓冲,然后数据将移动到套接字输出缓冲,最后将字符串发送到对方主机。
标准I/O函数与系统函数之间的性能对比
分别利用标准I/O函数和系统函数编写文件复制程序,主要为了检验缓冲提高性能的程度。
利用系统函数复制文件的示例:
#include<stdio.h> #include<fcntl.h> #include<unistd.h> #define BUF_SIZE 3 //用最短数组长度构成 int main(int argc,char *argv[]) { int fd1,fd2; //保存在fd1和fd2中的是文件描述符! int len; char buf[BUF_SIZE]; fd1 = open("news.txt",O_RDONLY); fd2 = open("cpy.txt",O_WRONLY | O_CREAT | O_TRUNC); while ((len = read(fd1,buf,sizeof(buf))) > 0) write(fd2,buf,len); close(fd1); close(fd2); return 0; }
采用标准I/O函数复制文件示例:
#include<stdio.h> #define BUF_SIZE 3 //用最短数组长度构成 int main(int argc,char *argv[]) { FILE * fp1; //保存在fp1中的是FILE结构体指针 FILE * fp2; //.... char buf[BUF_SIZE]; fp1 = fopen("news.txt","r"); fp2 = fopen("cpy.txt","w"); while(fgets(buf,BUF_SIZE,fp1) != NULL) fputs(buf,fp2); fclose(fp1); fclose(fp2); return 0; }
fgets和fputs是一种基于缓冲的复制。
标准I/O函数的几个缺点
--不容易进行双向通信
--有时可能频繁调用fflush函数
--需要以FILE结构体指针的形式返回文件描述符
使用标准I/O函数
创建套接字时返回文件描述符,为了使用标准I/O函数,只能将其转换为FILE结构体指针。
利用fdopen函数转换为FILE结构体指针
示例:desto.c
#include<stdio.h> #include<fcntl.h> int main(void) { FILE *fp; int fd = open("data.dat", O_WRONLY | O_CREAT | O_TRUNC); if (fd == -1) { fputs("file open error!",stdout); return -1; } fp = fdopen(fd,"w"); //将fd转换为FILE指针,向第二个参数传递w,因此返回写模式FILE指针 fputs("Network C programming \n",fp); fclose(fp); return 0; }
运行结果:
利用fileno函数转换为文件描述符
此函数与fdopen函数功能相反。
示例:
#include<stdio.h> #include<fcntl.h> int main(void) { FILE *fp; int fd = open("data.dat", O_WRONLY | O_CREAT | O_TRUNC); if (fd == -1) { fputs("file open error",stdout); return -1; } printf("First file description: %d \n",fd); //输出文件描述符整数值 fp = fdopen(fd,"w"); //转化为FILE指针 fputs("TCP/IP SOCKET PROGRAMMING \n",fp); printf("Second file description: %d \n",fileno(fp));//转化为文件描述符,并输出 fclose(fp); return 0; }
运行结果:
基于套接字的标准I/O函数使用
将之前的回声服务器端和客户端改为基于标准I/O函数的数据交换形式。
服务器端:echo_stdserv.c
/* 回声服务器端echo_server.c */ #include<stdio.h> #include<stdlib.h> #include<string.h> #include<unistd.h> #include<arpa/inet.h> #include<sys/socket.h> #define BUF_SIZE 1024 void error_handling(char *message) { fputs(message,stderr); fputc('\n',stderr); exit(1); } int main(int argc,char *argv[]) { int serv_sock, clnt_sock; char message[BUF_SIZE]; int str_len, i; struct sockaddr_in serv_adr, clnt_adr; socklen_t clnt_adr_sz; FILE * readfp; FILE * writefp; if (argc != 2) { printf("Usage : %s <port> \n",argv[0]); exit(1); } serv_sock = socket(PF_INET,SOCK_STREAM,0); if (serv_sock == -1) error_handling("socket() error!"); memset(&serv_adr,0,sizeof(serv_adr)); serv_adr.sin_family = AF_INET; serv_adr.sin_addr.s_addr = htonl(INADDR_ANY); serv_adr.sin_port = htons(atoi(argv[1])); if (bind(serv_sock,(struct sockaddr*) &serv_adr,sizeof(serv_adr)) == -1) error_handling("bind() error!"); if (listen(serv_sock,5) == -1) error_handling("listen() error!"); clnt_adr_sz = sizeof(clnt_adr); for (i = 0; i < 5; i++) //迭代5次 { clnt_sock = accept(serv_sock,(struct sockaddr*)&clnt_adr,&clnt_adr_sz); if (clnt_sock == -1) error_handling("accept() error!"); else printf("Connected client %d\n",i+1); readfp = fdopen(clnt_sock,"r"); writefp = fdopen(clnt_sock,"w"); while(!feof(readfp)) { fgets(message,BUF_SIZE,readfp); fputs(message,writefp); fflush(writefp); //冲洗缓冲 } fclose(readfp); fclose(writefp); } close(serv_sock); return 0; }
客户端:echo_client.c
/* 回声客户端 */ #include<stdio.h> #include<stdlib.h> #include<string.h> #include<unistd.h> #include<arpa/inet.h> #include<sys/socket.h> #define BUF_SIZE 1024 void error_handling(char *message) { fputs(message,stderr); fputc('\n',stderr); exit(1); } int main(int argc,char *argv[]) { int sock; char message[BUF_SIZE]; int str_len; struct sockaddr_in serv_adr; FILE * readfp; FILE * writefp; if(argc != 3) { printf("Usage : %s <IP> <port>\n",argv[0]); exit(1); } sock = socket(PF_INET,SOCK_STREAM,0); if (sock == -1) error_handling("socket() error!"); memset(&serv_adr,0,sizeof(serv_adr)); serv_adr.sin_family = AF_INET; serv_adr.sin_addr.s_addr = inet_addr(argv[1]); serv_adr.sin_port = htons(atoi(argv[2])); if (connect(sock,(struct sockaddr*) &serv_adr,sizeof(serv_adr)) == -1) error_handling("connect() error!"); else puts("Connected........."); readfp = fdopen(sock,"r"); writefp = fdopen(sock,"w"); while (1) { fputs("Input message(Q to quit): ",stdout); fgets(message,BUF_SIZE,stdin); if (!strcmp(message,"q\n") || !strcmp(message,"Q\n")) // 输入q/Q退出 break; fputs(message,writefp); fflush(writefp); fgets(message,BUF_SIZE,readfp); printf("Message from server: %s",message); } fclose(writefp); fclose(readfp); return 0; }
运行结果:
完