Добавление универсальной поддержки входа в C++ совместно использовало библиотеку

Сводка

сокет TCP является экземпляром конечной точки определенный IP-адресом и портом в контексте или конкретного соединения TCP или состояния слушания.

порт А является идентификатором виртуализации определение сервисной конечной точки (в отличие от сервиса экземпляр конечная точка иначе идентификатор сессии).

сокет TCP А не соединение , это - конечная точка определенного соединения.

могут быть параллельные соединения к сервисной конечной точке , потому что соединение определяется [1 114] и его локальное и удаленное конечные точки, позволяя трафику быть направленным к определенному сервисному экземпляру.

может только быть один сокет слушателя для данного адреса/комбинации портов .

Выставка

Это было интересным вопросом, который вынудил меня вновь исследовать много вещей, я думал, что очень хорошо знал. Вы думали бы, что имя как "сокет" будет очевидно: это было, очевидно, выбрано для вызывания формирования изображений конечной точки, в которую Вы включаете сетевой кабель, там будучи сильными функциональными параллелями. Тем не менее, в сетевом языке слово "сокет" несет так много багажа, что тщательная повторная проверка необходима.

В самом широком смысле, порт является точкой входа или выхода. Хотя не используемый в сетевом контексте, французский Word Оттоманская Порта буквально средства дверь или шлюз , далее подчеркивая то, что порты являются конечными точками транспортировки, поставляете ли Вы данные или большие стальные контейнеры.

В целях этого обсуждения я ограничу соображение контекстом сетей TCP-IP. Модель OSI очень хороша, но полностью никогда не реализовывалась, а тем более широко развертывалась в условиях высокого напряжения интенсивного трафика.

комбинацию IP-адреса и порта строго известны как конечная точка и иногда называют сокетом. Это использование происходит с RFC793, исходной спецификацией TCP.

соединение TCP А определяется двумя конечными точками иначе сокеты .

конечная точка (сокет) определяется комбинацией сетевого адреса и порт идентификатор. Обратите внимание, что адрес/порт делает не , полностью определяют сокет (больше на этом позже).

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

Это - пара сокета (с 4 кортежами, состоящий из клиентского IP-адреса, числа клиентского порта, IP-адреса сервера и номера порта сервера), который определяет две конечных точки, который однозначно определяет каждое соединение TCP в Интернете. ( IP TCP Проиллюстрированный Объем 1 , W. Richard Stevens)

На большинстве языков C-derived, соединения TCP устанавливаются и управляли методами использования на экземпляре класса Сокета. Хотя распространено воздействовать на более высокий уровень абстракции, обычно экземпляр класса NetworkStream, это обычно представляет ссылку на объект сокета. Кодеру этот объект сокета, кажется, представляет соединение, потому что соединение создается и управляло методами использования объекта сокета.

В C#, для установления соединения TCP (существующему слушателю) сначала Вы создаете TcpClient. Если Вы не определяете конечную точку к конструктор TcpClient , она использует значения по умолчанию - так или иначе, локальная конечная точка определяется. Тогда Вы вызываете Подключение метод на экземпляре, который Вы создали. Этот метод требует параметра, описывающего другую конечную точку.

Все это немного сбивает с толку и приводит Вас полагать, что сокет является соединением, которое является яйцами. Я трудился под этим недоразумением, пока Richard Dorman не задал вопрос.

сделавший большое чтение и взгляды, я теперь убежден, что это имело бы намного больше смысла иметь класс TcpConnection с конструктором, который берет два аргумента, LocalEndpoint и RemoteEndpoint. Вы могли, вероятно, поддерживать отдельный аргумент RemoteEndpoint , когда значения по умолчанию приемлемы для локальной конечной точки. Это неоднозначно на многоадресных компьютерах, но неоднозначность может быть разрешена с помощью таблицы маршрутизации путем выбора интерфейса с кратким маршрутом к удаленной конечной точке.

Ясность была бы улучшена в других отношениях, также. Сокет не определен комбинацией IP-адреса и порта:

[...] TCP демультиплексирует входящие сегменты с помощью всех четырех значений, которые включают локальные и внешние адреса: целевой IP-адрес, номер целевого порта, исходный IP-адрес и номер исходного порта. TCP не может определить, какой процесс получает входящий сегмент путем рассмотрения целевого порта только. Кроме того, единственная из [различных] конечных точек в [данный номер порта], который получит запросы входящего соединения, является той в слушать состоянии. (p255, IP TCP Проиллюстрированный Объем 1 , W. Richard Stevens)

, Как Вы видите, это не просто возможно, но и довольно вероятно для сетевой службы иметь многочисленные сокеты с тем же адресом/портом, но только один сокет слушателя на конкретном адресе/комбинации портов. Типичные реализации библиотеки представляют класс сокета, экземпляр которого используется, чтобы создать и управлять подключением. Это чрезвычайно неудачно, так как это вызывает беспорядок и имеет вывод к широко распространенному соединению этих двух понятий.

Hagrawal не верит мне (см. комментарии), таким образом, вот реальный образец. Я подключил веб-браузер с http://dilbert.com и затем работал netstat -an -p tcp. Последние шесть строк вывода содержат два примера факта, которые обращаются, и порт недостаточно для однозначного определения сокета. Существует два отличных соединения между 192.168.1.3 (моя рабочая станция) и 54.252.94.236:80 (удаленный сервер HTTP)

  TCP    192.168.1.3:63240      54.252.94.236:80       SYN_SENT
  TCP    192.168.1.3:63241      54.252.94.236:80       SYN_SENT
  TCP    192.168.1.3:63242      207.38.110.62:80       SYN_SENT
  TCP    192.168.1.3:63243      207.38.110.62:80       SYN_SENT
  TCP    192.168.1.3:64161      65.54.225.168:443      ESTABLISHED

, Так как сокет является конечной точкой соединения, существует два сокета с адресом/комбинацией портов 207.38.110.62:80 и еще два с адресом/комбинацией портов 54.252.94.236:80.

я думаю, что недоразумение Hagrawal является результатом моего очень тщательного использования слова, "определяет". Я имею в виду "полностью, однозначно и однозначно определяет". В вышеупомянутом образце существует две конечных точки с адресом/комбинацией портов 54.252.94.236:80. Если все, что Вы имеете, является адресом и портом, у Вас нет достаточной информации для сообщения этих сокетов независимо. Это - недостаточно информации к [1 131], определяют сокет.

Абзац Приложения

два из раздела 2.7 из RFC793 говорят

, соединение А полностью определяется парой сокетов в концах. Локальный сокет может участвовать во многих соединениях с различными внешними сокетами.

Это определение сокета не полезно с точки зрения программирования, потому что это не то же как сокет объект , который является конечной точкой конкретного соединения. Программисту и большей части аудитории этого вопроса программисты, это - жизненное функциональное различие.

Ссылки

  1. IP TCP Проиллюстрированный Объем 1 Протоколы , W. Richard Stevens, 1994 Addison Wesley

  2. RFC793, Институт Информатики, Университет Южной Калифорнии для DARPA

  3. RFC147, Определения Сокета, Joel M. Winett, Lincoln Laboratory

8
задан 16 July 2009 в 09:30
поделиться

6 ответов

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

То есть, в вашей библиотеке укажите абстрактный класс интерфейса регистрации, например:

class Logger
{
public:
    virtual ~Logger () {}
    virtual void log (const std::string& message) = 0;
};

и класс для регистрации Регистратора с помощью:

class Log
{
private:
    static Logger* logger_;
public:
    static void registerLogger (Logger& logger)
    { logger_ = &logger; }

    static void log (const std::string& message)
    { if (logger_ != 0) logger_->log (message); }
};

Ваша библиотека затем регистрирует что-то вроде:

Log::log ("My log message");

Приложение, использующее вашу библиотеку, должно предоставить реализацию Регистратора (т.е. конкретный подкласс) и зарегистрировать его в вашем классе Журнала. Их Logger impl будет реализовывать ведение журнала по своему усмотрению.

Это позволяет использовать вашу библиотеку приложениями, которые используют разные библиотеки регистрации.

Обратите внимание, что приведенный выше код является базовым и не протестирован. На практике вы можете изменить методы ведения журнала, чтобы включить параметр уровня ведения журнала и т. Д.

