Страницы

Поиск по вопросам

пятница, 29 ноября 2019 г.

Что будет если подключившись к серверу по SSH закрыть терминал без команды exit?

#ubuntu #ssh


Что будет если подключившись к серверу по SSH закрыть терминал без команды exit?
    


Ответы

Ответ 1



выполняющийся процесс получит сигнал hup. что будет дальше — целиком и полностью зависит от того, что разработчики вложили в программу. по умолчанию она должна завершиться. скрипт для проверки: #!/bin/bash trap 'touch hupped; exit' hup echo $$ while :; do sleep 1; echo -n .; done сначала он выводит номер своего процесса, а затем раз в секунду выдаёт в stdout символ «точка». при получении сигнала hup создаёт в текущем каталоге файл hupped и завершает работу.

Ответ 2



Если терминал завершен корректно, то посылает команду закрыть соединение ssh, дальше сигнал hup всем процессам. Если процесс терминала убить, то операционная система посылает tcp-fin пакет, возникает исключение на сервере, дальше hup. Если соединение было разорванной некорректно , например отключилась сеть, то fin не дойдёт и процесс будет выполняться какое-то время (около получаса обычно) пока соединение не разорвется по таймауту сервером. Дальше как и в других случаях hup.

Ответ 3



По закрытию контролирующего терминала bash получает SIGHUP и выходит, [в интерактивном случае] пересылая сигнал всем процессам из списка её задач (job). Остановленные задачи получают также SIGCONT. Из документации bash по сигналам (что соответствует ожидаемому поведению групп процессов, создаваемых с помощью setpgid(2)) : The shell exits by default upon receipt of a SIGHUP. Before exiting, an interactive shell resends the SIGHUP to all jobs, running or stopped. Stopped jobs are sent SIGCONT to ensure that they receive the SIGHUP. To prevent the shell from sending the SIGHUP signal to a particular job, it should be removed from the jobs table with the disown builtin (see Job Control Builtins) or marked to not receive SIGHUP using disown -h. nohup позволяет игнорировать SIGHUP сигнал, disown команда позволяет исключить задачу из этого списка. systemd 230 версия изменяет поведение по умолчанию при завершении пользовательской сессии. ssh процесс на клиенте получает SIGHUP. ssh при получении сигнала восстанавливает stdin, если необходимо, пересылает сигнал proxy-команде, если есть и выходит. В сторону, обычно, при нормальном выходе bash (exit, Ctrl-D), SIGHUP не будет послан задачам, так как huponexit опция выключена по умолчанию. In which cases is SIGHUP not sent to a job when you log out? При этом на сервере могут не сразу узнать, что ssh клиент умер. Does getting disconnected from an SSH session kill your programs? Когда sshd на сервере заметит что соединение мертво, это приводит к посылке SIGHUP сигнала уже на сервере и повторяется поведение из цитаты выше.

На каком языке программирования написана Windows XP и 7?

#windows #windows_7


На каком языке программирования написана Windows XP и 7?    


Ответы

Ответ 1



На самом деле они написаны не на одном языке программирования, а на смеси: большая часть - С/С++ (с Visual Studio) небольшая часть - ассемблер (masm, какой же ещё) С# (этого в ХР изначально не было, а вот для 7 - уже много) hta (это такой способ делать приложения с помощью html и скриптов). Есть такая байка (не знаю, на сколько правдивая, но очень интересная), что Висту изначально хотели написать полностью на С# и .NET языках. Типа было бы очень круто (все было бы очень стабильно и круто). Но потом поняли, что это просто невозможно (как минимум - ещё нет такого железа, что бы оно все взлетело). И сделали по старинке - допилили XP. Если есть интерес к тому, как оно там устроено внутри, то можно посмотреть на ReactOs - это попытка сделать windows совместимую операционную систему.

Ответ 2



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

Откатить уже опубликованный коммит и опубликовать новый, не вызывая мержа у других

#git #git_commit #git_remote


Предположим, я сделал коммит X и опубликовал его на удаленный репозиторий (git push).
Все, у кого есть доступ к репозиторию обновились. 

Далее я обычно откатываю коммит через  git reset --hard HEAD~1, делаю изменения и
пушу через git push -f origin master, что полностью удаляет прошлый коммит. Однако,
если все снова запулят, то у них будет мерж удаленного коммита с новым.

Как этого избежать?
    


Ответы

Ответ 1



Если коммит попал в общую/стабильную ветку (т.е. ту, которой пользуется хоть кто-то ещё, обычно это master, develop и прочие), то его нельзя удалять. Можно только создать «отменяющий» коммит с помощью git revert (подробнее тут, пункт 5). Возможно, в вашем коммите оказались какие-то критические данные, например пароли или ключи. В этом случае бесполезно пытаться спасти их с помощью удаления коммита, который их содержит. Данные уже скомпрометированы, все пароли и ключи придётся менять. # отменяем последний коммит, доступный по указателю HEAD git revert HEAD # фиксируем отмену в новом коммите git commit -m'reverted the last commit' Если вы абсолютно уверены, что вы запушили «лишний» коммит в собственную ветку, что её никто не замержил в стабильную ветку и просто так не начал разработку от последнего вашего коммита, можно откатить локальную ветку к предыдущему коммиту, а потом переписать изменения в удалённой (подробнее тут, пункт 4.2) Внимание! Никогда не делайте так с общими ветками (master, develop и прочие). Если это категорически необходимо, обязательно и сразу же предупредите всех, кто работает с этим репозиторием. После переписывания последнего коммита в стабильной ветке им придётся вручную обновлять эту ветку на своей машине. Если у них есть какие-то новые коммиты, предком которых является удаляемый коммит, им придётся делать rebase на коммит. git reset HEAD^ git push -f Вот вам моя любимая схема, иллюстрирующая разные варианты решения.

Ответ 2



У них скорее всего будет не просто слияние с удалённым коммитом, но будут какие-то проблемы. Ведь у них в репозиториях лежат коммиты с родителем A, а в удалённом репозитории лежит другой коммит, но тоже с родителем A. Я, откровенно говоря, не знаю как поведёт себя git, но единтсвенным правильным решением в данной ситуации является откат всех локальных репозиториев точно так же, как Вы откатитились: git reset --hard HEAD~1, только потом git pull Вообще говоря за git push -f origin master, в репозиторий, который используется более чем одним человеком, бьют по лицу. Так делать можно только в ЭКСТРЕННЫХ случаях и только если вся команда в курсе происходящего и принимает соответсвующие меры на своих локальных копиях.

Что такое пул в php-fpm?

#php #php_fpm


В php-fpm по умолчанию, сразу после установки есть пул www. Все об этом знают и надеюсь
понимают, но я не совсем. Примерно понимаю что это типа выделенная группа процессов
php-fpm. Может быть наверное несколько пулов. 

Кто-то может объяснить или дать ссылку на документацию где объясняется что такое
пул php-fpm и зачем он нужен? Сам я путем гугления не нашёл.

Заранее благодарю.
    


Ответы

Ответ 1



Пулы php-fpm - позволяют запускать процессы php под разными пользователями, тем самым создавая более безопасную среду. Так же, каждому пулу - можно выделять свои ресурсы и переопределять переменные php.ini Например: Для production версии сайта - один пул, для development версии сайта - другой пул. Каждый пул работает или на отдельном порте, или на отдельном сокет файле. Как утверждают некоторые мануалы по оптимизации php-fpm - то для сайта с высокой нагрузкой разумней использовать несколько пулов. Цитата: In our experience, multiple upstream backends on the same machine, produce higher throughout than a single one.

Ответ 2



