Telnet chat server for Linux x86_64

Тема в разделе "WASM.BEGINNERS", создана пользователем Hacker, 16 июл 2023.

  1. Research

    Research Active Member

    Публикаций:
    1
    Регистрация:
    6 янв 2024
    Сообщения:
    172
    Kulesh, тебе нужно за этот прайс написать код на насм с теми же глюками как в исходнике на с?
    --- Сообщение объединено, 17 фев 2024 ---
    У тебя внутри DCPlusPlus-0.881, в ресурсах, какой-то ехе файл
     

    Вложения:

    • 1.rar
      Размер файла:
      456 байт
      Просмотров:
      167
  2. Kulesh

    Kulesh Member

    Публикаций:
    0
    Регистрация:
    16 фев 2024
    Сообщения:
    30
    У меня где DCPlusPlus? та которая на ftp или на share http?
    Я хз что там - это оригенальная сборка. Я пользуюсь EiskaltDC++ у меня UNIX

    А тебе вотлично своетю попользватся DCPlusPlus и слезать с Fly
     
  3. CaptainObvious

    CaptainObvious Member

    Публикаций:
    1
    Регистрация:
    18 янв 2024
    Сообщения:
    87
    Сказка ложь, да в ней намёк.
    А в намёке том — упрёк.
    А в упрёке — диво дивное
    и агрессия пассивная.
     
  4. Kulesh

    Kulesh Member

    Публикаций:
    0
    Регистрация:
    16 фев 2024
    Сообщения:
    30
    Деньги нашел. 5000 RUB на карте, ждут своего хозяина.
    Вот рабочая страничка проекта: http://global.net.ru/teletype/
     
  5. alex_dz

    alex_dz Active Member

    Публикаций:
    0
    Регистрация:
    26 июл 2006
    Сообщения:
    458
    Ну за такую сумму наверное надо аукцион устроить!
    а вдруг будет 10 желающих??
    --- Сообщение объединено, 17 фев 2024 ---
    upload_2024-2-17_18-26-17.png
     
  6. Kulesh

    Kulesh Member

    Публикаций:
    0
    Регистрация:
    16 фев 2024
    Сообщения:
    30
    Думаешьот денежной суммы зависит количество исполнителей? То же сишники? или php-шник?
     
  7. HoShiMin

    HoShiMin Well-Known Member

    Публикаций:
    5
    Регистрация:
    17 дек 2016
    Сообщения:
    1.460
    Адрес:
    Россия, Нижний Новгород
    Вот накидал простенький чатик:
    Код (C++):
    1. #include <errno.h>
    2. #include <unistd.h>
    3. #include <sys/types.h>
    4. #include <sys/socket.h>
    5. #include <netinet/in.h>
    6. #include <poll.h>
    7.  
    8. #include <cstdio>
    9. #include <cstring>
    10.  
    11. #include <utility>
    12. #include <vector>
    13. #include <string>
    14. #include <set>
    15. #include <map>
    16.  
    17.  
    18. namespace Auto
    19. {
    20.  
    21. class Fd
    22. {
    23. public:
    24.     static constexpr int k_invalid = -1;
    25.  
    26. private:
    27.     int m_fd;
    28.  
    29. public:
    30.     Fd() noexcept
    31.         : m_fd(k_invalid)
    32.     {
    33.     }
    34.  
    35.     explicit Fd(int fd) noexcept
    36.         : m_fd(fd)
    37.     {
    38.     }
    39.  
    40.     Fd(const Fd&) noexcept = delete;
    41.  
    42.     Fd(Fd&& fd) noexcept
    43.         : m_fd(std::exchange(fd.m_fd, k_invalid))
    44.     {
    45.     }
    46.  
    47.     ~Fd() noexcept
    48.     {
    49.         if (valid())
    50.         {
    51.             ::close(m_fd);
    52.         }
    53.     }
    54.  
    55.     Fd& operator = (const Fd&) noexcept = delete;
    56.  
    57.     Fd& operator = (Fd&& fd) noexcept
    58.     {
    59.         if (&fd == this)
    60.         {
    61.             return *this;
    62.         }
    63.  
    64.         m_fd = std::exchange(fd.m_fd, k_invalid);
    65.  
    66.         return *this;
    67.     }
    68.  
    69.     bool valid() const noexcept
    70.     {
    71.         return m_fd != k_invalid;
    72.     }
    73.  
    74.     explicit operator bool () const noexcept
    75.     {
    76.         return valid();
    77.     }
    78.  
    79.     int fd() const noexcept
    80.     {
    81.         return m_fd;
    82.     }
    83. };
    84.  
    85. } // namespace Auto
    86.  
    87. namespace Poll
    88. {
    89.  
    90. class Entry : public pollfd
    91. {
    92. public:
    93.     Entry(int fd, short events) noexcept
    94.         : pollfd{ fd, events, 0 }
    95.     {
    96.     }
    97.  
    98.     Entry(const Entry&) noexcept = delete;
    99.  
    100.     Entry(Entry&& desc) noexcept
    101.         : pollfd(std::exchange(static_cast<pollfd&>(desc), pollfd{}))
    102.     {
    103.     }
    104.  
    105.     Entry& operator = (const Entry&) noexcept = delete;
    106.  
    107.     Entry& operator = (Entry&& desc) noexcept
    108.     {
    109.         if (&desc == this)
    110.         {
    111.             return *this;
    112.         }
    113.  
    114.         static_cast<pollfd&>(*this) = std::exchange(static_cast<pollfd&>(desc), {});
    115.  
    116.         return *this;
    117.     }
    118.  
    119.     void reset() noexcept
    120.     {
    121.         pollfd::revents = 0;
    122.     }
    123.  
    124.     bool signaled() const noexcept
    125.     {
    126.         return (pollfd::revents & pollfd::events) != 0;
    127.     }
    128. };
    129.  
    130. } // namespace Poll
    131.  
    132.  
    133.  
    134. int main()
    135. {
    136.     // Create the server socket:
    137.     const Auto::Fd serverSocket(::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP));
    138.     if (!serverSocket)
    139.     {
    140.         const int err = errno;
    141.         printf("Unable to create socket: %i (%s)\n", err, strerror(err));
    142.         return -1;
    143.     }
    144.  
    145.     // Bind the server socket to the IP address:
    146.     sockaddr_in serverAddress{};
    147.     serverAddress.sin_family = AF_INET;
    148.     serverAddress.sin_addr.s_addr = INADDR_ANY;
    149.     serverAddress.sin_port = htons(23999);
    150.     const int bindStatus = ::bind(serverSocket.fd(), reinterpret_cast<const sockaddr*>(&serverAddress), sizeof(serverAddress));
    151.     if (bindStatus != 0)
    152.     {
    153.         const int err = errno;
    154.         printf("Unable to bind the server socket: %i (%s)\n", err, strerror(err));
    155.         return -1;
    156.     }
    157.  
    158.     // Start listening:
    159.     const int listenStatus = ::listen(serverSocket.fd(), 128);
    160.     if (listenStatus != 0)
    161.     {
    162.         const int err = errno;
    163.         printf("Unable to start listening: %i (%s)\n", err, strerror(err));
    164.         return -1;
    165.     }
    166.  
    167.     std::map<int, std::string> clientIdentifiers;
    168.     clientIdentifiers.emplace(serverSocket.fd(), "Server");
    169.  
    170.     // Start polling for new connections or for incoming data:
    171.     std::vector<Poll::Entry> pollEntries;
    172.  
    173.     // The first entry will be the server socket, other entries will be client sockets:
    174.     pollEntries.emplace_back(serverSocket.fd(), POLLIN);
    175.  
    176.     while (true)
    177.     {
    178.         const int pollStatus = ::poll(&pollEntries[0], pollEntries.size(), -1);
    179.         if (pollStatus == -1)
    180.         {
    181.             const int err = errno;
    182.             printf("An error has been occured: %i (%s)\n", err, strerror(err));
    183.             continue;
    184.         }
    185.  
    186.         int newClient = Auto::Fd::k_invalid;
    187.         std::set<int> disconnectedClients;
    188.         for (auto& pollEntry : pollEntries)
    189.         {
    190.             if (!pollEntry.signaled())
    191.             {
    192.                 continue;
    193.             }
    194.  
    195.             pollEntry.reset();
    196.  
    197.             if (pollEntry.fd == serverSocket.fd())
    198.             {
    199.                 // The new client is arrived:
    200.                 sockaddr_in clientAddress{};
    201.                 socklen_t clientAddressLength = sizeof(clientAddress);
    202.                 newClient = ::accept(serverSocket.fd(), reinterpret_cast<sockaddr*>(&clientAddress), &clientAddressLength);
    203.                 if (newClient == Auto::Fd::k_invalid)
    204.                 {
    205.                     const int err = errno;
    206.                     printf("Unable to accept the client: %i (%s)\n", err, strerror(err));
    207.                     continue;
    208.                 }
    209.  
    210.                 char identifier[16]{};
    211.                 sprintf(&identifier[0], "%u.%u.%u.%u",
    212.                     (clientAddress.sin_addr.s_addr) & 0xFF,
    213.                     (clientAddress.sin_addr.s_addr >> 8) & 0xFF,
    214.                     (clientAddress.sin_addr.s_addr >> 16) & 0xFF,
    215.                     (clientAddress.sin_addr.s_addr >> 24) & 0xFF
    216.                     );
    217.                 clientIdentifiers.emplace(newClient, identifier);
    218.             }
    219.             else
    220.             {
    221.                 // The client sent a portion of data or disconnected:
    222.                 const char* userIdentifier = "";
    223.                 const auto identifierEntry = clientIdentifiers.find(pollEntry.fd);
    224.                 if (identifierEntry != clientIdentifiers.end())
    225.                 {
    226.                     userIdentifier = identifierEntry->second.c_str();
    227.                 }
    228.  
    229.                 char recvBuffer[1024]{};
    230.                 strcpy(recvBuffer, "\r\e[0;31m");
    231.                 strcat(recvBuffer, userIdentifier);
    232.                 strcat(recvBuffer, ">\e[0m ");
    233.                 const size_t prefixLength = strlen(recvBuffer);
    234.  
    235.                 static const char k_suffix[] = "\r\n";
    236.  
    237.                 const ssize_t receivedSize = ::recv(pollEntry.fd, &recvBuffer[prefixLength], sizeof(recvBuffer) - prefixLength - sizeof(k_suffix), MSG_DONTWAIT);
    238.                 if (!receivedSize)
    239.                 {
    240.                     // The client has been disconnected:
    241.                     disconnectedClients.emplace(pollEntry.fd);
    242.                     ::shutdown(pollEntry.fd, SHUT_RDWR);
    243.                     ::close(pollEntry.fd);
    244.                     continue;
    245.                 }
    246.                 else if (receivedSize < 0)
    247.                 {
    248.                     // Something went wrong:
    249.                     const int err = errno;
    250.                     printf("Unable to read data from the client: %i (%s)\n", err, strerror(err));
    251.                     continue;
    252.                 }
    253.  
    254.                 static const char cmdSetName[] = "/setname ";
    255.                 if (strncmp(&recvBuffer[prefixLength], cmdSetName, sizeof(cmdSetName) - sizeof('\0')) == 0)
    256.                 {
    257.                     recvBuffer[prefixLength + receivedSize] = '\0';
    258.                     if (identifierEntry != clientIdentifiers.end())
    259.                     {
    260.                         identifierEntry->second = &recvBuffer[prefixLength + sizeof(cmdSetName) - sizeof('\0')];
    261.                     }
    262.                     continue;
    263.                 }
    264.  
    265.                 strcpy(&recvBuffer[prefixLength + receivedSize], k_suffix);
    266.  
    267.                 printf("%s", recvBuffer);
    268.  
    269.                 // Broadcast the message to other clients:
    270.                 const size_t formattedSize = prefixLength + receivedSize + sizeof(k_suffix);
    271.                 for (const auto& client : pollEntries)
    272.                 {
    273.                     if ((client.fd == serverSocket.fd()) || (client.fd == pollEntry.fd))
    274.                     {
    275.                         continue;
    276.                     }
    277.  
    278.                     // Ignore possible errors here as we can do nothing with them:
    279.                     ::send(client.fd, recvBuffer, formattedSize, 0);
    280.                 }
    281.             }
    282.         }
    283.  
    284.         // Add the accepted client to the pollset:
    285.         if (newClient != Auto::Fd::k_invalid)
    286.         {
    287.             pollEntries.emplace_back(newClient, POLLIN);
    288.         }
    289.  
    290.         // Remove disconnected clients from the pollset:
    291.         for (auto it = pollEntries.begin(); it != pollEntries.end();)
    292.         {
    293.             if (disconnectedClients.find(it->fd) != disconnectedClients.end())
    294.             {
    295.                 clientIdentifiers.erase(it->fd);
    296.                 it = pollEntries.erase(it);
    297.             }
    298.             else
    299.             {
    300.                 ++it;
    301.             }
    302.         }
    303.     }
    304.  
    305.     return 0;
    306. }
    Копируешь код в main.cpp, собираешь:
    Код (Bash):
    1. g++ ./main.cpp -o ./server
    Он открывает сервер на порту 23999. Если хочешь изменить порт (например, использовать дефолтный телнетовский) - поменяй его на 149й строчке (serverAddress.sin_port = htons(23999);).
    Подключаешься по телнету:
    Код (Bash):
    1. telnet 123.123.123.123 23999
    где 123.123.123.123 - IP сервера, на котором запускаешь.

    Поддерживает команду "/setname Ник". Если ник не задавать - будет писать IP клиента.

    Telnet.gif
     
    MaKsIm нравится это.
  8. alex_dz

    alex_dz Active Member

    Публикаций:
    0
    Регистрация:
    26 июл 2006
    Сообщения:
    458
    как насчет IPv6 сокетов?
    2) почему не perror()?
     
  9. HoShiMin

    HoShiMin Well-Known Member

    Публикаций:
    5
    Регистрация:
    17 дек 2016
    Сообщения:
    1.460
    Адрес:
    Россия, Нижний Новгород
    Без проблем. Если ТСу надо IPv6 - пусть создаст серверный сокет, используя sockaddr_in6, сняв у него IPV6_V6ONLY, а у клиентских смотрит на полученный socklen_t, чтобы понять, с каким адресом надо работать.
    Можно и perror.
     
  10. Research

    Research Active Member

    Публикаций:
    1
    Регистрация:
    6 янв 2024
    Сообщения:
    172
    HoShiMin, в чем выгода использования таких конструкций:
    Код (Text):
    1. namespace Auto
    2. {
    3. class Fd
    4. {
    5. public:
    6.     static constexpr int k_invalid = -1;
    7. private:
    8.     int m_fd;
    9. public:
    10.     Fd() noexcept
    11.         : m_fd(k_invalid)
    12.     {
    13.     }
    14.     explicit Fd(int fd) noexcept
    15.         : m_fd(fd)
    16.     {
    17.     }
    18.     Fd(const Fd&) noexcept = delete;
    19.     Fd(Fd&& fd) noexcept
    20.         : m_fd(std::exchange(fd.m_fd, k_invalid))
    21.     {
    22.     }
    23.     ~Fd() noexcept
    24.     {
    25.         if (valid())
    26.         {
    27.             ::close(m_fd);
    28.         }
    29.     }
    30.     Fd& operator = (const Fd&) noexcept = delete;
    31.     Fd& operator = (Fd&& fd) noexcept
    32.     {
    33.         if (&fd == this)
    34.         {
    35.             return *this;
    36.         }
    37.         m_fd = std::exchange(fd.m_fd, k_invalid);
    38.         return *this;
    39.     }
    40.     bool valid() const noexcept
    41.     {
    42.         return m_fd != k_invalid;
    43.     }
    44.     explicit operator bool () const noexcept
    45.     {
    46.         return valid();
    47.     }
    48.     int fd() const noexcept
    49.     {
    50.         return m_fd;
    51.     }
    52. };
    53. } // namespace Auto
    54. namespace Poll
    55. {
    56. class Entry : public pollfd
    57. {
    58. public:
    59.     Entry(int fd, short events) noexcept
    60.         : pollfd{ fd, events, 0 }
    61.     {
    62.     }
    63.     Entry(const Entry&) noexcept = delete;
    64.     Entry(Entry&& desc) noexcept
    65.         : pollfd(std::exchange(static_cast<pollfd&>(desc), pollfd{}))
    66.     {
    67.     }
    68.     Entry& operator = (const Entry&) noexcept = delete;
    69.     Entry& operator = (Entry&& desc) noexcept
    70.     {
    71.         if (&desc == this)
    72.         {
    73.             return *this;
    74.         }
    75.         static_cast<pollfd&>(*this) = std::exchange(static_cast<pollfd&>(desc), {});
    76.         return *this;
    77.     }
    78.     void reset() noexcept
    79.     {
    80.         pollfd::revents = 0;
    81.     }
    82.     bool signaled() const noexcept
    83.     {
    84.         return (pollfd::revents & pollfd::events) != 0;
    85.     }
    86. };
    87. } // namespace Poll
    Вместо того чтобы написать отдельные функции, и вызывать их в нужном месте.
    Всегда не понимал что движет людьми, которые создают класс для таких задач(да и вообще для любых других).

    Или
    1. namespace Auto
    2. namespace Poll

    Наконец удалось встретить такого разраба в естественной среде обитания,
    расскажи пожалуйста, ато у меня эта неопределенность годами
     
    Последнее редактирование: 18 фев 2024
  11. HoShiMin

    HoShiMin Well-Known Member

    Публикаций:
    5
    Регистрация:
    17 дек 2016
    Сообщения:
    1.460
    Адрес:
    Россия, Нижний Новгород
    Auto - чтобы вручную не закрывать дескрипторы. Когда начинал писать - сразу написал эту обёртку: думал, что дальше понадобится и для клиентов, но в итоге не пригодился.
    А Poll::Entry просто для удобства, чтобы объединить все действия над записью в поллсете в одном объекте.
    В принципе, для такой простой программки можно было вообще ничего не заворачивать.
    --- Сообщение объединено, 18 фев 2024 ---
    Просто объектная модель очень естественна и хорошо ложится на всё, с чем мы работаем.
    Когда код состоит из одной функции- особой разницы нет, но когда в проекте приходится оперировать множеством "чего-то", у чего есть изменяемые свойства, объектная модель возникает сама собой.
    А в языках без сборщика мусора это ещё и способ управления временем жизни ресурсов, чтобы не освобождать данные вручную.
    Да и просто удобно, когда пишешь имя объекта, ставишь точку - и сразу в подсказках видишь, что с ним можно сделать.
     
    MaKsIm нравится это.
  12. Research

    Research Active Member

    Публикаций:
    1
    Регистрация:
    6 янв 2024
    Сообщения:
    172
    Когда точку ставишь и выводит что есть, в этом есть какая-то логика. Кроме этого есть какой-то смысл в этих обьектных моделях?

    А в чем проблема вручную освободить? Выделил память, сделал что-то, освободил память
     
  13. HoShiMin

    HoShiMin Well-Known Member

    Публикаций:
    5
    Регистрация:
    17 дек 2016
    Сообщения:
    1.460
    Адрес:
    Россия, Нижний Новгород
    Считай это просто средством организации кода, когда данные и действия над ними компонуются в единую сущность.
    Преимущество перед процедурной моделью только в читаемости и наглядности кода: можно закрыть внутренности объекта от внешнего мира, можно наглядно строить иерархии объектов (кто чьим подмножеством является) и переопределять действия над данными.
    Всё то же самое можно сделать и обычными функциями, просто будет больше визуального шума, и такой код сложнее читать и поддерживать.
    В плане производительности разницы нет: и процедурная, и объектная модель превращаются в одинаковые вызовы функций - разница есть только для программиста.

    Обычно такая проблема возникает в сложном коде с неоднозначным временем жизни объектов.
    Например, когда ты выделяешь объект, а дальше по коду есть много мест, где надо откатить действия (и освободить его). Когда таких объектов много, и они создаются в разное время, следить за ними становится сложно, легко забыть кого-то освободить (или наоборот, освободить кого-то дважды).
    Концепция RAII избавляет нас от этой рутины: нам больше не надо заботиться о ручном освобождении, компилятор расставит деструкторы сам.
    В итоге код получается короче, визуального шума меньше - и больше нельзя забыть кого-то освободить.
     
    MaKsIm нравится это.
  14. Research

    Research Active Member

    Публикаций:
    1
    Регистрация:
    6 янв 2024
    Сообщения:
    172
    Еще один вопрос совсем не дает мне покоя
    Если сделать структуру из 2 атрибутов, первое поле - память, второе - флаг выделена память или освобождена.

    Т.к. объектов много, создается динамический массив из таких типов данных.
    Выделили память - отметили флагом. Освободили память - отметили флагом.

    Это делается только в том случае если:
    Если надо освободить все объекты, перечисляем их в цикле for, если флаг установлен - освобождаем.

    В чем разница в плане конечного результата? В том что в начале надо создавать структуру из 2 полей?
     
    Последнее редактирование: 18 фев 2024
  15. Kulesh

    Kulesh Member

    Публикаций:
    0
    Регистрация:
    16 фев 2024
    Сообщения:
    30
    Спасибо за премер. Мне не нужны ни IP ни темболее ники, просто poll и отправка и получение сообщений по протаколу
     
  16. HoShiMin

    HoShiMin Well-Known Member

    Публикаций:
    5
    Регистрация:
    17 дек 2016
    Сообщения:
    1.460
    Адрес:
    Россия, Нижний Новгород
    Ну гут, просто убери clientIdentifiers и обработку /setname, и получишь именно то, что тебе нужно.
    Можно обойтись одним полем: если указатель ненулевой - значит, надо освободить. А при освобождении зануляем указатель.
    Но это не решает проблему необходимости ручного освобождения: на каждый return надо вызывать для всех free или close.
    Если же все выделенные объекты класть в коллекцию, а затем по ней бегать for’ом и освобождать - ты придумал сборщик мусора.
    Только в этом случае будут проблемы с передачей владения: например, когда возвращаешь объекты из функций или перекладываешь их из коллекции в коллекцию: всегда придётся следить за тем, чтобы обнулить все указатели в перемещённом объекте и правильно всё скопировать при перемещении.
    В случае использования деструкторов, move-семантики и запрета операторов копирования мы решаем эту проблему очень изящно: объект не получится скопировать, а передача владения делается через std::move, а деструкторы сами почистят неперемещённые объекты.
    Вот и получается, что в плюсах объектная модель - единственный способ автоматизировать рутинные действия.
     
  17. Kulesh

    Kulesh Member

    Публикаций:
    0
    Регистрация:
    16 фев 2024
    Сообщения:
    30
    я не могу прочитать код - там одни скрипты
    --- Сообщение объединено, 18 фев 2024 ---
    макросы
     
  18. HoShiMin

    HoShiMin Well-Known Member

    Публикаций:
    5
    Регистрация:
    17 дек 2016
    Сообщения:
    1.460
    Адрес:
    Россия, Нижний Новгород
    А тебе и не надо, просто собирай и пользуйся.
     
  19. Kulesh

    Kulesh Member

    Публикаций:
    0
    Регистрация:
    16 фев 2024
    Сообщения:
    30
    У меня тут не Windows ребята, и програмирование не такое
     
  20. HoShiMin

    HoShiMin Well-Known Member

    Публикаций:
    5
    Регистрация:
    17 дек 2016
    Сообщения:
    1.460
    Адрес:
    Россия, Нижний Новгород
    Чувак, о каком «не таком» программировании речь?
    Здесь три сотни строчек, которые пишутся за час.
    На ассемблере то же самое займёт не триста, а несколько тысяч. Что ты в них собрался понимать?
    Если не понимаешь даже си - учебник в руки и читаешь до тех пор, пока не поймёшь.