昆明酒店网站建设,苏州网络推广软件,wordpress下载类型主题,注册会计师协会标准I/O函数的优点
标准I/O函数的两个优点 将标准I/O函数用于数据通信并非难事。但仅掌握函数使用方法并没有太大意义#xff0c;至少应该 了解这些函数具有的优点。下面列出的是标准I/O函数的两大优点: □标准I/O函数具有良好的移植性(Portability) □标准I/O函数可以利用缓…标准I/O函数的优点
标准I/O函数的两个优点 将标准I/O函数用于数据通信并非难事。但仅掌握函数使用方法并没有太大意义至少应该 了解这些函数具有的优点。下面列出的是标准I/O函数的两大优点: □标准I/O函数具有良好的移植性(Portability) □标准I/O函数可以利用缓冲提高性能。 关于移植性无需过多解释。不仅是IO函数所有标准函数具有良好的移植性。因为为了支持所有操作系统编译器这些函数都是按照ANSI C标准定义的。当然这并不局限于网络编程而是适用于所有编程领域。 接下来讨论标准I/O函数的第二个优点。使用标准IO函数时会得到额外的缓冲支持。这种表达方式也许会带来一些混乱因为之前讲过创建套接字时操作系统会准备I/O缓冲。造成更大混乱之前先说明这两种缓冲之间的关系。创建套接字时操作系统将生成用于I/O的缓冲。此缓冲在执行TCP协议时发挥着非常重要的作用。此时若使用标准IO函数将得到额外的另一缓冲的支持。大概意思如下图所示: 从图中可以看到使用标准I/O函数传输数据时经过两个缓冲。例如通过fputs函数传输字符串“Hello”时首先将数据传递到标准IO函数的缓冲。然后数据将移动到套接字输出缓冲最后将字符串发送到对方主机。 既然知道了两个缓冲的关系接下来再说明各自的用途。设置缓冲的主要目的是为了提高性能但套接字中的缓冲主要是为了实现TCP协议而设立的。例如TCP传输中丢失数据时将再次传递 而再次发送数据则意味着在某地保存了数据。存在什么地方呢套接字的输出缓冲。与之 相反使用标准IO函数缓冲的主要目的是为提高性能但是实际上缓冲并非在所有情况下都能带来卓越的性能。但需要传输的数据越多有无缓冲带来的性能差异越大。可以通过如下两种角度说明性能的提高。 □传输的数据量 □数据向输出缓冲移动的次数 比较1个字节的数据发送10次(10个数据包的情况和累计10个字节发送1次的情况。发送数据时使用的数据包中含有头信息(首部)。头信息与数据大小无关是按照一定的格式填入的。即使假设该头信息占用40个字节实际更大需要传递的数据量也存在较大差别。 □1个字节10次40×10400字节 □10个字节1次40x140字节 另外为了发送数据向套接字输出缓冲移动数据也会消耗不少时间。但这同样与移动次数 有关。1个字节数据共移动10次花费的时间将近10个字节数据移动1次花费时间的10倍。
标准I/O函数的几个缺点 如果就此结束说明各位可能认为标准I/O函数只有优点。其实它同样有缺点整理如下。 □不容易进行双向通信。 □有时可能频繁调用fflush函数。(用以刷新缓冲区) □需要以FILE结构体指针的形式返回文件描述符。 假设各位已掌握了C语言中的绝大部分文件IO相关知识。打开文件时如果希望同时进行读写操作则应以r、w、a模式打开。但因为缓冲的缘故每次切换读写工作状态时应调用fflush函数。这也会影响基于缓冲的性能提高。而且为了使用标准IO函数需要FILE结构体指针以下简称“FILE指针”)。而创建套接字时默认返回文件描述符因此需要将文件描述符转化为FILE指针。
使用标准I/O函数 如前所述创建套接字时返回文件描述符而为了使用标准IO函数只能将其转换为FILE 结构体指针。先介绍其转换方法。 利用fdopen函数转换为FILE结构体指针 可以通过fdopen函数将创建套接字时返回的文件描述符转换为标准IO函数中使用的FILE结 构体指针。
#includestdio.h
FILE * fdopen(int fildes, const char * mode);
//成功时返回转换的FILE结构体指针失败时返回NULL。fildes //需要转换的文件描述符。mode //将要创建的FILE结构体指针的模式mode信息。
上述函数的第二个参数与fopen函数中的打开模式相同。常用的参数有读模式r和写模式w。
利用fileno函数转化为文件描述符
接下来介绍与fdopen函数提供功能相反的函数该函数在有些情况下非常好用。
#includestdio.h
int fileno(FILE * stream);//成功时返回转化后的文件描述符失败时返回-1
此函数的用法也非常简单向该函数传递FILE指针参数时返回相应文件描述符。
基于套接字的标准I/O函数使用
前面介绍了标准IO函数的优缺点同时介绍了文件描述符转换为FILE指针的方法。下面将其适用于套接字。虽然是套接字操作但并没有需要另外说明的内容只需简单应用这些函数。接下来将之前的回声服务器端和客户端改为基于标准IO函数的数据交换形式。 无论是服务器端还是客户喘更改方式并无差异。只需调用fdopen函数并使用标准IO函数 相信各位也能自行更改。首先给出更改后的服务器端代码。
#include头文件声明和之前章节中的回声服务端相同故省略
#define BUF_SIZE 30
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_addr;struct sockaddr_in clnt_addr;socklen_t clnt_addr_sz;FILE * readfp;FILE * writefp;if(argc!2){printf(Usage : %s port\n,argv[0]);exit(1);}serv_socksocket(PF_INET,SOCK_STREAM,0);if(serv_sock-1)error_handling(socket() error);memset(serv_addr,0,sizeof(serv_addr));serv_addr.sin_familyAF_INET;serv_addr.sin_addr.s_addrhtonl(INADDR_ANY);serv_addr.sin_porthtons(atoi(argv[1]));if(bind(serv_sock,(struct sockaddr*)serv_addr,sizeof(serv_addr))-1)error_handling(bind() error);if(listen(serv_sock,5)-1)error_handling(listen() error);clnt_addr_szsizeof(clnt_sock);for(int i0;i5;i){clnt_sockaccept(serv_sock,(struct sockaddr*)clnt_sock,clnt_addr_sz);if(clnt_sock-1)error_handling(accept() error);else printf(Connected client %d \n,i1);readfpfdopen(clnt_sock,r);writefpfdopen(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){//与之前章节的错误处理函数相同故省略
}
接下来给出回声客户端代码
#include与之前章节的头文件声明相同故省略
#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_int serv_addr;FILE * readfp;FILE * writefp;if(argc!3){printf(Usage : %s IP port\n,argv[0]);exit(1);}socksocket(PF_INET,SOCK_STREAM,0);if(sock-1)error_handling(socket() error);memset(serv_addr,0,sizeof(serv_addr));serv_addr.sin_familyAF_INET;serv_addr.sin_addr.s_addrinet_addr(argv[1]);serv_addr.sin_porthtons(atoi(argv[2]));if(connect(sock,(struct sockaddr*)serv_addr,sizeof(serv_addr))-1)error_handling(connect() error);elseputs(Connected.......);readfpfdopen(sock,r);writefpfdopen(sock,w);while(1){fputs(Input message(Q to quite):,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){//和前面章节的错误处理函数相同故省略。
}
以上就是标准IO函数在套接字编程中的应用方法因为需要编写额外的代码所以并不像想象中那么常用。但某些情况下也是非常有用的而且可以再次复习标准IO函数对大家也非常有益。