宿迁网站建设托管,什么类型的产品可以做网站出口,怎样做好竞价推广,关键词优化难度分析第 15 章 套接字和标准I/O
15.1 标准 I/O 的优点 标准 I/O 函数的两个优点#xff1a; 除了使用 read 和 write 函数收发数据外#xff0c;还能使用标准 I/O 函数收发数据。下面是标准 I/O 函数的两个优点#xff1a;
标准 I/O 函数具有良好的移植性标准 I/O 函数可以利用…第 15 章 套接字和标准I/O
15.1 标准 I/O 的优点 标准 I/O 函数的两个优点 除了使用 read 和 write 函数收发数据外还能使用标准 I/O 函数收发数据。下面是标准 I/O 函数的两个优点
标准 I/O 函数具有良好的移植性标准 I/O 函数可以利用缓冲提高性能 创建套接字时操作系统会准备 I/O 缓冲。此缓冲在执行 TCP 协议时发挥着非常重要的作用。此时若使用标准 I/O 函数将得到额外的缓冲支持。如下图 假设使用 fputs 函数进行传输字符串 「Hello」时首先将数据传递到标准 I/O 缓冲然后将数据移动到套接字输出缓冲最后将字符串发送到对方主机。 设置缓冲的主要目的是为了提高性能。从以下两点可以说明性能的提高
传输的数据量。数据向输出缓冲移动的次数。 比较 1 个字节的数据发送 10 次的情况和 10 个字节发送 1 次的情况。发送数据时数据包中含有头信息。头信与数据大小无关是按照一定的格式填入的。假设头信息占 40 个字节需要传输的数据量也存在较大区别 1 个字节 10 次40*10400 字节。 10个字节 1 次40*140 字节。 另外为了发送数据向套接字输出缓冲移动数据也会消耗不少时间。但这同样与移动次数有关。1个字节数据共移动10次花费的时间将近10个字节数据移动1次花费时间的10倍。
标准 I/O 函数和系统函数之间的性能对比 基于readwrite函数的文件复制程序
#include stdio.h
#include fcntl.h
#define BUF_SIZE 3int main(int argc, char *argv[])
{int 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_SZIE 3int main(int argc, char *argv[])
{FILE *fp1;FILE *fp2;char buf[BUF_SZIE];fp1 open(news.txt, r);fp2 open(cpy.txt, w);while (fgets(buf, BUF_SZIE, fp1) ! NULL)fputs(buf, fp2);fclose(fp1);fclose(fp2);return 0;
} 对以上两种示例测试基于标注I/O函数的示例运行得更快。
标准 I/O 函数的几个缺点 标准 I/O 函数存在以下几个缺点
不容易进行双向通信。有时可能频繁调用 fflush 函数。需要以 FILE 结构体指针的形式返回文件描述符。
15.2 使用标准 I/O 函数
利用 fdopen 函数转换为 FILE 结构体指针 函数原型如下
#include stdio.h
FILE *fdopen(int fildes, const char *mode);
/*
成功时返回转换的 FILE 结构体指针失败时返回 NULL
fildes 需要转换的文件描述符
mode 将要创建的 FILE 结构体指针的模式信息
*/ 示例
#include stdio.h
#include fcntl.hint main()
{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); //返回 写 模式的 FILE 指针fputs(NetWork C programming \n, fp);fclose(fp);return 0;
} 运行结果 文件描述符转换为 FILE 指针并可以通过该指针调用标准 I/O 函数。
利用 fileno 函数转换为文件描述符 该函数与fdopen函数提供相反功能函数原型如下
#include stdio.h
int fileno(FILE *stream);
/*
成功时返回文件描述符失败时返回 -1
*/
#include stdio.h
#include fcntl.hint main()
{FILE *fp;int fd open(data.dat, O_WRONLY | O_CREAT | O_TRUNC);if (fd -1){fputs(file open error);return -1;}printf(First file descriptor : %d \n, fd);fp fdopen(fd, w); //转成 file 指针fputs(TCP/IP SOCKET PROGRAMMING \n, fp);printf(Second file descriptor: %d \n, fileno(fp)); //转回文件描述符fclose(fp);return 0;
} 运行结果 输出的文件描述符值相同证明fileno函数正确转换了文件描述符。
15.3 基于套接字的标准 I/O 函数使用 把第四章的回声客户端和回声服务端的内容改为基于标准 I/O 函数的数据交换形式
客户端
#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);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!);elseputs(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))break;fputs(message, writefp);fflush(writefp);fgets(message, BUF_SIZE, readfp);printf(Message from server: %s, message);}fclose(writefp);fclose(readfp);return 0;
}void error_handling(char *message)
{fputs(message, stderr);fputc(\n, stderr);exit(1);
}
服务端
#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);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);//调用 5 次 accept 函数共为 5 个客户端提供服务for (i 0; i 5; i){clnt_sock accept(serv_sock, (struct sockaddr *)clnt_adr, clnt_adr_sz);if (clnt_sock -1)error_handling(accept() error);elseprintf(Connect 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;
}void error_handling(char *message)
{fputs(message, stderr);fputc(\n, stderr);exit(1);
}
运行实例 可以看出运行结果和第四章相同这是利用标准 I/O 实现的。 习题
1、请说明标准 I/O 的 2 个优点。他为何拥有这 2 个优点 ①具有很高的移植性②有良好的缓冲提高性能。