socket选项之SO_LINGER,优雅关闭套接字

目录

1.什么是优雅关闭套接字?

2.close函数详解

2.1 close函数

2.2 close函数实现原理

3.SO_LINGER套接字选项

4.shutdown函数详解

4.1 shutdown函数

4.2 shutdown函数实现原理

5.如何优雅关闭套接字?

5.1 优雅关闭套接字需要满足什么要求?

5.2 直接调用close函数会有什么问题?

5.3 优雅关闭套接字流程


1.什么是优雅关闭套接字?

优雅关闭套接字指的是在关闭套接字时,双方通信的应用程序会进行一系列协商和处理,以确保数据传输的完整性和可靠性,避免数据的丢失或者损坏。 在传输数据时,通信的两端可能还有未完成的数据需要传输,如果直接关闭套接字,这些数据可能会丢失。因此,在关闭套接字之前,需要通信双方先协商确定是否还有未完成的数据需要传输,如果有,需要先将这些数据传输完成,然后再进行正式的关闭。这个过程称为优雅关闭套接字。

优雅关闭套接字指的是TCP套接字,UDP直接调用close函数关闭套接字。

2.close函数详解

2.1 close函数

close函数会释放该文件描述符所占用的资源,并将文件描述符从进程的文件描述符表中移除。
如果该文件描述符是最后一个引用该文件的文件描述符,close函数会将该文件从内核中移除。

#include <unistd.h>
int close(int fd);

参数:
fd: 要关闭的文件描述符

返回值:
成功:返回值为0
失败:返回值为-1,错误码保存在errno变量中

2.2 close函数实现原理

 图 1 close函数实现原理

3.SO_LINGER套接字选项

SO_LINGER是套接字选项之一,用于设置socket关闭时的行为。

SO_LINGER选项由结构体struct linger定义

struct linger {
    int l_onoff;
    int l_linger;
};

l_onoff:0:关闭SO_LINGER选项,1:开启SO_LINGER选项
l_linger:超时时间,单位秒

SO_LINGER不同参数行为如下表:

 SO_LINGER使用示例:

int sockfd = socket(AF_INET, SOCK_STREAM, 0);
struct linger so_linger;
so_linger.l_onoff = 1; //开启
so_linger.l_linger = 5; //超时时间5秒
setsockopt(sockfd, SOL_SOCKET, SO_LINGER, &so_linger, sizeof(so_linger));

4.shutdown函数详解

4.1 shutdown函数

shutdown函数通过向套接字发送一个特定的信息来关闭连接。它并不是立即关闭,而是等待所有数据发送完成后再关闭。如果套接字上还有未发送的数据,那么它们将在关闭之前被发送出去。

注意,如果套接字已经被关闭,则调用shutdown函数将会导致错误返回。

#include <unistd.h>

int shutdown(int sockfd, int how);

参数:
sockfd:套接字的文件描述符
how:指定关闭方式

SHUT_RD:关闭该套接字的读功能
SHUT_WR:关闭该套接字的写功能,TCP套接字进入half-close状态
SHUT_RDWR:同时关闭该套接字的读写功能

返回值:
成功:返回0
失败:返回-1,并设置errno

4.2 shutdown函数实现原理

图 2 shutdown函数实现原理 

5.如何优雅关闭套接字?

5.1 优雅关闭套接字需要满足什么要求?

  • 保证双方数据不丢失
  • 保证双方套接字资源和文件描述符正确释放

5.2 直接调用close函数会有什么问题?

a.close存在引用计数的问题,如果引用计数不为0,可能不会对套接字做释放操作。

b.close会直接清空套接字资源,此时套接字无法再接收对端数据,导致接收数据丢失。 

c.close可能会发送RST报文给对端,对端收到RST报文后也是直接释放套接字资源。

5.3 优雅关闭套接字流程

1.调用shutdown函数关闭套接字写功能,发送FIN报文,完成四次挥手正常关闭套接字。

2.接收剩余数据,防止数据丢失

2.调用close函数,释放套接字资源,关闭文件描述符。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string/h>
#include <sys/socket.h>

#define MAX_LEN (2048)

int my_shutdown(int sockfd) {

    //关闭套接字写功能,TCP套接字进入半关闭状态
    if (shutdown(sockfd, SHUT_WR) == -1) {
        return -1;
    }

    //接收剩余数据
    char buf[MAX_LEN] = {0};
    ssize_t len = 0;
    do {
        memset(buf, 0, MAX_LEN);
        len = recv(sockfd, buf, MAX_LEN);
        //处理数据
    } while(len <= 0);

    //关闭套接字,释放套接字资源
    if (close(sockfd) == -1) {
        return -1;
    }

    return 0;
}
  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

物联网心球

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值