Пул (pool) в программировании - это контейнер для повторно используемых ресурсов. Он используется для экономии на создании ресурса. Идея в том, что после завершения использования ресурса он не уничтожается - а возвращается в пул, откуда его можно быстро достать для повторного использования. Не следует путать пул и кэш - хотя их назначение и схоже, но в кэше хранятся разные объекты, в пуле же все ресурсы абсолютно одинаковы (смысл пула как раз в том чтобы ресурс, взятый из пула, никак не отличался от только что созданного). К примеру, открытие соединения с БД - операция долгая, поскольку надо устанавливать сетевое соединение. Поэтому соединения с БД часто объединяют в пулы соединений. Создание нового потока - операция дорогая. Поэтому библиотеки, предназначенные для асинхронной работы, часто содержат пул потоков. А на винде пул потоков даже является частью WinAPI. В случае php-fpm, каждый запрос обрабатывается в некотором процессе. Запуск процесса - операция еще более дорогая чем создание потока - а потому используются пулы процессов. Ну а поскольку в случае с php-fpm может потребоваться создавать разные процессы (с разными настройками), а один пул может содержать только одинаковые ресурсы - php-fpm создает несколько пулов, каждый со своими настройками. Вот так настройки процесса стали настройками пула, а пул из паттерна программирования стал единицей администрирования.

В чём отличие npm install --save-dev от --save

#javascript #node.js #npm


В чем заключается отличие команд --save-dev и --save при установке пакета через npm?
    


Ответы

Ответ 1



-S, --save: Пакет будет отображается в ваших dependencies -D, --save-dev: пакет будет отображаться в ваших devDependencies Для более подробной информации смотрите npm-install

Ответ 2



Если указывать флаг --save то при установке пакета, его имя и версия пропишутся в файле package.json в разделе dependencies. Если установить с флагом --save-dev, то имя и версия попадут в раздел devDependencies

Ответ 3



В версии npm 6.5 можно не писать -save или -s , npm сам добавит установленный пакет вам в "dependencies": { }. Из документации https://docs.npmjs.com/cli/install : -P, --save-prod: опять же сохранит в "dependencies": { }. Это ваш код для продакшена, он будет включен в ваш конечный продукт. Добавляйте сюда только те библиотеки, которые будут использованы при работе вашего конечного продукта (вэб страницы например). -D, --save-dev: сохранит пакет в "devDependencies": { }. Это пакеты, которые вы используете в процессе девелопмента, препроцессоры LESS, SASS, валидаторы кода, JShint Slint, препроцессоры JS: Babel. Эти пакеты не будут включены в конечный продукт. -O, --save-optional: пакет будет добавлен в "optionalDependencies": { }. эти пакеты могут быть использованы в работе, но если они будут недоступны или произойдет ошибка при их установке, то npm просто пропустит их и продолжит работу. --no-save: Запрещает сохранять пакет в package.json. +Дополнительные флаги: -E, --save-exact: сохранит версию пакета точно, как указано. -B, --save-bundle: сохранит пакет в "bundleDependencies": { }.

Ответ 4



Если правильно помню, то когда добавляешь -dev , то помимо пакета ставится все, от чего он зависим. Например: bower install jqueryvalidation --save-dev Поставит jqueryvalidation и jquery. т.к. как зависим от нее. если указать без -dev, то jquery поставлена не будет.

Разница между компилятором и интерпретатором

#компилятор #терминология #интерпретатор


Какая разница между компилятором и интерпретатором? Может ли язык программирования
иметь и компилятор и интерпретатор?
    


Ответы

Ответ 1



Чтобы опеределить разницу, давайте узнаем, что это такое: Компиля́тор — программа или техническое средство, выполняющее компиляцию. Компиля́ция — трансляция программы, составленной на исходном языке высокого уровня, в эквивалентную программу на низкоуровневом языке, близком машинному коду (абсолютный код, объектный модуль, иногда на язык ассемблера). Входной информацией для компилятора (исходный код) является описание алгоритма или программа на предметно-ориентированном языке, а на выходе компилятора — эквивалентное описание алгоритма на машинно-ориентированном языке (объектный код). Википедия Интерпрета́тор — программа (разновидность транслятора), выполняющая интерпретацию. Интерпрета́ция — пооператорный (покомандный, построчный) анализ, обработка и тут же выполнение исходной программы или запроса (в отличие от компиляции, при которой программа транслируется без её выполнения). Википедия Таким образом, можно заключить, что компилятор приобразует исходный код к близкому к машинному коду. Интерпретатор же, позволяет выполнять некоторое представление программы, налету преобразуя в машинный код. Если взять язык java, то он имеет, как компилятор, так и интерпретатор. Компилятор преобразует исходный код в байткод. А байткод в начальной стадии выполнения программы обрабатывается интерпретатором. Компилятор, это отдельная программа javac, интерпретатор же встроен в jvm. Помимо обычного компилятора, в jvm присутствует just-in-time компиляция. т.к. интерпретация довольно медленна, то горячие места в программе компилируются в машинный код jit компилятором, тем самым ускоряя выполнение.

Ответ 2



1) Разница в том, что компилятор преобразует код алгоритмического языка в исполняемый (байт-код либо нативный) код (в пределе - в машинные коды), в то время как интерпретатор самостоятельно распознаёт и выполняет построчно инструкции программного кода. 2) Да, может. Даже древние turbo/quick basic - и те могли. Причём Borland Turbo BASIC был "в одном флаконе", в то время как Microsoft Quick Basic использовал, как и все современные, внешний компилятор. UPD: Наверное, можно ещё сформулировать так: интерпретатор для выполнения программы обязан располагать исходным кодом программы (в исходном либо формализованном виде) на алгоритмическом языке, в то время как компиляция создаёт исполняемый модуль, который не содержит текста программы на алгоритмическом языке. Также, если при компиляции не добавляется отладочная информация, невозможно полное восстановление исходного кода.

Ответ 3



интерпретатор выполняет программу, трансляторы в т.ч. компиляторы преобразуют без выполнения

Какое значение примет элемент n[1] после выполнения команд:

#c++ #language_lawyer #неопределенное_поведение


int i = 0, n[] = {7, 5, 3, 1};
for ( ; i<3; n[i++] = n[i]);


Дело в том, что два разных компилятора (Code Blocks и CppDroid) выдают два разных
значения. В Code Blocks получается 5, а в CppDroid - 3. Так какой же ответ правильный?
Проблема в одном из компиляторов, или само задание некорректно?
    


Ответы

Ответ 1



По-моему, порядок вычисления выражения слева и выражения справа при выполнении присваивания не оговорен стандартом (порядок определяется конкретным компилятором). Для C++11, раздел 5.17: The assignment operator (=) and the compound assignment operators all group right-to-left. All require a modifiable lvalue as their left operand and return an lvalue referring to the left operand. The result in all cases is a bit-field if the left operand is a bit-field. In all cases, the assignment is sequenced after the value computation of the right and left operands, and before the value computation of the assignment expression. With respect to an indeterminately-sequenced function call, the operation of a compound assignment is a single evaluation Поскольку итоговый результат вычисления зависит от порядка вычисления операндов, то и возникает undefined behavior. Для C++17, раздел 5.18, порядок вычисления уже более строго определен: The right operand is sequenced before the left operand. Поэтому неопределенного поведения не должно возникать. И после выполнения цикла массив не изменится, поэтому n[1] равно 5.

Ответ 2



Компилятор C++ имеет право переупорядочивать инструкции в целях оптимизации. Рассмотрим выражение n[i++] = n[i] Как оно может быть интерпретировано? Первый вариант. int tmp = i; i = i + 1; n[tmp] = n[i]; То есть, например, при i == 0 n[0] = n[1] Второй вариант auto tmp_n = n[i]; int tmp_i = i; i = i + 1; n[tmp_i] = tmp_n; То есть, при i == 0 n[0] = n[0]; Таким образом, поскольку порядок вычислений внутри одной операции не определён, компилятор может сгенерировать как первый код, так и второй. То есть правильный ответ здесь следующий: Неопределено. P.S. Кстати, Code::Blocks это не компилятор, а среда разработки, не имеющая собственного компилятора.

Ответ 3



Имеет место неопределенное поведение программы. Согласно стандарту C++ (1.9 Program execution) ...If a side effect on a scalar object is unsequenced relative to either another side effect on the same scalar object or a value computation using the value of the same scalar object, and they are not potentially concurrent (1.10), the behavior is undefined. Там же в стандарте приведен схожий пример i = i++ + 1; // the behavior is undefined

Ответ 4



Никакой. Фрагмент n[i++] = n[i] провоцирует неопределённое поведение, так как операция приравнивания не является точкой следования. Это значит, что оператор волен выбирать, какое именно выражение надо вычислять первее: n[i++] или n[i]. Единственное ограничение — к моменту присваивания оба фрагмента должны дать по значению (ссылку и число соответственно). Неопределённое поведение следует из того, что компилятор рассматривает обе части независимо. Соответственно, i++ из левой части и i из правой друг с другом как бы не связаны. Мало того, что чтение-изменение-запись постинкремента может быть переставлено местами с просто чтением, так они могут быть ещё и перемешаны друг с другом. На большом StackOverflow уже был задан вопрос о том, почему присваивание не является точкой следования: Имеется ли какое-нибудь обоснованию тому, что оператор = не является точкой следования как в Си, так и в C++? Нужна веская причина для того, чтобы что-то стало точкой следования. В причинах же того, чтобы этого не делать, нужды нет — это вариант по умолчанию. К примеру, && должен быть точкой следования из-за short-circuiting: если левая часть оператора ложна, правая его часть вычислена не будет. Это связано не столько с оптимизацией, сколько с возможностью создания зависимости правой части от левой (к примеру, в ptr && ptr->data). Поэтому левая часть обязательно должна быть вычислена строго до правой, чтобы знать, надо ли вычислять правую часть вообще. В случае же с = подобной причины не существует. Хотя этот оператор и является присваиванием (...), точный порядок вычисления сторон не имеет значения, пока они выполняются до собственно присваивания. P. S. Кстати, проблема с ++i + ++i имеет такую же первопричину.

Ответ 5



Неопределенное поведение. Компилятор g++, запущенный с ключем -Wall честно предупреждает об этом. Пример (с чуть модифицированной для печати промежуточных результатов программой): avp@wubu:hashcode$ cat t.c #include #include #include int main (int ac, char *av[]) { int i = 0, n[] = {7, 5, 3, 1}; int l = 0; for ( ; i<3; n[i++] = n[i]) { printf("loop %d i = %d\n", l++, i); for (int j = 0; j < 4; j++) printf("%d ", n[j]); puts(""); } puts(""); printf("result i = %d\n", i); for (int j = 0; j < 4; j++) printf("%d ", n[j]); puts(""); } avp@wubu:hashcode$ g++ -Wall t.c t.c: In function ‘int main(int, char**)’: t.c:11:28: warning: operation on ‘i’ may be undefined [-Wsequence-point] for ( ; i<3; n[i++] = n[i]) { ^ avp@wubu:hashcode$ ./a.out loop 0 i = 0 7 5 3 1 loop 1 i = 1 5 5 3 1 loop 2 i = 2 5 3 3 1 result i = 3 5 3 1 1 avp@wubu:hashcode$ Как видите n[1] = 3, т.е. этот компилятор в операторе присваивания (в данном случае это завершающая часть for(;;)) берет текущее значение i, вычисляет и запоминает адрес цели, увеличивает i, на основе уже нового значения i выбирает данные источника (n[i]) и копирует их по адресу цели.