сокет - закрыть (2) отправить пакет RST вместо пакета FIN - PullRequest
0 голосов
/ 01 марта 2019

Я написал простой клиент и сервер, в основном клиент сначала подключается к серверу, а затем отключается с помощью close(2), который выглядит следующим образом:

/* setting server address and other stuff */
...

connect();
close();

между вызовом * 1005 нет никаких других действий* и close().

сервер принимает соединение и использует epoll(7) для мониторинга события EPOLLOUT.Когда epoll сообщает EPOLLOUT, сервер записывает 1 байт клиенту.

     nev = epoll_wait(ep, events, 10, -1);

     for (int i=0; i<nev; i++) {
         std::cout << "ready, events: " << std::hex
             << events[i].events << std::dec << std::endl;
         if (events[i].data.fd == sockfd) {
             int connfd = accept(sockfd, (struct sockaddr*)&client, &len);
             if (connfd < 0) {
                 std::cout << strerror(errno) << std::endl;
                 exit(0);
             }
             std::cout << "accpeted\n";

             struct epoll_event ev;
             ev.events = EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLHUP;
             ev.data.fd = connfd;
             epoll_ctl(ep, EPOLL_CTL_ADD, connfd, &ev);
         } else { 
             if (events[i].events & EPOLLOUT) {
                 write(events[i].data.fd, "1", 1);
                 sleep(1);
             }
         }
    }

tcpdump здесь, 9999 - это сервер:

11:52:11.411988 IP localhost.37776 > localhost.9999: Flags [S], seq 2786125487, win 43690, options [mss 65495,sackOK,TS val 34912846 ecr 0,nop,wscale 7], length 0
11:52:11.412013 IP localhost.9999 > localhost.37776: Flags [S.], seq 1338547838, ack 2786125488, win 43690, options [mss 65495,sackOK,TS val 34912846 ecr 34912846,nop,wscale 7], length 0
11:52:11.412035 IP localhost.37776 > localhost.9999: Flags [.], ack 1, win 342, options [nop,nop,TS val 34912846 ecr 34912846], length 0
11:52:11.413476 IP localhost.9999 > localhost.37776: Flags [P.], seq 1:2, ack 1, win 342, options [nop,nop,TS val 34912847 ecr 34912846], length 1
11:52:11.414869 IP localhost.37776 > localhost.9999: Flags [.], ack 2, win 342, options [nop,nop,TS val 34912847 ecr 34912847], length 0
11:52:11.415882 IP localhost.37776 > localhost.9999: Flags [R.], seq 1, ack 2, win 342, options [nop,nop,TS val 34912847 ecr 34912847], length 0

, последний пакет предлагает клиенту отправить пакет RST для закрытиясвязь.Я не установил опцию SO_LINGER, почему это происходит?

1 Ответ

0 голосов
/ 01 марта 2019

Реализация tcp_close на ядре, в файле net/ipv4/tcp.c.
Ядро объясняется следующим образом:

/* As outlined in RFC 2525, section 2.17, we send a RST here because
 * data was lost. To witness the awful effects of the old behavior of
 * always doing a FIN, run an older 2.1.x kernel or 2.0.x, start a bulk
 * GET in an FTP client, suspend the process, wait for the client to
 * advertise a zero window, then kill -9 the FTP client, wheee...
 * Note: timeout is always zero in such a case.
 */
if (unlikely(tcp_sk(sk)->repair)) {
    sk->sk_prot->disconnect(sk, 0);
} else if (data_was_unread) {
    /* Unread data was tossed, zap the connection. */
    NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPABORTONCLOSE);
    tcp_set_state(sk, TCP_CLOSE);
    tcp_send_active_reset(sk, sk->sk_allocation);
}

Ссылка: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/net/ipv4/tcp.c?h=v4.19.26#n2348

...