daemon Linux pe PHP5

Buna ziua, azi voi descrie o sarcină destul de amuzant, de mic câmp direct legate de web-programare, ci mai degrabă crearea unui demon în PHP. Este clar că prima întrebare este: „De ce este necesar?“ Ei bine, ne vom ocupa consecutiv.


S-ar părea, de fapt, o rară programe de pervertire scriere de acest tip în limbi cum ar fi PHP, dar că, dacă există necesitatea de a monitoriza continuu proces sau un proces continuu sau periodic, și au nevoie de un pic skriptik. Ca regulă generală, la îndemână nu este un profesionist competent capabil să nu te trage în picior cu C ++ sau să nu taie piciorul folosind C, bine, sau doar un programator aplicație bună. În aceste cazuri, fiecare filare ca tine poate, atunci există o varietate de himere și hibrizi, cum ar fi rularea script-uri pentru a set_time_limit parametrul (0). script-uri lansate de la un loc de muncă cron în fiecare secundă (da, a văzut și așa mai departe) și alte, nu mai puțin de Spike lucruri.

De fapt, în formularea problemei. Pe parcursul proiectului a existat o nevoie de integrare cu software complex terță parte. Singura modalitate de a comunica cu programmulina - comunicarea prin intermediul propriului său protocol printr-un port de rețea, de așteptare pentru debutul evenimentului, analiza răspunsul, procesul, salvați la baza de date. S-ar părea nimic complicat, scrie skriptik cu o buclă infinită, în interiorul căruia ar avea loc toată magia și voila necesare! La început, am vorbit despre același lucru, dar în curând a devenit clar faptul că această abordare are un dezavantaj major, una dintre acestea fiind date incorecte, apar la momentul decesului a scenariului. Repornește server și baza de date sunt date care nu au timp și nici nu proces sau șterge. E neplăcut, foarte neplăcut.

Ei bine, să se ocupe, avem o lampă clasic pe CentOS, fețe softina și o dorință puternică de a nu lega alte instrumente sau așa „Doamne ferește de programare în C». M-am gândit că ar fi nu-i rău în cazul în care script-ul original poate fi învățat să recunoască semnalele de funcționare a sistemului, astfel încât acesta și-a îndeplinit sarcina sa în mod corect. Pentru cei care nu știu, în termeni generali, Linux gestionează procesele prin intermediul unor semnale care spun procesul de modul în care el ar trebui să se comporte. La primirea unui astfel de proces de semnal trebuie să își schimbe comportamentul și să nu fac nimic în cazul în care nu este necesară pentru funcționarea sa. Personal pentru mine, cel mai interesant semnal SIGTERM. Acest semnal indică faptul că procesul ar trebui să își încheie activitatea. Lista tuturor semnalelor existente pot fi vizualizate aici:
semnalele UNIX

Deoarece există o altă caracteristică, fiecare proces în Linux oricum asociat cu terminalul de la care a fost lansat și de la aceeași moștenește fluxuri I / O pe aceasta ca imediat ce închideți terminalul, care a lansat scenariul acesta completează imediat executarea acestuia. Pentru a evita o astfel de situație, este necesară crearea unui proces de copil, pentru a face de bază, și dezlegați procesul părinte ucide de la terminalele de intrare / ieșire rămase, în care a fost început. Sunt de acord, sună complicat, confuz și nu este clar, dar în practică este mult mai ușor decât pare.

Ceea ce avem nevoie pentru a lucra? În principiu, nu atât de mult, de fapt ea însăși PHP, în cazul meu, PHP5.6 și mai multe îmbunătățiri:

Acum, că avem tot ceea ce avem nevoie pentru a ajunge în jos pentru a scrie cod.

După cum sa menționat mai sus, pentru a începe daemon noastre, în conformitate cu normele acestor programe funcționează pe Linux, este necesar să se decupleze de la terminal, în cazul în care a început să facă acest lucru, utilizați pcntl_fork funcția (). creează o copie copil al procesului actual și returnează ID-ul numeric în caz de succes. Și, desigur, ucide procesul părinte.

Astfel, sistemul de operare va ști că suntem capabili de a determina propriul comportament și a pus pid procesul nostru în loc pentru semnalele de sistem.

Acum ne așteptăm cel mai interesant - aveți nevoie pentru a determina exact modul în care lucrăm și să interacționeze cu sistemul de operare. Am decis să fac această funcționalitate într-o clasă separată, în cazul în care în cazul în care acest cod este încă necesară. Să începem, mai întâi trebuie să stabilească faptul că această clasă ar trebui să poată să facă.

Primi și procesa semnale ale sistemului de operare;
Să fie capabil să înțeleagă dacă daemonul se execută sau nu;
Execută sarcina după cum este necesar pentru demonizarea;
Știu când să se oprească;