10
ответ дан 5 December 2019 в 12:11
поделиться

Объявите прототип функции ведения журнала в вашей библиотеке:

extern void __cdecl UserLog(char* stText);

Не реализовывайте ее в своей библиотеке. Пользователь вашей библиотеки должен реализовать эту функцию, и ваша библиотека будет использовать реализацию пользователя.

Реализация пользователя может выглядеть следующим образом (это всего лишь образец):

void __cdecl UserLog(char* stText)
{
  std::cout << stText << std::endl;
}

Это действительно, если ваша библиотека является статической.

В своем коде вы сможете использовать следующее:

class A {
  public: 
  void method(string param1, int param2);
}   

void A::method(string param1, int param2){
   string formatted = str( boost::format( "param1=%s param2=%d" ) % param1 % param2 );
   UserLog( formatted.c_str() );
}
1
ответ дан 5 December 2019 в 12:11
поделиться

Вы можете использовать google-glog. Мне его приятно использовать.

https://github.com/google/glog

Он поддерживает значения отладки для каждого файла, может вести журнал в системном журнале, отправлять вам сообщения электронной почты и множество других полезных функций.

1
ответ дан 5 December 2019 в 12:11
поделиться

системный журнал - тогда вы можете использовать любое средство системного журнала.

или позволить пользователю указать обратный вызов.

0
ответ дан 5 December 2019 в 12:11
поделиться

Используйте log4cxx или log4cplus .

2
ответ дан 5 December 2019 в 12:11
поделиться

Если вы не хотите использовать существующую библиотеку ведения журнала, вы можете попробовать использовать макросы. Я бы рекомендовал предоставить вашу собственную библиотеку и сделать ее доступной с макросами с механизмом форматирования наподобие printf.

Я делал нечто подобное в прошлом. Макрос вызывал объект журнала, который инкапсулирует реальное ведение журнала, которое можно было расширить с помощью плагина.

Но я думаю, что нечто подобное уже сделано в Log4xxx, так что, возможно, стоит взглянуть на это.

Вот предложение (извините, нет времени проверять, надеюсь, оно работает)

header:

#ifdef _MYAPI_IMPL
#define MY_API __declspec(dllexport)
#else
#define MY_API __declspec(dllimport)
#endif

class MY_API Log
{
public:
    enum Level {Error, Warning, Info, Debug};
    Log(Level level, const char* file, int line );
    void operator()(const char* Format, ... );
private:
       const char* m_file;
       Level m_level;
       int m_line;
};

#define __LOG(lvl) (Log(lvl, __FILE__, __LINE__ ))

#define LOG_ERR  __LOG(Log::Error)
#define LOG_WRN  __LOG(Log::Warning)
#define LOG_INF  __LOG(Log::Info)
#define LOG_DBG  __LOG(Log::Debug)

class My_API Logger
{
public:
    virtual void log(const char* message)=0;
};

class MY_API LoggerManager
{
private:
    static LoggerManager* s_inst;
    LoggerManager() {}
        virtual ~LoggerManager() {}
public:
    static LoggerManager* Instance();
    static void Clean();
    addLogger(Logger* newLogger, Log::Level minlevel = Log::Info);
        log(const char* file, int line, Log::Level level, const char* message);
};

Cpp:


Log::Log(Level level, const char* file, int line)
 : m_file(file), m_level(level), m_line(line)
{
}

void Log::operator()(const char* format, ... )
{
    va_list va;
    va_start(va, format);
    char message[LENGTH+1]={0};

    _vsnprintf(message, LENGTH, format, va);

    va_end(va);

    LoggerManager::Instance()->log(m_file, m_line, m_level, message);


};

Другие библиотеки и exe должны иметь возможность вызывать подобный вызов. Им просто нужно включить .h и ссылку на библиотеку.

LOG_INF("Hello %s!", "world");

Обновление: я добавил объяснение, необходимое для механизма регистрации. Также можно превратить макросы в обычный printf, если вы не хотите реализовывать весь механизм ведения журнала.

0
ответ дан 5 December 2019 в 12:11
поделиться
Другие вопросы по тегам:

Похожие вопросы: