标准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
                










