优雅关闭:如果发送缓存中还有数据未发出则其发出去,并且收到所有数据的ACK之后,发送FIN包,开始关闭过程。TCP连接线关闭一个方向,此时另外一个方向还是可以正常进行数据传输。
强制关闭:如果缓存中还有数据,则这些数据都将被丢弃,然后发送RST包,直接重置TCP连接。两边都关闭了,服务端处理完的信息没有正常传给客户端。
#include <unistd.h>
int close(int fd);
close()函数会使套接字的引用计数减1,若套接字的引用计数为0,则彻底关闭连接,并且会关闭TCP两个方向的数据流,既不能发送数据也不能接收数据。close函数不能关闭一个方向上的连接,而shutdown函数可以实现。如果服务端还又没有处理完的数据,不能正常发送给客户端。
int shutdown(int sock, int howto);
参数howto的取值:
SHUT_RD:断开输入流。套接字无法接收数据(即使输入缓冲区收到数据也被抹去),无法调用输入相关函数。
SHUT_WR:断开输出流。套接字无法发送数据,但如果输出缓冲区中还有未传输的数据,则将传递到目标主机。
SHUT_RDWR:同时断开 I/O 流。相当于分两次调用 shutdown(),其中一次以 SHUT_RD 为参数,另一次以 SHUT_WR 为参数。
LINGER结构包含了指定套接字的信息,当调用了close()函数关闭该套接字时,LINGER结构中的信息指定了如何处理未发送的数据。
typedef struct linger {
u_short l_onoff;
u_short l_linger;
} LINGER, *PLINGER, *LPLINGER;
参数:
l_onoff | l_linger | close行为 | 发送队列 | 底层行为 |
零 | 忽略 | 立即返回。 | 保持直至发送完成。 | 系统接管套接字并保证将数据发送至对端。(就是正常的close) |
非零 | 零 | 立即返回。 | 立即放弃。 | 直接发送RST包,自身立即复位,不用经过2MSL状态。对端收到复位错误号。 |
非零 | 非零 | 阻塞直到l_linger时间超时或数据发送完成。(套接字必须设置为阻塞) | 在超时时间段内保持尝试发送,若超时则立即放弃。 | 超时则同第二种情况,若发送完成则皆大欢喜。 |
取值方案:
a. send buffer中的所有数据都被发送并且得到对方TCP的应答消息(这种应答并不是意味着对方应用程序已经接收到数据)
b.延迟时间消耗完。在延迟时间被消耗完之后,send buffer中的所有数据都将会被丢弃。
这种关闭称为“优雅的”关闭。
setsockopt()函数的作用是设置套接字的选项。
man手册查阅函数原型:
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int getsockopt(int sockfd, int level, int optname,
void *optval, socklen_t *optlen);
int setsockopt(int sockfd, int level, int optname,
const void *optval, socklen_t optlen);
参数:
返回值:
总结:
通过setsockopt可以设置SO_LINGER,从而实现优雅的关闭连接
示例:
struct linger tmp = {1, 1};
setsockopt(sockfd, SOL_SOCKET, SO_LINGER, &tmp, sizeof(tmp));