16.1 分离I/O流

16.1.1 分离“流“的好处

  • 为了将FILE指针按读模式和写模式加以区分
  • 可以通过区分读写模式降低实现难度
  • 通过区分I/O缓冲提高缓冲性能

16.1.2 “流”分离带来的EOF问题

  1. //sep_serv.c
  2. #include<stdio.h>
  3. #include<stdlib.h>
  4. #include<string.h>
  5. #include<unistd.h>
  6. #include<arpa/inet.h>
  7. #include<sys/socket.h>
  8. #define BUF_SIZE 1024
  9. int main(int argc, char *argv[])
  10. {
  11. int serv_sock, clnt_sock;
  12. FILE *readfp;
  13. FILE *writefp;
  14. struct sockaddr_in serv_adr, clnt_adr;
  15. socklen_t clnt_adr_sz;
  16. char buf[BUF_SIZE]={0,};
  17. serv_sock=socket(PF_INET, SOCK_STREAM, 0);
  18. memset(&serv_adr, 0, sizeof(serv_adr));
  19. serv_adr.sin_family=AF_INET;
  20. serv_adr.sin_addr.s_addr=htonl(INADDR_ANY);
  21. serv_adr.sin_port=htons(atoi(argv[1]));
  22. bind(serv_sock, (struct sockaddr*)&serv_adr, sizeof(serv_adr));
  23. listen(serv_sock, 5);
  24. clnt_adr_sz=sizeof(clnt_adr);
  25. clnt_sock=accept(serv_sock, (struct sockaddr*)&clnt_adr, &clnt_adr_sz);
  26. readfp=fdopen(clnt_sock, "r");
  27. writefp=fdopen(clnt_sock, "w");
  28. fputs("FROM SERVER: Hi~ client? \n", writefp);
  29. fputs("You are awesome! \n", writefp);
  30. fflush(writefp);
  31. fclose(writefp);
  32. fgets(buf, sizeof(buf), readfp);
  33. fputs(buf, stdout);
  34. fclose(readfp);
  35. return 0;
  36. }
//sep_clnt.c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#define BUF_SIZE 1024

int main(int argc, char *argv[])
{
    int sock;
    char buf[BUF_SIZE];
    struct sockaddr_in serv_addr;

    FILE *readfp;
    FILE *writefp;
    sock=socket(PF_INET, SOCK_STREAM, 0);
    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family=AF_INET;
    serv_addr.sin_addr.s_addr=inet_addr(argv[1]);
    serv_addr.sin_port=htons(atoi(argv[2]));

    connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
    readfp=fdopen(sock, "r");
    writefp=fdopen(sock, "w");

    while(1)
    {
        if(fgets(buf, sizeof(buf), readfp)==NULL)
            break;
        fputs(buf, stdout);
        fflush(stdout);
    }
    fputs("FROM CLIENT: Thank you! \n", writefp);
    fflush(writefp);
    fclose(writefp);
    fclose(readfp);
    return 0;
}
#server
zhang@zhang-virtual-machine:~/Desktop/Ctest/Demo32$ ./sep_serv 9190
#client
zhang@zhang-virtual-machine:~/Desktop/Ctest/Demo32$ ./sep_clnt 127.0.0.1 9190
FROM SERVER: Hi~ client? 
You are awesome!

16.2 文件描述符的复制和半关闭

16.2.1 终止”流“时无法半关闭的原因

针对写模式FILE指针调用fclose函数时,只能销毁与该FILE指针相关的文件描述符,无法销毁套接字

16.2.2 dup & dup2

#include<unistd.h>

int dup(int fildes);
int dup2(int fildes, int fildes2);
//成功时返回文件描述符,失败时返回-1
//fildes 需要复制的文件描述符
//fildes2 明确指定的文件描述符整数值
//dup.c
#include<stdio.h>
#include<unistd.h>

int main(int argc, char *argv[])
{
    int cfd1, cfd2;
    char str1[]="Hi~\n";
    char str2[]="It's nice day~ \n";

    cfd1=dup(1);
    cfd2=dup2(cfd1, 7);

    printf("fd1=%d, fd2=%d \n",cfd1, cfd2);
    write(cfd1, str1, sizeof(str1));
    write(cfd2, str2, sizeof(str2));

    close(cfd1);
    close(cfd2);
    write(1, str1, sizeof(str1));
    close(1);
    write(1, str2, sizeof(str2));
    return 0;
}
zhang@zhang-virtual-machine:~/Desktop/Ctest/Demo32$ gcc dup.c -o dup
zhang@zhang-virtual-machine:~/Desktop/Ctest/Demo32$ ./dup
fd1=3, fd2=7 
Hi~
It's nice day~ 
Hi~

16.2.3 复制文件描述符后”流“的分离

//sep_serv2.c
//sep_clnt.c不变
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#define BUF_SIZE 1024

int main(int argc, char *argv[])
{
    int serv_sock, clnt_sock;
    FILE *readfp;
    FILE *writefp;

    struct sockaddr_in serv_adr, clnt_adr;
    socklen_t clnt_adr_sz;
    char buf[BUF_SIZE]={0,};

    serv_sock=socket(PF_INET, SOCK_STREAM, 0);
    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]));

    bind(serv_sock, (struct sockaddr*)&serv_adr, sizeof(serv_adr));
    listen(serv_sock, 5);
    clnt_adr_sz=sizeof(clnt_adr);
    clnt_sock=accept(serv_sock, (struct sockaddr*)&clnt_adr, &clnt_adr_sz);

    readfp=fdopen(clnt_sock, "r");
    writefp=fdopen(clnt_sock, "w");

    fputs("FROM SERVER: Hi~ client? \n", writefp);
    fputs("I love all of the world \n", writefp);
    fputs("You are awesome! \n", writefp);
    fflush(writefp);

    shutdown(fileno(writefp), SHUT_WR);
    fclose(writefp);

    fgets(buf, sizeof(buf), readfp);
    fputs(buf, stdout);
    fclose(readfp);
    return 0;
}
#server
zhang@zhang-virtual-machine:~/Desktop/Ctest/Demo32$ gcc sep_serv2.c -o sep_serv2
zhang@zhang-virtual-machine:~/Desktop/Ctest/Demo32$ ./sep_serv2 9190
#client
zhang@zhang-virtual-machine:~/Desktop/Ctest/Demo32$ ./sep_clnt 127.0.0.1 9190
FROM SERVER: Hi~ client? 
I love all of the world 
You are awesome!