标准I/O函数的优点
- 标准I/O函数具有良好的移植性( PortabiJity )。
- 标准I/O函数可以利用缓冲提高性能。
- 数据传输快(300M的文件只要很短的时间就可以完成,但是不用标准I/O要传输很久)
创建套接字时,操作系统将生成用于I/O的缓冲。此缓冲在执行TCP协议时发挥着非常重要的作用。此时若使用标准I/O函数,将得到额外的另一缓冲的支持,如图所示。
标准I/O函数的几个缺点
- 不容易进行双向通信。
- 有时可能频繁调用fllush 函数。
- 需要以FILE结构体指针的形式返回文件描述符。
打开文件时,如果希望同时进行读写操作,则应以r+ 、W七a+模式打开。但因为缓冲的缘故,每次切换读写工作状态时应调用fllush
函数。这也会影响基于缓冲的性能提高。而且,为了使用标准I/0函数,需要FILE指针。而创建套接字时默认返回文件描述符,因此需要将文件描述符转化为FILE指针。
利用fdopen 函数转换为FILE 结构体指针
FILE* fdopen(int fildes, const char * mode);
//成功时返回转换的FILE 结构体指针,失败时返回NULL 。
实例代码:
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");
fputs("Network C programming \n", fp);
fclose(fp);
return 0;
}
利用fileno 函数转换为文件描述符
int fileno(FILE * stream);
//成功时返回转换后的文件描述符,失败时返回-1 。
实例代码:
int main(void)
{
FILE *fp;
int fd=open("data.dat", O_WRONLYjO_CREAT IO_TRUNC);
if{fd==-1)
{
fputs("file open error", stdout);
return -1;
}
printf("First file descriptor: %d \n", fd);
fp=fdopen(fd, "w");
fputs("TCP/IP SOCKET PROGRAMMING \n", fp);
printf("Second file descriptor: %d \n", fileno(fp));
fclose(fp);
return 0;
}
基于套接字的标准I/O函数使用
服务器:
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;
struct sockaddr_in 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("list en() e r ror");
clnt_adr_sz=sizeof (clnt_adr ) ;
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");
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;
}
void error_handling(char *message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
客户端:
void error_handling(char *message);
int main(int argc, char *argv[])
{
int clnt_sock;
char message[BUF_SIZE];
int str_len, i;
struct sockaddr_in clnt_adr;
socklen_t clnt_adr_sz;
FILE * readfp;
FILE * writefp;
if(argc!=3) {
printf("Usage : %s <port>\n", argv[0]);
exit(1);
}
clnt_sock=socket(PF_INET, SOCK_STREAM, 0);
if(clnt_sock==-1)
error_handling("socket() error");
memset(&clnt_adr, 0, sizeof(clnt_adr));
clnt_adr.sin_family=AF_INET;
clnt_adr.sin_addr.s_addr=htonl(INADDR_ANY);
clnt_adr.sin_port=htons(atoi(argv[2]));
if(connect(clnt_sock, (struct sockaddr*)&clnt_adr, sizeof(clnt_adr))== - 1)
error_handling("bind() error");
readfp=fdopen(clnt_sock, "r");
writefp=fdopen(clnt_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(readfp);
fclose(writefp);
close(clnt_sock);
return 0;
}
void error_handling(char *message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
运行结果:
$ ./ser 9190
Connected client 1
$ ./cli 192.168.43.220 9190
Input message(Q to quit) : 123
Message from server: 123
Input message(Q to quit) : 456
Message from server: 456