Skip to content

artiomn/cpp-network-tasks

Repository files navigation

Repository with a code for the Geekbrains students

Это репозиторий, содержащий код для студентов, проходящих курс "Сетевое программирование на C++" в GeekBrains.

Начало работы

Чтобы начать работать:

  • Если Docker не установлен в системе, установите его.
  • Если Git не установлен в системе, установите его.
  • Склонируйте репозиторий: git clone https://github.com/artiomn/cpp-network-tasks.git.
    Внимание: склонируйте репозиторий в каталог, содержащий только латинские символы в пути!
  • Зайдите в каталог cpp-network-tasks.
  • Запустите скрипт ./build_dockerized.sh

Если это первый запуск, пройдёт значительное время перед тем, как вы получите результат.
Возможно, что вам потребуется установить Docker.

Для запуска IDE QtCreator выполните из каталога cpp-network-tasks следующую команду: ./run -q.
Будет запущена IDE, в которой необходимо открыть, как проект, файл CMakeLists.txt в каталоге /home/developer/src или /usr/src/gb/src (первый каталог - ссылка).

FAQ

Как сделать домашнее задание, чтобы преподаватель его посмотрел?

Чтобы ваше задание не получило статус "Не сдано" автоматически, ещё до проверки его преподавателем, выполните несколько правил:

  • Проверьте, что код скомпилируется.
  • Для сборки используйте CMake.
  • Оформите код согласно кодовому стилю.

Подходящий вариант стиля для ClangFormat находится в репозитории: code-style.clang-format.

* Файл стиля был предоставлен Henryk ll Selenya.

Пример оформления вы увидите в примерах к уроку.

Кратко:

  • В качестве отступов используются пробелы.
  • Ширина отступа 4 пробела.
  • Открывающая фигурная скобка на следующей строки после имени.
  • После if, for и подобных операторов - один пробел до скобки.
  • После имён функций и методов нет пробелов.
  • После открывающей и перед закрывающей круглыми скобками нет пробелов.
  • После каждой запятой и точки с запятой - пробел.
  • Названия классов пишутся в CamelCase.
  • Названия функций, методов и переменных - в snake_case.
  • Между реализациями функция и методов ставится две пустые строки.
  • Внутри тела функций и методов не допускается более одной пустой строки.
  • Атрибуты классов оканчиваются на _.
  • Комментарии желательно оставлять на английском языке. В примерах они, местами, на русском. Исключительно потому, что примеры учебные.

Правильный вариант оформления:

int main()
{
    std::cout
        << "Getting name for \"" << host_name << "\"...\n"
        << "Using getaddrinfo() function." << std::endl;

    addrinfo hints =
    {
        .ai_flags= AI_CANONNAME,
        // Неважно, IPv4 или IPv6.
        .ai_family = AF_UNSPEC,
        // TCP stream-sockets.
        .ai_socktype = SOCK_STREAM,
        // Any protocol.
        .ai_protocol = 0
    };

    // Results.
    addrinfo *servinfo = nullptr;
    int status = 0;

    if ((status = getaddrinfo(host_name.c_str(), nullptr, &hints, &servinfo)) != 0)
    {
        std::cerr << "getaddrinfo error: " << gai_strerror(status) << std::endl;
        return EXIT_FAILURE;
    }

    for (auto const *s = servinfo; s != nullptr; s = s->ai_next)
    {
        std::cout << "Canonical name: ";
        if (s->ai_canonname)
             std::cout << s->ai_canonname;
        std::cout << "\n";

        assert(s->ai_family == s->ai_addr->sa_family);
        std::cout << "Address type: ";

        if (AF_INET == s->ai_family)
        {
            char ip[INET_ADDRSTRLEN];
            std::cout << "AF_INET\n";
            sockaddr_in const * const sin = reinterpret_cast<const sockaddr_in* const>(s->ai_addr);
            std::cout << "Address length: " << sizeof(sin->sin_addr) << "\n";
            in_addr addr = { .s_addr = *reinterpret_cast<const in_addr_t*>(&sin->sin_addr) };

            std::cout << "IP Address: " << inet_ntop(AF_INET, &addr, ip, INET_ADDRSTRLEN) << "\n";
        }
        else if (AF_INET6 == s->ai_family)
        {
            char ip6[INET6_ADDRSTRLEN];

            std::cout << "AF_INET6\n";
        }
        else
        {
            std::cout << s->ai_family << "\n";
        }
        std::cout << std::endl;
    }
    std::cout << std::endl;

    freeaddrinfo(servinfo);

    return EXIT_SUCCESS;
}

К оглавлению ⮐

Я художник, я так вижу, мне плевать на правила оформления

Ваша работа сразу автоматически отправляется в помойку.

К оглавлению ⮐

Надо ли обновляться и как?

Иногда - надо. Когда в код или образ вносятся изменения, о чём вам должны сообщить. Если вы работаете с Git репозиторием, код обновляется следующим образом:

git pull 

Если вам предоставляется архив, преподаватель обновит его сам.

Docker образы могут быть обновлены следующими командами:

artiomn/gb-build-image
artiomn/gb-qt-creator-image

К оглавлению ⮐

Как собрать примеры?

Сборка производится, используя CMake, поэтому:

  • Вы можете использовать любую современную IDE для сборки.
  • Скрипт ./build.sh.
  • Прямой запуск CMake.

Сборка не подгружает зависимости автоматически. Поэтому, для того, чтобы собрать без необходимости заниматься установкой множества пакетов, используется подготовленная среда. Она представляет собой Docker-контейнер, образ которого лежит на docker.hub. Сборка в ней запускается через скрипт ./build_dockerized.sh.

Под Windows сборка была проверена на MSVS 2019 и собранные артефакты будут находиться в src\out\build\windows-default\bin. Собираться под Windows будет не всё, есть примеры только под Linux.

К оглавлению ⮐

Сборка не проходит, вообще не собирается ничего

Может быть несколько причин из-за которых не проходит сборка. Для начала, убедитесь, что у вас:

Далее, проверьте, что каталог в котором производится сборка, не содержит в пути не латинских символов, пробелов и спецсимволов.

Не делайте каталог вида: ~/Общедоступные/user/geekbrains/lessons/C++-network/Programming_Lessons & Code/Репозиторий!/cpp-network-tasks.
Для большинства сборок - это верный путь к проблемам, о которых не знали разработчики.

Положите репозиторий в каталог с нормальным именем, например ~/projects/cpp-network-tasks.

Если вы уже собирали проект локально и хотите собрать его в Docker или, наоборот, собирали в Docker и хотите собрать локально, CMake выдаст ошибку, похожую на следующую:

CMake Error: The current CMakeCache.txt directory /home/user/projects/cpp-network-tasks/build/CMakeCache.txt is different than the directory /usr/src/gb/build where CMakeCache.txt was created. This may result in binaries being created in the wrong place. If you are not sure, reedit the CMakeCache.txt
CMake Error: The source "/home/artiom/user/cpp-network-tasks/src/CMakeLists.txt" does not match the source "/usr/src/gb/src/CMakeLists.txt" used to generate cache.  Re-run cmake with a different source directory.

Что говорит о том, что конфигурации CMake различаются, вы запускаете его в разном окружении.

Чтобы исправить это, удалите каталог build и запустите сборку заново:

➭ rm -rf build && ./build_dockerized.sh

К оглавлению ⮐

Почему используется Linux?

  • Потому что, на Linux и BSD системах работают большинство сетевых приложений.
  • На Linux работает автор курсов.
  • Кроме Linux есть множество других ОС, и рассмотреть особенности каждой невозможно.
  • Перевод кода на Windows оговорён.
  • По возможности, код и так кроссплатформенный.

К оглавлению ⮐

Могу ли я собрать код на Windows?

Да, возможно собрать часть кода. Сборка проверялась на MS Visual Studio 2019.
Чтобы собрать код, надо открыть корневой CMakeLists.txt, как CMake проект.

Но есть следующие проблемы:

  • Есть код специфичный для Linux, например перехватчик вызовов, который будет собираться и работать только на этой платформе.
  • Некоторый код просто не был адаптирован для Windows, и его сборка выключена.
  • Есть редкие примеры, которые собираются, но работать корректно не будут (один из таких - асинхронный сервер на select()). Оно не работает, потому что не было достаточно времени и мотивации, чтобы доработать под Windows. Если вы считаете, что можете доделать такой код - You're welcome.
  • В Windows есть не все библиотеки, а CMake не имеет, например модуля для поиска Qt, если Qt не установлен. Это приводит к тому, что пример не просто нельзя собрать, если чего-то не хватает, а падает сборка. Конечно, возможно это исправить, если вы считаете, что нужно, репозиторий открыт для правок.

Также, есть некоторый код, специфичный для Windows, но в уроках он, как правило, не упоминается.

К оглавлению ⮐

А есть что-то про CMake?

Есть:

К оглавлению ⮐

Docker - что это?

Предполагается, что в процессе работы с курсом, вы будете активно использовать поиск.
Соответственно, Google поможет.
Если очень кратко, Docker - это один из вариантов реализации автоматизации инфраструктуры контейнеризации.
Он позволяет изолировать приложения в контейнерах, образы которых скачаны из репозитория. Здесь он нужен для того, чтобы:

  • Вы могли собрать код, не устанавливая лишних библиотек.
  • Вы могли проверить сборку тем же самым компилятором, что и проверяющий.

Напомню, что образ с инструкциями лежит на Docker.hub. У GeekBrains есть поясняющее видео про C++ в Docker.

К оглавлению ⮐

Как использовать Docker?

На Windows только вместе с Linux подсистемой.
На Linux его надо установить, а как, зависит от вашего дистрибутива. Например, в deb-based это делается по следующей инструкции.

К оглавлению ⮐

У меня сборка только под суперпользователем (root) запускается, почему?

Управлять Docker, в том числе и запускать или останавливать контейнеры могут только:

  • Пользователь root.
  • Пользователи в группе docker.

Добавить вашего пользователя в группу Docker возможно по-разному. Один из вариантов, который будет работать для многих дистрибутивов:

$ sudo usermod -a -G docker "${USER}"

После этого надо завершить сессию, например выйти на Login Screen, и снова войти.

К оглавлению ⮐

Могу ли я собирать в IDE?

Это зависит от IDE. Возможно использовать удалённую сборку по SSH (сервер установлен в образе), некоторые IDE, такие как CLion, поддерживают работу с Docker напрямую.

К оглавлению ⮐

CLion

Пример настройки CLion показан здесь.

Настройки конфигурации Docker показаны на скриншоте:

Настройки конфигурации CMake:

К оглавлению ⮐

QtCreator

Раньше QtCreator не поддерживал удалённую сборку по SSH.

Есть вариант настройки с подмонтированием каталога через SSHFS. Но все пути к инклудам, а также библиотекам, естественно, будут некорректны, т.к. в контейнере они другие.

Возможно самый просто вариант - установить QtCreator в контейнер и запустить оттуда. На данный момент для этого собран образ. Чтобы запустить его, используйте:

./run -q

QtCreator, запущенный в Docker

К оглавлению ⮐

Не могу подключиться к Docker либо IDE его не видит, что делать?

Проверьте:

  • Установлен ли у вас Docker. Если нет - установите.
  • Достаточно ли прав у вашего пользователя, что с Docker взаимодействовать.

В большинстве дистрибутивов, при установке Docker создаёт группу docker, что вы можете проверить, выполнив следующую команду:

$ grep docker /etc/group
docker:x:997:

Видно, что пользователя в этой группе нет. Добавьте его туда:

$ sudo usermod -a -G docker "$USER"
$ grep docker /etc/group
docker:x:997:artiom

После того, как вы перелогинитесь в системе, группа будет видна:

$ groups
sys network power video storage lp input audio wheel artiom docker

К оглавлению ⮐

В образе чего-то не хватает

Возможно, образ устарел. Обновите его:

$ docker pull artiomn/gb-build-image
Using default tag: latest
latest: Pulling from artiomn/gb-build-image
Digest: sha256:be8e76c39543bd03f503a294d96dc578c5ad90b77c1473e6b03ef1feb88c0b0c
Status: Downloaded newer image for artiomn/gb-build-image:latest
docker.io/artiomn/gb-build-image:latest

К оглавлению ⮐

Работая в Docker я не могу испортить систему?

Можете. Контейнер запускается в privileged режиме. Т.е. из него возможно создавать устройства, а значит испортить всё, что угодно. Это требуется для того, чтобы сети, в частности Yggdrasil, могли создать TUN устройство.

К оглавлению ⮐

Как запустить собранное?

Если вы производили сборку, как указано выше, собранные бинарные файлы будут находиться в каталоге build/bin. Запустить вы их можете напрямую, однако из-за отсутствующих в системе зависимостей работать может не всё. Поэтому, запуск также производится в контейнере, используя команду ./run, которой передаются необходимые приложению аргументы и путь к нему.

Пример:

➭ ./run sudo ./build/bin/ping google.com
Pinging "google.com" [64.233.165.113]
Start to sending packets...
Sending packet 0 to "google.com" request with id = 29
Receiving packet 0 from "google.com" response with id = 29, time = 15.5ms

К оглавлению ⮐

Как запустить консоль?

  • ./run
  • docker-compose run --rm gb - для тех, кто пользуется docker-compose.

Обратите внимание: консоль запускается через скрипт ./run в корне репозитория, не через docker run.

К оглавлению ⮐

Где взять Netcat под Windows?

Например, здесь.

Внимание!
Windows Defender может заблокировать Netcat, определив его, как Netcat.Hacktool. В таком случае, просто отключите "защиту реального времени".

К оглавлению ⮐

Всё делаю правильно, но что-то не подключается

Такая проблема была у одного из студентов. Он выяснил, что Netcat подключался на IPv6 адрес, тогда как сервер прослушивал только IPv4. Как исправить? Зависит от приложения. Задайте ему не доменное имя, а IPv4 адрес явно, при возможности. Для Netcat возможно использовать опцию -4 (не все реализации её поддерживают).

К оглавлению ⮐

Я нашёл ошибку в коде, могу ли я её исправить

Да. Следуя обычному процессу Guthub:

  • Сначала делаете форк репозитория.
  • Клонируете его, исправляете ошибку.
  • Делаете Pull request.

Или просто можете просто завести Issue. Но, в этом случае, обещать быстрое исправление я не могу.

К оглавлению ⮐

А у меня вопрос!

Замечательно. Но прежде, чем задавать его преподавателю, вы пробовали найти ответ? Возможно, что его надо лишь поискать? У преподавателя не так много времени для того, чтобы делать это за вас. Если ответа нет - задавайте.

К оглавлению ⮐