Pentru atingerea acestor obiective este de a înțelege caracteristicile care vin la îndemână. pcntl_signal () funcția. Ai nevoie pentru a atribui o funcție unui handler pentru semnalul. Este nevoie ca argumente: semnalul pentru care procesorul atribuit și o metodă funcție sau clasă este responsabil pentru procesarea semnalului. getmypid () funcția. care returnează PID-ul procesului curent. În cele din urmă posix_kill () funcția. trimite un semnal la procesul specificat ia două argumente: pid procesul pe care doriți să trimită un semnal și semnalul real în sine, care urmează să fie trimis.

Pentru a monitoriza starea propriului proces, avem nevoie de un steag, care va determina timpul pentru a termina procesul sau nu. După cum există unele subtilități pentru a economisi resurse CPU, este necesar să se întrerupe, în care aplicația va aștepta pur și simplu pentru următoarea iterație a buclei, prin urmare, nu influențează interogarea permanentă a sistemului. Trebuie să definiți acești parametri ca câmpuri de clasă.

După cum se poate vedea metoda are ca argument un semnal care este trimis la el, și în funcție de care semnalul este trimis la daemon efectuează anumite acțiuni.

Acum trebuie să aflăm exact dacă demonului nostru se execută sau nu. Cum o facem bine, pentru ca daemon-ul poate fi pornit de la un alt terminal sau de mai multe ori. În cazul în care mai multe instanțe ale aceluiași script va încerca să acceseze simultan aceleași resurse, cred că va fi extrem de neplăcut. Pentru a evita această situație, putem folosi vechi ca mod dealuri, în cadrul programului pentru a crea un fișier într-un anumit loc, cu un program înregistrat pentru a pid procesul și îndepărtați-l de fiecare dată când aplicația noastră este închisă. Astfel, verificarea existenței acestui fișier, putem ști dacă există o copie de funcționare a aplicației. Pentru a rezolva această problemă, definim metoda clasei noastre.

Aici vom testa toate scenariile posibile, dacă există un fișier, dacă da, ce proces creat, verificați dacă există un astfel de proces în cazul în care procesul este de a crea un fișier nu există, pentru că procesul sa încheiat în mod neașteptat, încercați să ștergeți fișierul.

E timpul să ne gândim, dar cum am prodelyvat de fapt, aceste operațiuni aceeași pentru care a fost conceput și toate? Există mai multe variante. În cazul meu a fost necesar să se aștepte rezultatele de servicii terțe părți care nu sunt produse fără aceste date procesul a fost inutil și nici o acțiune asupra datelor existente, sau resursele, așa că am pus în aplicare toate prelucrării în funcția pe care a primit sau nu a primit serviciul de la o serie de date terță parte. În cazul în care datele nu a fost funcția ar trebui să cauzeze atâta timp cât acestea nu apar. Astfel, în scris clasa I metoda care pune în aplicare sarcina utilă depinde de doi parametri: starea internă a daemon și rezultatele funcției de prelucrare a datelor de la un serviciu terță parte.

Așa că am luat două bucle în mod condiționat infinit, de interior, care așteaptă până când funcția este executată și externe, care așteaptă până la schimbarea daemon de stat. Nimeni nu spune că punerea în aplicare mea este cea mai corectă, punerea în aplicare a metodei poate fi redefinit ca este convenabil, fără a uita pentru a ține evidența dacă este sau nu timpul pentru a termina procesul.

Acum vine punctul culminant, trebuie să-l lega totul împreună și a alerga, cred că e timpul pentru a scrie un constructor pentru clasa noastră.

Verificați dacă procesul se execută utilizând fișierul sau nu, dacă rulați afișează un avertisment, setați întârziere, atribuiți stivuitoare de semnal (în acest caz, doar unul), a crea un fișier și scrie la un BIP, să cunoască celelalte exemplare ale procesului știu că suntem deja de lucru. Cu clasa am terminat.

Acum ne întoarcem la scrierea daemon script-ul. Am stat pe terminat toate pregătirile pentru a porni demonul.

Noi conecta toate bibliotecile de care avem nevoie, inclusiv un fișier cu clasa Daemon.php noastre, descrie funcția pe care o va transporta o sarcină utilă, de a crea o instanță a Daemonului clasa cu parametrii doriți, pierderea standard de intrare / ieșire de la terminalul curent și să redirecționeze lor la / dev / null (dacă am fi făcut-o înainte, aceasta ar risca să nu vadă mesajele de eroare în timpul executării scriptului), peredaom rula metoda de clasa Daemon, funcția noastră să fie realizată de un demon.

Asta e tot. daemon nostru se execută bine și comunică cu sistemul de operare. Toate noroc bine și bine.