【linux】close与shutdown

了解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        ESTABLISHED
tcp 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

猜你喜欢

转载自blog.csdn.net/dachunfree/article/details/76162445