Задать вопрос
  • Как изменить настройки работающего контейнера Docker?

    Vamp
    @Vamp
    Единственный официальный способ изменить настройки контейнера - удалить и запустить новый с измененными настройками. Чтобы не терять настройки, удобнее всего записывать их в конфиги формата compose, с которыми работает утилита docker-compose.

    Чтобы не терять данные контейнера их нужно размещать в папках, подключаемых через volume. Всё остальное будет уничтожено при переделке контейнера.
    Ответ написан
    Комментировать
  • Как написать программу работающую со сборщиком мусора?

    Vamp
    @Vamp
    Задание поставлено очень широко. Листинг из примера ниже будет ему в точности соответствовать:

    // Работа с большими объектами
    byte[] b = new byte[65536];
    b[0] = 1;
    System.out.println(b[0]);
    
    // и с маленькими
    String s = "123";
    System.out.println(s.hashCode());
    
    // и с финализируемыми объектами
    Object f = new Object() {
        @Override
        protected void finalize() {
            System.out.println("I'm finalized!");
        }
    };
    // Строго говоря, объекты b и s так же являются финализируемыми,
    // так как наследуют метод finalize() от своего предка.
    // Так что f можно было даже не писать.
    
    System.gc();
    System.gc();
    System.gc();
    System.gc();
    // В этом месте объекты b, s и f пережили 4 цикла сборки.
    // Наверное... ¯\_(ツ)_/¯
    //
    // Более точно можно сказать, запустив программу с
    // аргументом -verbose:gc или с помощью утилиты visualvm
    Ответ написан
    6 комментариев
  • Есть ли разница в сложности освоения разных дистрибутивов, основанных на debian/ubuntu?

    Vamp
    @Vamp
    Как правило, трудностей не возникает. Но всё зависит от того, насколько сильно дистрибутив отличается от своей базы. Ubuntu, например, хоть и основан на Debian, но так сильно от него отличается, что искать решение проблем убунту в дебиановских доках практически бесполезно. Но Mint, основанный на Ubuntu, отличается незначительно, поэтому проблемы минта в доках убунты решаются без проблем.

    Хорошо работает подход при гуглении - добавлять название дистрибутива к поисковому запросу и если нет успеха, то добавить название базового дистрибутива.

    1. "[описание проблемы] kali"
    2. "[описание проблемы] debian"
    3. "[описание проблемы]" (если предыдущие два варианта облажались, гугление безотносительно дистрибутива - единственный оставшийся вариант)
    Ответ написан
    Комментировать
  • Почему не устанавливается расширение php-bcmath?

    Vamp
    @Vamp
    Потому что нужно устанавливать пакет php7.3-bcmath. На вашем же скриншоте видно, что установилась версия модуля для PHP 7.4: php-bcmath is already the newest version (2:7.4+73+ubuntu18.04.1+deb.sury.org+1)
    Ответ написан
    Комментировать
  • Стоит ли уменьшать количество подключенных файлов?

    Vamp
    @Vamp
    В линуксе (а большинство сайтов хостится именно на нем) контент часто запрашиваемых файлов кеширутся в память, так что нагрузка на диск от чтения скриптов будет генерироваться только первыми посетителями сайта. Поэтому не заморачивайтесь и делайте столько файлов, сколько нужно.

    Если хотите точно знать как сильно влияет на производительность то или иное ваше решение в проекте, берите apache bench, siege, yandex.tank и тестируйте. Сразу скажу, разницы между 11 и 5 файлами вы точно не увидите. Впрочем, как между 5 и 555. Но не во всех случаях ответ будет сразу очевиден, поэтому обязательно освойте какую-нибудь тулзу для нагрузочного тестирования и не гадайте на кофейной гуще.
    Ответ написан
    Комментировать
  • Как хранить подключения(Socket) клиентов и надо-ли это делать?

    Vamp
    @Vamp
    Хранить объект конечно нужно, иначе как клиенту отправлять данные?

    Начните с Map, а дальше видно будет. Ещё нужно обязательно предусмотреть регулярную очистку Map от закрывшихся сокетов, иначе получите утечку памяти.
    Ответ написан
    Комментировать
  • Как добавить HTTP заголовки к SOAP запросу?

    Vamp
    @Vamp
    __setSoapHeaders устанавливает заголовки soap запроса, а не http. Они размещаются в элементе Header. По вашему примеру кода получится что-то типа такого:
    <SOAP-ENV:Envelope
        xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
        xmlns:ns1="yourns"
        xmlns:ns2="http://soapinterop.org/echoheader/">
        <SOAP-ENV:Header>
            <ns2:token>token</ns2:token>
            <ns2:user-token>user_id</ns2:user-token>
        </SOAP-ENV:Header>
        <SOAP-ENV:Body>
            <!-- тело запроса -->
        </SOAP-ENV:Body>
    </SOAP-ENV:Envelope>


    Для добавления именно http заголовков нужно создать stream context:
    $aOptions['stream_context'] = stream_context_create([
        'http' => [
            'header' => "token: abc\r\nuser-token: 123"
        ]
    ]);
    
    $oSoapClient = new SoapClient( $url, $aOptions );
    $result = $oSoapClient->__doRequest( $sXml, $url, null, SOAP_1_1 );
    Ответ написан
    3 комментария
  • Возможен ли перехват tcp tls траффика в незашифрованном виде напрямую с устройства?

    Vamp
    @Vamp
    Перехват невозможен, так как шифрование трафика производится на уровне приложения, а не ОС. Ваш единственный способ перехвата - mitm. Но если приложение использует certificate/public key pinning, то и mitm вам не поможет.
    Ответ написан
    Комментировать
  • Что значить atime в stat?

    Vamp
    @Vamp
    Время последнего доступа кого угодно к файлу, на который вызываете stat(). Открытие файла и чтение данных из него обновляет метку atime. Причём последнее зарегистрированное время открытия/чтения необязательно могло быть сделано PHP скриптом.
    Ответ написан
    Комментировать
  • Объекты, имеющие поля сложных типов (Immutable или нет)?

    Vamp
    @Vamp
    В состояние объекта входит состояние объектов сложных типов. С формальной точки зрения объекты обоих ваших классов являются изменяемыми. Однако в JVM существует понятие effectively final - это мутабельный объект, состояние которого не изменяется, хоть и не форсируется модификаторами private и final. Если JVM поймёт, что конкретный объект вашего класса не меняется (другими словами, является effectively final), то к этому объекту могут применяться оптимизации, характерные для неизменяемых объектов.
    Ответ написан
    Комментировать
  • При инициализации класса, загружаются ли в память его instace-члены?

    Vamp
    @Vamp
    Могут загружаться, а могут и нет. JVMS не определяет должны ли загружаться все, часть или вообще никакие типы, на которые ссылается загружаемый класс. Так что данное поведение остаётся на усмотрение разработчика JVM.

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

    Пример:
    import java.time.LocalDateTime;
    import java.util.concurrent.CountDownLatch;
    
    public class A {
    
        private static LocalDateTime ldt;
    
        private static CountDownLatch cdl;
    
        static {
            ldt = LocalDateTime.now();
            cdl = null;
        }
    
        public static void main(String[] args) {
            System.out.println("123");
        }
    
    }

    При запуске данного кода с аргументом JVM "-verbose:class" выведется список всех загруженных классов. Пример запуска на openjdk 12:

    ...
    [0,100s][info][class,load] java.time.temporal.TemporalAccessor source: shared objects file
    [0,100s][info][class,load] java.time.temporal.Temporal source: shared objects file
    [0,100s][info][class,load] java.time.temporal.TemporalAdjuster source: shared objects file
    [0,101s][info][class,load] java.time.chrono.ChronoLocalDateTime source: shared objects file
    [0,101s][info][class,load] java.time.LocalDateTime source: shared objects file
    ...

    Видно, что загрузился LocalDateTime и все имплементируемые им интерфейсы, но CountDownLatch в списке отсутствует, несмотря на то, что существует статическая переменная с этим типом.

    Аналогично происходит и с instance членами - классы, на которые они ссылаются, будут загружаться только по мере необходимости (использования). Вполне нормальна ситуация, когда объекты одного класса активно используются в программе, но при этом не все используемые им типы загружены. Более того, это относится не только к членам класса или объекта, но и к локальным переменным и даже просто коду:

    import java.math.BigDecimal;
    import java.time.LocalDateTime;
    
    public class A {
    
        public static void main(String[] args) {
            if ("world".equals(System.getenv("HELLO"))) {
                System.out.println(LocalDateTime.now());
            } else {
                System.out.println(BigDecimal.TEN);
            }
        }
    
    }

    В этом примере будет загружен класс BigDecimal, но не LocalDateTime. Если инвертировать условие или запустить код с выставленной переменной окружения HELLO=world, то в списке классов появится LocalDateTime, но BigDecimal будет отсутствовать.
    Ответ написан
    2 комментария
  • Почему рекурсия в java уходит в бесконечность?

    Vamp
    @Vamp
    Идеальная задачка для пошаговой отладки. Она есть в любой приличной IDE. Покажу на примере IDEA:

    1. Ставьте на строчке, которую хотите отладить, так называемую точку прерывания (breakpoint).

    5de7eb1ceef0b714535201.png

    2. Запускайте программу в отладочном режиме.

    5de7eb4300731205266204.png

    3. Программа начнёт выполняться как обычно, но когда исполнение дойдёт до строки, помеченной breakpoint'ом, выполнение остановится и в дебаг окне отобразится текущий стек трейс, значения локальных переменных и самое важное для вашей проблемы - кнопки пошагового продолжения.

    5de7ebd9dd5e7287922482.png(на скриншоте я уже проехал несколько шагов вперёд)

    Вот эти 5de7ecb0c3d98348194703.png
    Первая кнопка продвинет выполнение программы на одну строчку. Вторая сделает то же самое, но если в выполняемой строке вызывается какой-то метод, то отладка шагнёт внутрь метода и шаги продолжатся уже в теле вызываемого метода.

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

    Vamp
    @Vamp
    Храните и отображайте в обычной строке. Влезет столько знаков, сколько нужно.
    Ответ написан
  • Где можно почитать/посмотреть про принципы проектирования и написания ПО для стратегически важных объектов?

    Vamp
    @Vamp
    Такие стандарты существуют. Наиболее известные - MISRA C и MISRA C++. Как можно догадаться, для языков С и С++, соответственно. Изначально созданы для автомобильной промышленности, но распространились и на аэрокосмическую отрасль, медицинскую технику, военных и прочие критичные к надёжности области. В том числе и АЭС.

    Из MISRA C выросли SEI CERT C/C++, AUTOSAR General Software Specification, JPL Institutional Coding Standard for the C (стандарт NASA) и ещё куча других.

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

    Помимо этого, существует ворох стандартов, описывающих подходы к организации процесса разработки и контроля качества. У каждой отрасли свои стандарты. Например, AS9100.

    Если вы интересуетесь вопросом чтобы применять подобные техники в повседневном программировании, то не стоит - никакого удовольствия и конкурентного преимущества вы от этого не получите. Если конечно ваше повседневное программирование не включает в себя разработку панели управления АЭС.

    Update 2019-12-30:
    На хабре появилась интересная статья с кратким обзором MISRA.
    Ответ написан
    Комментировать
  • Как правильно между запросами cURL делать паузу?

    Vamp
    @Vamp
    Сразу после вызова функции.

    for ($i=0; $i < 3; $i++) { 
      echo curlNew();
      sleep($sleepTime);
    }
    Ответ написан
    Комментировать
  • Как пользоваться gRPC?

    Vamp
    @Vamp
    1. Надо смотреть какое именно API предоставляет сервер. Если JSON REST, то gRPC не подойдёт. gRPC - отдельный протокол, который должны поддерживать и клиент, и сервер, чтобы можно было по нему взаимодействовать.

    2. Если хотите взаимодействовать с удалённым сервером, то нужен только клиент. Если хотите сами быть для кого-то сервером, предоставляющим gRPC API, то нужен сервер. На PHP нельзя сделать gRPC сервер, видимо поэтому и предлагают node.js. Попробуйте поднять сервер на линуксе, вместо openserver. Тогда появятся команды, описанные в доке, и вообще разработка станет гораздо проще.

    3. Простых доков по gRPC не видел.

    Помимо самого gRPC вам придётся разобраться ещё и с protobuf, так как gRPC основан на нём. Его тоже необходимо установить либо как модуль к PHP, либо как composer зависимость. Помимо этого, удалённый сервер должен предоставить proto файл, на основе которого вы будете делать gRPC клиента. Этот файл необходимо скомпилировать при помощи protoc (компилятора protobuf) с использованием специального плагина к нему - grpc_php_plugin. В результате получится набор PHP скриптов, реализующих gRPC клиента для доступа к API удалённого сервера. Вот эти скрипты вы и будете использовать в своих скриптах для общения с сервером.
    Ответ написан
    3 комментария
  • Как сформировать XML в SOAP на PHP?

    Vamp
    @Vamp
    Вам придется вручную составить XML. Встроенных средств для работы с атрибутами у SoapClient нет.

    $xw = new XMLWriter();
    $xw->openMemory();
    $xw->startElementNS('ns1', 'GetTariffRequest', null);
        $xw->startElement('NeedList');
            $xw->text('1');
        $xw->endElement();
    
        $xw->startElement('Subject');
            $xw->writeAttribute('SbjKey', '1');
        $xw->endElement();
    $xw->endElement();
    
    $s = new SoapClient(...);
    $s->GetTariff(new SoapVar($xw->outputMemory(), XSD_ANYXML));

    XMLWriter здесь только как пример. Составлять строку с XML вы можете любым другим способом.
    Ответ написан
    Комментировать
  • Разные development и production окружения не нарушают концепцию Docker?

    Vamp
    @Vamp
    В dev окружении почти никогда не бывает такой же образ как в prod. Но docker позволяет сделать очень близко к проду при помощи наследования. То есть prod наследуется от, допустим, php:7.3.3-fpm, устанавливает нужные модули и опции php.ini, а dev образ наследуется от prod и доустанавливает xdebug, composer, node, модифицирует только нужные для дева опции php.ini.

    Такая организация позволяет почти не тратить время на актуализацию dev образа. Поменялся prod - в одну команду пересобрали и dev. Очень удобно.

    Корнем всей иерархии будет это базовый prod образ, в котором нет никаких файлов проекта. Уже от него наследуются dev и образы с запакованным приложением. В контейнер на основе dev образа монтируете рабочую директорию проекта и работаете как удобно.

    Иерархия наследования получается примерно такая:
    php:7.3.3-fpm
    └─ prod:base
       ├─ dev:latest
       ├─ prod:0.0.1
       ├─ prod:0.1.15
       └─ prod:1.0.4
          └─ prod:latest  (плавающий тег, указывающий
                           на самый свежий релиз)

    При таком подходе у вас будет 3 докерфайла - prod:base, dev и финальный prod.

    Можно обойтись двумя докер файлами, если на прод подсовывать скрипты проекта через volume, как и в dev. Я как раз использую этот вариант, так как в моей компании применяется continuous delivery. Грубо говоря, это когда почти каждый коммит в master сразу улетает на прод. Если каждый раз собирать новый образ, становится слишком много образов, за которыми приходится отдельно следить и удалять старые, чтобы избежать переполнения реестра. Плюс возникают сложности с обеспечением атомарности деплоя, так как сервис становится недоступен в момент рестарта контейнера, из-за чего приходится городить балансировку и/или blue-green деплоймент.

    С volume всё просто - залил в него новый код, переключил симлинк и всё готово. А базовый образ меняется относительно редко - обычно когда выходит новая версия PHP. В этом случае можно и ручками обновить базовый образ на сервере. Но этот вариант хорош только когда мало серверов. Для больших кластеров конечно лучше работает вариант с упаковкой приложения в отдельный образ.
    Ответ написан
    4 комментария
  • Почему разные выходные значения Java и Python?

    Vamp
    @Vamp
    Причина в том, что второй вызов метода вычисляется в значение, не влезающее в тип данных long. То есть возникает классический integer overflow. В java и php старшие биты, не поместившиеся в long, просто отбрасываются. В python и ruby на уровне языка поддерживается bignum арифметика, поэтому результат другой. То есть числа могут быть сколь угодно велики без опасности возникновения переполнения. В php такое тоже возможно при помощи модуля bcmath или gmp. В java аналогичную арифметику предоставляет класс BigInteger:

    import java.math.BigInteger;
    
    public class A {
        public static void main(String[] args) {
            BigInteger output_1 = generate(400732734464L, -74, 12);
            BigInteger output_2 = generate(1641401281110016L, 100, 14);
    
            System.out.println(output_1);
            System.out.println(output_2);
        }
    
        public static BigInteger generate(long val1, int val2, int val3) {
            return BigInteger.valueOf(val2 & 255)
                .add(BigInteger.valueOf(val1))
                .shiftLeft(val3);
        }
    }
    Ответ написан
    Комментировать
  • Как ограничить область действия зависимостей?

    Vamp
    @Vamp
    Лучше всего форкнуть проект библиотеки и переписать код на spring 5. Возможно это будет не слишком трудоёмко, учитывая, что зависимость от spring у библиотеки транзитивная. То есть в коде библиотеки может и не быть кода, зависящего от spring, поэтому может быть достаточно обновить только версию непосредственной зависимости, которая уже тащит spring.

    Альтернативным вариантом является использование maven-shade-plugin. Этот плагин упаковывает зависимости проекта в единый jar файл и, опционально, может перемещать классы в другой пакет. Фича называется class relocation. То есть вы можете собрать shaded версию библиотеки soap-ws, у которой классы spring будут релоцированы из пакета org.springframework в, например, vildaraj.shaded.org.springframework. В этом случае вы можете в основном проекте использовать какую угодно версию spring без конфликтов.
    Ответ написан
    Комментировать