Как воспроизвести ошибку принятия в Linux - PullRequest
0 голосов
/ 13 ноября 2018

Я изучаю Том 1 для сетевого программирования Unix, хочу воспроизвести ошибку подтверждения для RST в Linux.

  1. сервер: вызов socket(), bind(), listen() и sleep(10)
  2. клиент: звонок socket(), connect(), setsockopt() из LINGER, close() и return
  3. сервер: звонок accept()

Я думаю, что на 3-м шаге появится сообщение об ошибке типа ECONNABORTED, но нет.

Хочу узнать почему?

Буду признателен, если вы мне поможете.

Сервер является следующим code:

#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <stdio.h>
#include <strings.h>
#include <unistd.h>

int main(int argc, char* argv[]) {
    int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    struct sockaddr_in addr;

    bzero(&addr, sizeof addr);
    addr.sin_family = AF_INET;
    addr.sin_port = htons(6666);
    inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr);

    bind(sock, (struct sockaddr*)(&addr), (socklen_t)(sizeof addr));
    listen(sock, 5);
    sleep(10);

    if (accept(sock, NULL, NULL) < 0)
        perror("error");
    else
        printf("right");

    return 0;
}

Следующий клиент code

#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <stdio.h>
#include <strings.h>
#include <unistd.h>

int main(int argc, char* argv[]) {
    int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    struct sockaddr_in addr;

    bzero(&addr, sizeof addr);
    addr.sin_family = AF_INET;
    addr.sin_port = htons(6666);
    inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr);

    connect(sock, (struct sockaddr*)(&addr), (socklen_t)(sizeof addr));

    struct linger ling;
    ling.l_onoff = 1;
    ling.l_linger = 0;
    setsockopt(sock, SOL_SOCKET, SO_LINGER, &ling, sizeof ling);
    close(sock);

    return 0;
}

Ответы [ 2 ]

0 голосов
/ 22 декабря 2018

Linux accept () (и accept4 ()) передает уже ожидающие сетевые ошибки на новом сокете как код ошибки от accept ().Это поведение отличается от других реализаций сокетов BSD.Для надежной работы приложение должно обнаружить сетевые ошибки, определенные для протокола после accept (), и обработать их как EAGAIN, повторив попытку.В случае TCP / IP это ENETDOWN, EPROTO, ENOPROTOOPT, EHOSTDOWN, ENONET, EHOSTUNREACH, EOPNOTSUPP и ENETUNREACH.

http://man7.org/linux/man-pages/man2/accept.2.html

0 голосов
/ 20 ноября 2018

Неа. Я думаю, что вы получите пустое, но полное соединение (без данных). Ядро будет управлять установлением полного соединения, а затем получит немедленный пакет FIN (то есть EOF, а не сброс) и обработает его (или подождет, пока процесс пространства пользователя закроет свою сторону, чтобы отправить FIN на другую сторону) Для прерывания соединения вам необходимо перезагрузить клиентский компьютер (или сервер), не позволяя ему отправлять пакеты FIN (или отключая его от сети до перезагрузки). ACK никогда не получен, поэтому вы выиграли не получен RST от ACK.

RST-пакеты автоматически отправляются ядром, когда между двумя сторонами возникает некоторое несовпадение состояний. Чтобы это произошло в правильной реализации, вы должны принудительно вызвать такое несоответствие состояния (именно поэтому необходима перезагрузка компьютера)

  • Установите соединение между обеими сторонами и остановите его (в спящем режиме), чтобы убедиться, что соединение находится в УСТАНОВЛЕННОМ состоянии перед отсоединением кабеля.
  • физически отключить одного из пиров от сети, чтобы вы не позволяли его трафику идти в сеть.
  • перезагрузите компьютер, чтобы все сокеты были в состоянии IDLE.
  • переподключите кабель. Как только ожидающая машина выйдет из спящего режима и снова начнет отправлять пакеты, она получит сегмент RST с другой стороны, поскольку она была перезагружена, и TCP не знает об этом соединении.

Другие способы получения сегмента RST включают неверные реализации TCP или искажение пакетов в пути (изменение порядковых номеров отправителя или получателя в пути)

Целью пакетов RST является не добавление функциональности в TCP, а обнаружение неправильного поведения, чтобы не было средств для сброса при правильном использовании сокетов. Слушающий системный вызов позволяет вам резервировать ресурсы в пространстве ядра, чтобы процесс пользовательского пространства мог подготовиться к обработке соединения, пока клиенты пытаются подключиться. Если вы делаете то, что намереваетесь, вы получите соединение без данных, но с действительным соединением, SO_LINGER существует, чтобы вызвать потерю статуса, когда у машин нет времени отправлять пакеты друг другу ... но при подключении все соединение обрабатывается в ядре, и прерывание не ожидается.

...