当应用进程不想再接收数据时,就可以关闭TCP连接。关闭的方式有两种:如果进程既不想发送数据,也不想接收数据,则可以选择完全关闭;如果进程不想发送数据,但仍可以接收数据,可以执行“半关闭”。
关闭TCP连接可以使用shutdown系统调用:
int shutdown(int sockfd, int how);
sockfd是要关闭的TCP socket的文件描述符,how是用来指定关闭方式:为SHUT_RD则关闭收包,为SHUT_WR则关闭发包,为SHUT_RDWR则都关闭。
shutdown系统调用对应的内核函数为:
1932 SYSCALL_DEFINE2(shutdown, int, fd, int, how)
1933 {
1934 int err, fput_needed;
1935 struct socket *sock;
1936
1937 sock = sockfd_lookup_light(fd, &err, &fput_needed);
1938 if (sock != NULL) {
1939 err = security_socket_shutdown(sock, how);
1940 if (!err)
1941 err = sock->ops->shutdown(sock, how); //指向inet_shutdown函数
1942 fput_light(sock->file, fput_needed);
1943 }
1944 return err;
1945 }
inet_shutdown函数:
811 int inet_shutdown(struct socket *sock, int how)
812 {
813 struct sock *sk = sock->sk;
814 int err = 0;
815
816 /* This should really check to make sure
817 * the socket is a TCP socket. (WHY AC...)
818 */
819 how++; /* maps 0->1 has the advantage of making bit 1 rcvs and
820 1->2 bit 2 snds.
821 2->3 */
822 if ((how & ~SHUTDOWN_MASK) || !how) /* MAXINT->0 */
823 return -EINVAL;
824
825 lock_sock(sk);
826 if (sock->state == SS_CONNECTING) { //连接建立尚未完成
827 if ((1 << sk->sk_state) &
828 (TCPF_SYN_SENT | TCPF_SYN_RECV | TCPF_CLOSE))
829 sock->state = SS_DISCONNECTING;
830 else
831 sock->state = SS_CONNECTED;
832 }
833
834 switch (sk->sk_state) {
835 case TCP_CLOSE:
836 err = -ENOTCONN;
837 /* Hack to wake up other listeners, who can poll for
838 POLLHUP, even on eg. unconnected UDP sockets -- RR */
839 default: //TCP_ESTABLISHED状态下关闭连接会到达这里
840 sk->sk_shutdown |= how;
841 if (sk->sk_prot->shutdown)
842 sk->sk_prot->shutdown(sk, how); //指向tcp_shutdown
843