Помогите разобраться с динамическими библиотеками (загрузка/выгрузка во время выполнения)

Модератор: Модераторы разделов

theven
Сообщения: 5
ОС: Gentoo

Помогите разобраться с динамическими библиотеками

Сообщение theven »

Интересуют возможности по загрузке/выгрузке динамических библиотек во время выполнения.

У сервера есть подключаемые службы. Каждая служба в своей динамической библиотеке. При работе во время выполнения загружаются необходимые библиотеки, создаются объекты служб (по одному на библиотеку). В библиотеках есть синглтоны (общие данные), от них не избавиться.

Хочется иметь возможность на лету заменять функциональность библиотек. Т.е. отправлять на сервер новую версию библиотеки и делать "подмену". Но тут есть два варианта.
1. Сначала полностью выгружать старую версию, потом загружать новую.
2. Сначала загружать новую, делать "быструю подмену", потом выгружать старую.
Второй вариант естественно намного более предпочтителен, т.к. имеет намного меньшую задержку в работе.
Я ещё не пробовал, интересно будет ли работать. Я предполагаю, что первый вариант работать будет, а вот со вторым возникнут проблемы из-за общих данных.

Также хочется загрузить два объекта одной и той-же службы, но чтобы общие данные у каждой службы били свои. Тут что-нибудь можно сделать? Может можно загрузить две библиотеки? Делать можно всё что угодно, вносить изменения в код, переименовывать файлы библиотек и т.п.

Если есть литература, буду благодарен.
Спасибо сказали:
Аватара пользователя
RasenHerz
Сообщения: 1341
ОС: Arch Linux amd64

Re: Помогите разобраться с динамическими библиотеками

Сообщение RasenHerz »

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

1) Изучил файл <dlfcn.h>. понял что-такое dlopen(), dlsym(), dlclose() - для базовой функциональности этого хватит.
2) Продумал интерфейс плагина и решил что, во-первых, от каждого плагина требуются функции инициализации(в каждом плагине она должна называтся одинаково), соединения с сервером, получения размера файла, самого файла, ну и конечно разрыва соединения с сервером; во-вторых, все функции плагина должны быть легко доступны приложению, поэтому я решил создать стуктуру, поля которой будут хранить адреса необходимых функций, структура создается в главном приложении и передается в функцию инициализирующую плагин.
3) Набросал простенький плагин:

Код: Выделить всё

#include "ftp.h"
#include <stdio.h>

FTP *ftpserv;
int logged = 0;

extern "C" int init_plugin(PLUGIN *plugin){
    if (!plugin) return 0;
    printf("Invoking ftp_init_plugin()\n");
    ftpserv = new FTP();
    int ret = (ftpserv) ? 1 : 0;
    plugin->connect = ftp_connect;
    plugin->get_size = ftp_get_size;
    /* и так далее */
    return ret;
}

extern "C" int ftp_connect(char *server){
    printf("Invoking ftp_connect(%s)\n", server);
    if(ftpserv->connect_to(server)){
        if (ftpserv->anon_login()){
            ftpserv->PASV();
            logged = 1;
            return logged;
        }
        else
            return 0;
    }
    else
        return 0;
}

extern "C" int ftp_get_size(char *file){
    printf("Invoking ftp_get_size(%s)\n", file);
    if (!logged)
        return 0;
    return (ftpserv->SIZE(file));
}

4) написал код клиента:

Код: Выделить всё

int main(int argc, char** argv) {
    HANDLE ftp_handle = 0;
    ftp_handle = dlopen("./libftp.so", RTLD_LAZY); /* открываем динамическую библиотеку */
    if (!ftp_handle){
        perror("dl");
        dlclose(ftp_handle);
        return (EXIT_FAILURE);
    }
    PLUGIN *pl = new PLUGIN;
    INIT_PLUGIN init = 0; /* указатель на функцию */
    init = (INIT_PLUGIN)dlsym(ftp_handle, INIT_FUNC_NAME); /* ищем функцию в библиотеке */
    if (!init){
        perror("dl");
        dlclose(ftp_handle);
        return (EXIT_FAILURE);
    }
    init(pl);
    pl->connect("127.0.0.1");
    /* и другие вызовы */
    return (EXIT_SUCCESS);
}


вот вроде и все.
что касается вашего вопроса насчет выгрузки библиотек и подмены функций, то дело, как говорится, хозяйское - можете сначала выгружать старую библиотеку, а потом загружать новую, а можно и наоборот.
делать "подмену" тоже просто - загружаете новую библиотеку и заменяете в старой структуре (от старой библиотеки) необходимые поля.
Спасибо сказали:
theven
Сообщения: 5
ОС: Gentoo

Re: Помогите разобраться с динамическими библиотеками

Сообщение theven »

Загрузчик делает чтобы в памяти всегда находилась только одна копия библиотеки и не загружает её повторно. На что он смотрит при загрузке? Что нужно сделать с библиотекой чтобы он решил что это уже другая библиотека?
Спасибо сказали:
Аватара пользователя
Portnov
Модератор
Сообщения: 1786
Статус: Матёрый линуксоид
ОС: Debian testing/unstable

Re: Помогите разобраться с динамическими библиотеками

Сообщение Portnov »

Подозреваю, что сменить soname. Но не уверен.
Работа: Ubuntu 9.10
Дом: Debian testing/unstable и на всякий случай winxp в virtualbox.
Для разнообразия: моя домашняя страница -http://iportnov.ru
Спасибо сказали:
Аватара пользователя
RasenHerz
Сообщения: 1341
ОС: Arch Linux amd64

Re: Помогите разобраться с динамическими библиотеками

Сообщение RasenHerz »

theven писал(а):
20.02.2009 20:21
Загрузчик делает чтобы в памяти всегда находилась только одна копия библиотеки и не загружает её повторно. На что он смотрит при загрузке? Что нужно сделать с библиотекой чтобы он решил что это уже другая библиотека?

попробую сегодня покопаться с этим, может чего найду. а нельзя ли добавлять к билиотекам какое-нибудь расширение, к примеру, указывающее ее версию? что-то вроде libftp.so.0.0.1
Спасибо сказали:
theven
Сообщения: 5
ОС: Gentoo

Re: Помогите разобраться с динамическими библиотеками

Сообщение theven »

RasenHerz писал(а):
20.02.2009 21:33
попробую сегодня покопаться с этим, может чего найду. а нельзя ли добавлять к библиотекам какое-нибудь расширение, к примеру, указывающее ее версию? что-то вроде libftp.so.0.0.1

Ещё проблема в том что в библиотеках есть общие данные (статические члены), и даже если библиотеку переименовать он всё равно использует одни и те-же данные. Что с функциональностью происходит я вообще чего-то запутался. Поэтому и прошу помощи, не понимаю я как это дело работает.
Спасибо сказали: