LINUX.ORG.RU

Избранные сообщения bonta

Наиболее эффективный способ передачи файлов по сети.

Форум — Development

Пишем сетевую файловую систему над FUSE, задача предполагает передачу кучи маленьких файлов (до 10кб) с сервера на клиент и обратно + агрессивное кэширование (без синхронизации с сервером, клиент блокирует любые операции на запись используемых файлов на время работы).
Пытаюсь принять решение касательно протокола передачи, возникла пара вопросов:
1. Как эффективнее передавать данные: по TCP с потерями на контроль доставки или по UDP без попакетного контроля (контролировать чексуммами блоков большого размера, например)?
2. Утилизует ли TCP-поток всю ширину канала? Будет ли выигрыш от приема/передачи через N соединений по количеству ядер процессора?

И касательно FUSE: 3. Можно ли его научить работать асинхронно тогда, когда это возможно?
Последовательное чтение метаданных в директориях с кучей файлов — это боль.

 , , , ,

mersinvald
()

А есть ли в этих наших линуксах профайлеры, для анализа кода на предмет того, где жрётся CPU?

Форум — Development

Сабж. Открытые и свободные разумеется

 

Harald
()

Контроль отправки данных по сети

Форум — Development

Имеется некая структура, которую я передаю по сети.
Сейчас, когда структура сериализуется, я делаю так (псевдокод):

static uint32_t magicNumberBegin = ...
static uint32_t magicNumberEnd = ...
stream << magicNumberBegin << struct << magicNumberEnd;
send(stream);
на другой стороне проверяю сходятся ли начальный и конечные числа, если да - считаю что передача удалась, то есть:
read(stream);
stream >> magicNumberBeginTmp >> struct >> magicNumberEndTmp;
if (magicNumberBeginTmp == magicNumberBegin && magicNumberEndTmp == magicNumberEnd) {
    // OK
} else { 
    //fail
}


Размер структуры - ~60 килобайт.

Вопрос: правильно ли я делаю? Если нет, какие предложение будут?
Считать, что порядок байт не имеет значения.

Вопрос 2: как контролировать, что с serial порта считались валидная строка? Строка будет <20 символов. Планирую приблизительно так же.

//device
send(magicNumberBegin, stringSize, string);
//reader
read(magicNumberBeginTMP, stringSizeTMP, string);
if (magicNumberBeginTmp == magicNumberBegin && stringSizeTMP == string.size()) {
    //OK
} else {
    //fail
}

 ,

ymuv
()

Указатель на указатель на функцию

Форум — Development

Небольшой и, возможно, глупый вопрос по Си.

void f(void (**some_func)(void*)) {
    (*some_func)(some_func);
}
...
struct {
    void (*func_ptr)(void*);
    ...
} some_struct = { ... };
f((void (**)(void*))&some_struct);

Является ли приведённый выше код корректным?

По сути дела он базируется на двух предположениях:

1) Адрес первого поля структуры совпадает с адресом структуры. Пустые байты для выравнивания (если компилятор решил их добавить) всегда добавляются после поля, но не перед ним.

2) Указатель на указатель на функцию это самый обычный указатель на данные. Указатель на функцию сам по себе может быть особенным. Например, если речь идёт о гарвардской архитектуре, в которой код и данные имеют разные адресные пространства. Соответственно, указатель на функцию может быть чем-то принципиально иным, нежели указатель на данные (даже банально разрядности адресов в памяти программ и памяти данных могут быть разными). Но указатель на указатель на функцию это уже самое обычное число.

Верны ли эти предположения для всех архитектур, где имеет место быть Си?

 

KivApple
()

Хочу стать программистом C/Linux в 32 года

Форум — Talks

Мне почти 32 года. До этого немного программировал как хобби. Хочу профессионально устроиться разработчиком в области C/Linux или встроенные системы.

Последние несколько месяцев изучал алгоритмы, язык C и низкоуровневое программирование. Сейчас начал читать книгу Керриска по Linux.

Какие мои шансы получить свою первую работу джуниором (в любом городе), скажем, через 4 месяца? К этому времени изучу 2/3 Керриска. Вообще приветствуются любые советы.

Перемещено tailgunner из job

 , , ,

Graduate
()

Отложенное освобождение памяти

Форум — Development

Как известно, в стандартной библиотеке C++ есть умный указатель с подсчётом ссылок std::shared_ptr; при желании можно думать о любом другом указателе с подсчётом ссылок, смысл дальнейшего от этого не изменится.

Как известно, при достижении счётчиком ссылок нуля вызывается deleter для указателя, управляемого shared_ptr-ом. По-умолчанию deleter просто применят оператор delete к указателю.

На что я хочу обратить внимание: работу по вызову деструктора и освобождению памяти делает тот тред и тот код, который сбрасывает счётчик до нуля. Если объект содержит другие shared_ptr в качестве своих полей, то часто освобождение этого объекта вызывает каскад освобождений памяти и приводит к задержкам в выполнении треда. Пример кода, могущий привести к таким каскадным высвобождениям, можно найти, например, тут https://bartoszmilewski.com/2013/11/13/functional-data-structures-in-c-lists/. Там односвязные иммутабельные списки, для предотвращения копирования всего списка при модификации, например, только головы, реализованы с использованием shared_ptr и могут иметь общие хвосты. Короче, с помощью shared_ptr реализуется persistence, я думаю вы знакомы с таким подходом.

Я тут подумал и пришёл к такой идее: завести threadsafe очередь для указателей (точнее, для структур, содержащих указатель + указатель на функцию, знающую что с этим указателем делать, ведь нам придётся стереть типы; но это уже детали) и при создании shared_ptr использовать custom deleter, который при вызове будет просто помещать указатель в очередь. Вызывать же деструкторы и освобождать память будет отдельный поток (или потоки?). Он будет брать очередной указатель из очереди и вызывать для него деструктор и освобождать память. Так мы избавим рабочие потоки от необходимости обслуживать каскады высвобождений памяти.

Я понимаю, что у этого подхода тоже будут performance penalties. Обычно куч всего несколько и при большом числе тредов каждая обслуживает несколько тредов. И если тред-освободитель будет освобождать память, он захватит лок у кучи, в которую могут лезть треды для выделения памяти. Там-то они и будут сталкиваться лбами. Это я понимаю. Но, в отличие от гарантированных длинных задержек, вызванных каскадным высвобождением памяти, тут задержки будут размазаны во времени или будут «распределены» между другими тредами, если они полезут выделять память в момент освобождения; или же, очень вероятно, эти задержки вообще не проявятся, если память выделять не полезут. Надо тестировать под различными нагрузками, заранее трудно сказать.

А что ЛОР про это думает? Дискас.

 , ,

dependent_type
()

Как отправить почту?

Форум — Development

Мне надо, чтобы мой сервер отправлял регистрационные коды пользователям. Использую такую разработку

#include <string>
#include <sstream>
#include <iostream>
#include <ctime>
#include <algorithm>
#include <random>
#include <curl/curl.h>

class EmailAddress 
{
public:
    EmailAddress(const char *email)
        : email_{email}
        {
        }

    EmailAddress(const std::string &email)
        : email_{email}
        {
        }

    EmailAddress(const std::string &email, const std::string &displayName)
        : email_{email.empty() ? "" : "<"+email+">"},
          name_{"\"" + displayName + "\""}
        {
        }

    std::string domain() const
        {
            return email_.substr(email_.find('@') + 1);
        }

    explicit operator const char *() const
        {
            return email_.c_str();
        }

    friend std::ostream &operator<<(std::ostream &out, const EmailAddress &email)
        {
            return out << email.name_ << " " << email.email_;
        }

private:
    std::string email_;
    std::string name_;
};

typedef std::vector<EmailAddress> EmailAddresses;
std::ostream &operator<<(std::ostream &out, const EmailAddresses &emailAddresses);

class Email
{
public:
    Email(const EmailAddress   &from,
          const EmailAddress   &to,
          const std::string    &subject,
          const std::string    &body,
          const EmailAddresses &cc = EmailAddresses())
        : from_{from}
        , to_{to}
        , cc_{cc.empty() ? EmailAddresses(1, to) : cc}
        , subject_{subject}
        , body_{body}
        {
        }

    CURLcode send(const std::string &url,
                  const std::string &userName, 
                  const std::string &password);

private:
    struct StringData {
            std::string msg;
            size_t bytesLeft;
            StringData(std::string &&m) : msg{m}, bytesLeft{msg.size()} {}
            StringData(std::string  &m) = delete;
        };

    static std::string dateTimeNow_();
    static size_t payloadSource_(void *ptr, size_t size, size_t nmemb, void *userp);
    std::string generateMessageId_() const;
    std::string setPayloadText_();

    EmailAddress from_, to_;
    EmailAddresses cc_;
    std::string subject_, body_;
};


CURLcode Email::send(const std::string &url,
                     const std::string &userName,
                     const std::string &password)
{
    CURLcode ret = CURLE_OK;

    struct curl_slist *recipients = NULL;

    CURL *curl = curl_easy_init();

    StringData textData { setPayloadText_() };

    if (curl) {
        std::ostringstream cc;
        cc << cc_;

        curl_easy_setopt(curl, CURLOPT_USERNAME,     userName.c_str());
        curl_easy_setopt(curl, CURLOPT_PASSWORD,     password.c_str());
        curl_easy_setopt(curl, CURLOPT_URL,          url     .c_str());

        curl_easy_setopt(curl, CURLOPT_USE_SSL,      (long)CURLUSESSL_ALL);
        //curl_easy_setopt(curl, CURLOPT_CAINFO,      "/path/to/certificate.pem");

        curl_easy_setopt(curl, CURLOPT_MAIL_FROM,    (const char *)from_);
        recipients = curl_slist_append(recipients,   (const char *)to_);
        recipients = curl_slist_append(recipients,   cc.str().c_str());

        curl_easy_setopt(curl, CURLOPT_MAIL_RCPT,    recipients);
        curl_easy_setopt(curl, CURLOPT_READFUNCTION, payloadSource_);
        curl_easy_setopt(curl, CURLOPT_READDATA,     &textData);
        curl_easy_setopt(curl, CURLOPT_UPLOAD,       1L);
        curl_easy_setopt(curl, CURLOPT_VERBOSE,      1L);

        ret = curl_easy_perform(curl);

        if (ret != CURLE_OK) {
            std::cerr << "curl_easy_perform() failed: "
                      << curl_easy_strerror(ret)
                      << std::endl;
        }

        curl_slist_free_all(recipients);
        curl_easy_cleanup(curl);
    }

    return ret;
}

std::string Email::dateTimeNow_()
{
    const int RFC5322_TIME_LEN = 32;

    std::string ret;
    ret.resize(RFC5322_TIME_LEN);

    time_t tt;

#ifdef _MSC_VER
    time(&tt);
    tm *t = localtime(&tt);
#else
    tm tv, *t = &tv;
    tt = time(&tt);
    localtime_r(&tt, t);
#endif

    strftime(&ret[0], RFC5322_TIME_LEN, "%a, %d %b %Y %H:%M:%S %z", t);

    return ret;
}

inline std::string Email::generateMessageId_() const
{
    const size_t MESSAGE_ID_LEN = 37;

    tm t;
    time_t tt;
    time(&tt);

#ifdef _MSC_VER
    gmtime_s(&t, &tt);
#else
    gmtime_r(&tt, &t);
#endif

    std::string ret;
    ret.resize(MESSAGE_ID_LEN);
    size_t dateLen = std::strftime(&ret[0], MESSAGE_ID_LEN, "%Y%m%d%H%M%S", &t);

    static const std::string alphaNum {
        "0123456789"
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        "abcdefghijklmnopqrstuvwxyz" };

    std::mt19937 gen;
    std::uniform_int_distribution<> distr(0, alphaNum.length() - 1);

    std::generate_n(ret.begin() + dateLen,
                    MESSAGE_ID_LEN - dateLen,
                    [&]() { return alphaNum[distr(gen)]; });

    return ret;
}

size_t Email::payloadSource_(void *ptr, size_t size, size_t nmemb, void *userp)
{
    StringData *text = reinterpret_cast<StringData *>(userp);

    if ((size == 0) || (nmemb == 0) || ((size * nmemb) < 1) || (text->bytesLeft == 0)) {
        return 0;
    }

    if ((nmemb * size) >= text->msg.size()) {
        text->bytesLeft = 0;
        return text->msg.copy(reinterpret_cast<char *>(ptr), text->msg.size());
    }

    return 0;
}

std::string Email::setPayloadText_()
{
    std::string ret = "Date: " + dateTimeNow_() + "\r\n";

    std::ostringstream oss;
    oss << "To: "   << to_   << "\r\n"
           "From: " << from_ << "\r\n";

    if (cc_.size() > 1) {
        oss <<   "Cc: "   << cc_   << "\r\n";
    }

    ret += oss.str();

    ret +=
        "Message-ID: <" + generateMessageId_() + "@" + from_.domain() + ">\r\n"
        "Subject: " + subject_ + "\r\n"
        "\r\n" +
        body_ + "\r\n"
        "\r\n";

    return ret;
}

std::ostream &operator<<(std::ostream &out, const EmailAddresses &emailAddresses)
{
    if (!emailAddresses.empty()) {
        auto it = emailAddresses.begin();
        out << *it;
        while (++it != emailAddresses.end()) {
            out << "," << *it;
        }
    }

    return out;
}

Если я отправляю с mail.ru тогда всё работает хорошо, например:

Email email({ "...@mail.ru", "Name" },
              "...@mail.ru",
              "Subject",
              "Body" );

email.send ( "smtp://smtp.mail.ru:25",
              "...",
              "Password"  );

Но если я отправляю с gmail

Email email({ "...@gmail.com", "Name" },
              "...@gmail.com",
              "Subj",
              "Body");

email.send(   "smtp://smtp.gmail.com:465",
              "...@gmail.com",
              "Password");

я получаю ошибку

* Rebuilt URL to: smtp://smtp.gmail.com:587/ * Hostname was NOT found in DNS cache * Trying 173.194.221.109... * Connected to smtp.gmail.com (173.194.221.109) port 587 (#0) < 220 smtp.gmail.com ESMTP 125sm1125430ljj.26 - gsmtp

EHLO DNPC

< 250-smtp.gmail.com at your service, [xx.xx.xxx.xx] < 250-SIZE 35882577 < 250-8BITMIME < 250-STARTTLS < 250-ENHANCEDSTATUSCODES < 250-PIPELINING < 250-CHUNKING < 250 SMTPUTF8

STARTTLS

< 220 2.0.0 Ready to start TLS * found 174 certificates in /etc/ssl/certs/ca-certificates.crt * server certificate verification OK * common name: smtp.gmail.com (matched) * server certificate expiration date OK * server certificate activation date OK * certificate public key: RSA * certificate version: #3 * subject: C=US,ST=California,L=Mountain View,O=Google Inc,CN=smtp.gmail.com * start date: Thu, 08 Dec 2016 10:53:19 GMT

* expire date: Thu, 02 Mar 2017 10:18:00 GMT

* issuer: C=US,O=Google Inc,CN=Google Internet Authority G2 * compression: NULL * cipher: AES-128-GCM * MAC: AEAD

EHLO DNPC

< 250-smtp.gmail.com at your service, [xx.xx.xxx.xx] < 250-SIZE 35882577 < 250-8BITMIME < 250-AUTH LOGIN PLAIN XOAUTH2 PLAIN-CLIENTTOKEN OAUTHBEARER XOAUTH < 250-ENHANCEDSTATUSCODES < 250-PIPELINING < 250-CHUNKING < 250 SMTPUTF8

AUTH LOGIN

< 334 VXNlcm5hbWU6

Z2lnaWN1Y3UwODhAZ21haWwuY29t

< 334 UGFzc3dvcmQ6

ZGt0Y2Voamxia2ZjbXRranhyZg==

< 235 2.7.0 Accepted

MAIL FROM:<...@gmail.com>

< 250 2.1.0 OK 125sm1125430ljj.26 - gsmtp

RCPT TO:<...@gmail.com>

< 250 2.1.5 OK 125sm1125430ljj.26 - gsmtp

RCPT TO:< ...@gmail.com>

< 553-5.1.2 The recipient address < ...@gmail.com> is not a valid RFC-5321 < 553 5.1.2 address. 125sm1125430ljj.26 - gsmtp * RCPT failed: 553

QUIT

< 221 2.0.0 closing connection 125sm1125430ljj.26 - gsmtp * Closing connection 0 curl_easy_perform() failed: Failed sending data to the peer

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

 , , ,

user08
()

Wheezy Redmond

Галерея — Скриншоты

Избавляюсь от старого хлама на винте, откопал старый скрин дебиана с MATE.

  • иконки - мутант из faenza и tango
  • gtk - что-то самопальное на основе mist для gtk2/gtk3.
  • metacity/marco - конвертация темы для emerald.

 ,

bubblecore
()