标准I/O函数的优点

  • 标准I/O函数具有良好的移植性( PortabiJity )。
  • 标准I/O函数可以利用缓冲提高性能。
  • 数据传输快(300M的文件只要很短的时间就可以完成,但是不用标准I/O要传输很久)

创建套接字时,操作系统将生成用于I/O的缓冲。此缓冲在执行TCP协议时发挥着非常重要的作用。此时若使用标准I/O函数,将得到额外的另一缓冲的支持,如图所示。

网编(14):套接字和标准I/O_结构体指针

标准I/O函数的几个缺点

  • 不容易进行双向通信。
  • 有时可能频繁调用fllush 函数。
  • 需要以FILE结构体指针的形式返回文件描述符。

打开文件时,如果希望同时进行读写操作,则应以r+ 、W七a+模式打开。但因为缓冲的缘故,每次切换读写工作状态时应调用fllush
函数。这也会影响基于缓冲的性能提高。而且,为了使用标准I/0函数,需要FILE指针。而创建套接字时默认返回文件描述符,因此需要将文件描述符转化为FILE指针。

利用fdopen 函数转换为FILE 结构体指针

#include <stdio.h>
FILE* fdopen(int fildes, const char * mode);
//成功时返回转换的FILE 结构体指针,失败时返回NULL 。

#tildes 需要转换的文件描述符。
#mode 将要创建的FILE结构体指针的模式(mode)信息。

实例代码:

#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");
fputs("Network C programming \n", fp);
fclose(fp);
return 0;
}

利用fileno 函数转换为文件描述符

#include <stdio.h>
int fileno(FILE * stream);
//成功时返回转换后的文件描述符,失败时返回-1 。

实例代码:

#include <stdio.h>
#include <fcntl.h>

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函数使用

服务器:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#define TTL 64
#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_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);
}

客户端:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#define TTL 64
#define BUF_SIZE 30
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