【linux】close与shutdown

来源:互联网 发布:岁寒然后知松柏下一句 编辑:程序博客网 时间:2024/06/10 17:52

了解close与shutdown区别,我们先回忆下文件描述符与进程的关系。代码如下:

#include<stdio.h>#include<unistd.h>#include<stdlib.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>int main(){        char *pathname = "a.txt";        char father[] = "this isffffffffffffffffif father";        char son[] = "this is sssssssssssssssssssssssssss son";        int fd;        int re;        fd = open(pathname,O_CREAT|O_RDWR);        pid_t pid = fork();        if(pid > 0)        {                write(fd,father,sizeof(father));                re = close(fd);                printf("father re = %d \n",re);                re = close(fd);                printf("father re 2  = %d \n",re);        }else if(pid == 0)        {                sleep(1);                write(fd,son,sizeof(son));                re = close(fd);                printf("son re = %d \n",re);        }}
   多进程中,父子进程都会有独立的空间(PCB,代码段,数据段,BSS,还有堆栈段),但是这时候文件描述符是共用的,都可以往同一个文件写内容。但是引入了一个计数器。如下图:refcnt:2,我们必须close两次才能把文件彻底关掉。

这里写图片描述

了解了如上内容,我们可以继续往下:

1.server代码如下:收到第一个字符为 1 后 close 当前进程文件描述符,关注下最后一行。server收数据

#include<stdio.h>#include<stdlib.h>#include <sys/types.h>          /* See NOTES */#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include<string.h>#include<signal.h>void handler(int num){        //wait(NULL);        int pp_pid = 0;        while((pp_pid = waitpid(-1,NULL,WNOHANG)) > 0)        {                printf("break pid :%d \n",pp_pid);        }        exit(0);}int main(){        struct sockaddr_in addr;        struct sockaddr_in addr_peer;        struct in_addr ip;        inet_aton("127.0.0.1",&ip);        addr.sin_family = AF_INET;        addr.sin_port =htons(8001);        addr.sin_addr = ip;        int sockfd = 0;        int conn =0;        int re = 0;        char buf[1024] = {0};        char buf_write[1024] = {0};        signal(SIGCHLD,handler);        sockfd = socket(AF_INET, SOCK_STREAM, 0);        if(sockfd == -1)        {                perror("sockfd error \n");        }        re = bind(sockfd,(struct sockaddr *)&addr,sizeof(struct sockaddr_in));        if(re == -1)        {                perror("bind error");        }        conn = listen(sockfd,SOMAXCONN);        if(conn == -1)        {                perror("listen error \n");        }        //while(1)        {                int len = sizeof(struct sockaddr_in);                conn =accept(sockfd,(struct sockaddr *)&addr_peer,&len);                printf("port:%u \n",ntohs(addr_peer.sin_port));                pid_t pid = fork();                if(pid == 0)                {                        int ret = 0;                        while(1)                        {                                ret = read(conn,buf,sizeof(buf));                                if(buf[0] == '1')                                {                                        close(conn);                                }                                fputs(buf,stdout);                                memset(buf,0,sizeof(buf));                        }                }else if(pid > 0)                {                   while(fgets(buf_write,sizeof(buf_write),stdin))!= NULL)                {                                                                                                                                                                             write(conn,buf_write,sizeof(buf_write));                                                                       }                }     }

client代码如下:client负责读写数据:

#include<stdio.h>#include<stdlib.h>#include <sys/types.h>          /* See NOTES */#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include<signal.h>#include<string.h>void handler(int num){        printf("num = %d \n",num);}int main(){        struct sockaddr_in addr;        struct in_addr ip;        inet_aton("127.0.0.1",&ip);        addr.sin_family = AF_INET;        addr.sin_port =htons(8001);        addr.sin_addr = ip;        int re = 0,i = 0,conn =0,sockfd = 0;        char buf[1024] ={0};        char buf_read[1024] = {0};        signal(SIGPIPE,handler);        {                sockfd = socket(AF_INET, SOCK_STREAM, 0);                if(sockfd == -1)                {                        perror("sockfd error \n");                }                conn = connect(sockfd, (const struct sockaddr *)&addr,sizeof(struct sockaddr_in));                if(conn == -1)                {                        perror("conn error \n");                }        }        pid_t pid = fork();        if(pid == 0)        {                while((fgets(buf,sizeof(buf),stdin)) != NULL)                {                        write(sockfd,buf,sizeof(buf));                        memset(buf,0,sizeof(buf));                }        }else if(pid > 0)        {                while(1)                {                        re = read(sockfd,buf_read,sizeof(buf_read));                        if(re == 0)                        {                                close(sockfd);                                printf("peer is break \n");                        }                        fputs(buf_read,stdout);                        memset(buf_read,0,sizeof(buf_read));                }        }   }

此时client发送1 后,server收到后关闭文件描述符,但是看状态:

tcp  0  0 localhost:49021  localhost:8001        ESTABLISHEDtcp 3072 0 localhost:8001  localhost:49021         ESTABLISHED

此时只是关闭了client的写和servser可以的读。server发数据client仍然可以读到。只有两个进程都关闭了文件描述符,才会发FIN字段,开始断开的4次握手。

close了解了
开始了解下shutdown。
SHUT_RD:关闭连接的读端。也就是该套接字不再接受数据,任何当前在套接字接受缓冲区的数据将被丢弃。进程将不能对该
套接字发出任何读操作。对TCP套接字该调用之后接受到的任何数据将被确认然后无声的丢弃掉。
SHUT_WR:关闭连接的写端,进程不能在对此套接字发出写操作
SHUT_RDWR:相当于调用shutdown两次:首先是以SHUT_RD,然后以SHUT_WR
使用close中止一个连接,但它只是减少描述符的参考数,并不直接关闭连接,只有当描述符的参考数为0时才关闭连接。
shutdown可直接关闭描述符,不考虑描述符的参考数,可选择中止一个方向的连接。

//更改server代码,将close改为shutdown                        while(1)                        {                                ret = read(conn,buf,sizeof(buf));                                if(buf[0] == '1')                                {                                        //close(conn);                                        shutdown(conn,SHUT_RDWR);                                }                                fputs(buf,stdout);                                memset(buf,0,sizeof(buf));                        }

查看状态

tcp    0   0 localhost:8001   localhost:49024         FIN_WAIT2  tcp    0   0 localhost:49024  localhost:8001          CLOSE_WAIT