Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Mój pierwszy serwer w PHP...
Forum PHP.pl > Inne > Hydepark
Bakus
Serwer (Wywoływany jako "php -q serwer.php"):
  1. <?php
  2. if(!extension_loaded('sockets'))
  3. dl(&#092;"php_sockets.dll\");
  4.  
  5. error_reporting (E_ALL);
  6.  
  7. $address = '192.168.0.1';
  8. $port = 522;
  9.  
  10. print 'Uruchamianie serwera';
  11.  
  12. if (($sock = socket_create(AF_INET, SOCK_STREAM, 0)) < 0)
  13. echo &#092;"nnsocket_create() failed: reason: \" . socket_strerror ($sock) . \"n\"; else print '.';
  14.  
  15. if (($ret = socket_bind($sock, $address, $port)) < 0)
  16. echo &#092;"nnsocket_bind() failed: reason: \" . socket_strerror($ret) . \"n\"; else print '.';
  17.  
  18. if (($ret = socket_listen($sock, 5)) < 0)
  19. echo &#092;"nnsocket_listen() failed: reason: \" . socket_strerror($ret) . \"n\"; else print '.';
  20.  
  21. do{
  22. if (($msgsock = socket_accept($sock)) < 0)
  23. {
  24. echo &#092;"nnsocket_accept() failed: reason: \" . socket_strerror($msgsock) . \"n\";
  25. break;
  26. }
  27.  
  28. $msg = &#092;"nWelcome to the KAB php Test Server. n\";
  29. socket_write($msgsock, $msg, strlen($msg));
  30. print &#092;"tUser connected\";
  31.  
  32. do{
  33. if (FALSE === ($buf = socket_read ($msgsock, 4096, PHP_NORMAL_READ)))
  34. {
  35. echo &#092;"socket_read() failed: reason: \" . socket_strerror($ret) . \"n\";
  36. break 2;
  37. }
  38. if (!$buf = trim($buf))
  39. {
  40. continue;
  41. }
  42. if ($buf == 'quit')
  43. {
  44. break;
  45. }
  46. if ($buf == 'get')
  47. {
  48. print &#092;"nttWysylanie 'file'...n\";
  49. $message = 'file';
  50. socket_write($msgsock, $message, strlen($message));
  51. print &#092;"ttreadyn\";
  52. if(!(FALSE === ($b = socket_read ($msgsock, 4096, PHP_NORMAL_READ))))
  53. {
  54. $message = 'ok';
  55. socket_write($msgsock, $message, strlen($message));
  56. $f = fopen(&#092;"./\" . $b, \"wb\");
  57. print &#092;"ttTransfering data\";
  58. while(!(FALSE === ($b = socket_read ($msgsock, 10240, PHP_NORMAL_READ))))
  59. {
  60. if($b != &#092;"end\")
  61. {
  62. print '.';
  63. fwrite($f, base64_decode($B));
  64. }else{
  65. print &#092;"nttOtrzymano 'end'...n\";
  66. fclose($f);
  67. break 2;
  68. }
  69. }
  70. print &#092;"tendn\";
  71. }else{
  72. print &#092;"terrorn\";
  73. }
  74. }
  75. if ($buf == 'shutdown')
  76. {
  77. $quit_message = 'Dziękujemy za skorzystanie z naszych usług';
  78. socket_write($msgsock, $quit_message, strlen($quit_message));
  79. socket_close($msgsock);
  80. print 'Zatrzymywanie serwera';
  81. break 2;
  82. }
  83. $talkback = &#092;"> '$buf'.n\";
  84. socket_write($msgsock, $talkback, strlen($talkback));
  85. echo &#092;"$bufn\";
  86. }while(true);
  87. print &#092;"tUzytkownik rozlaczonynn\";
  88. print &#092;"Oczekiwanie na nastepne polaczenien\";
  89. socket_close ($msgsock);
  90. }while(true);
  91. socket_close ($sock);
  92.  
  93. print &#092;"...EOSnn\";
  94. ?>


Klient (przez www):
  1. <PRE><?php
  2. $plik = &#092;"do_przeslania.zip\";
  3. $sciezka = &#092;"./\";
  4.  
  5. $s = fsockopen('192.168.0.1', 522, $error, $errno, 10);
  6. print fread($s, 2048);
  7. fputs($s, 'get');
  8. if(fread($s, 2048) == &#092;"file\")
  9. {
  10. fputs($s, $plik);
  11. if(fread($s, 2048) == &#092;"ok\")
  12. {
  13. $fp = fopen($sciezka . $plik, &#092;"rb\");
  14. while (!feof($fp))
  15. {
  16. fputs($s, base64_encode(fgets($fp, 8196)));
  17. }
  18. fclose($fp);
  19. fputs($s, 'end');
  20. fputs($s, 'quit');
  21. fclose($s);
  22. }else{
  23. fputs($s, 'quit');
  24. fclose($s);
  25. }
  26. }else{
  27. fputs($s, 'quit');
  28. fclose($s);
  29. }
  30. ?></PRE>


Klient wysyła zawartość pliku odczytanego z dysku na serwer.
Serwer jest jednowątkowy piki co, ale jak na pierwsze moje dzieło z użyciem socket_* to chyba nieźle...

Byłbym wdzięczny za poprawki do tego wspaniałego (moim skromym zdaniem) serwera...
Klient będzie docelowo napisany w php-GTK, tak by odczytywać pliki z dysków użytkowników...

Celem jest stworzenie uploadera w php-GTK (klient) i php (serwer).

Klient tutaj zamieszczony jest (jak już wspomniałem) dla potrzeb testów...

Najbardziej liczę na waszą pomoc jeżeli chodzi o dodanie wielowątkowości do serwera - tak by naraz z niego mogło korzystać wiele osób.
Jeżeli okaże się to niemożliwe, to proszę o podpowiedź w jaki sposób można "zablokować" serwer przed kolejnymi uploadami (tak, by klient wiedziałm że serwer jest wykorzystywany przez kogoś innego i musi poczkać)

<b>Właśnie - najważniejsza sprawa - serwer jest pod windowsa!</b>
Nie mam zielonego pojęcia, czy i w jaki sposób będzie działał pod linuxem...

UpDated: malutki bug w kliencie - nazwy zmiennych
UpDated: dodanie "if mod loaded = false"...
Uaktualniłem BBCode do wersji z IPB...
winksmiley.jpg
Paul
mozesz zrobic plik textowy w ktorym beda zapisalne info czy ktos teraz korzysta z uploadu - czyli na poczatku skryptu dajesz zapis do pliku, ze korzysta i na koncu po zakonczeniu uploadu ze jest skrypt wolny, plus jeszcze pare ifow, ze jak zawartosc danego pliku jest taka i taka to musisz czekac...
spenalzo
Cytat
Jeżeli okaże się to niemożliwe, to proszę o podpowiedź w jaki sposób można "zablokować" serwer przed kolejnymi uploadami (tak, by klient wiedziałm że serwer jest wykorzystywany przez kogoś innego i musi poczkać)

Utwórz sobie pusty plik "busy" i jeżeli jest to znaczy, że serwer jest zajęty.

Hmmm... nie rozumiem po co pisać serwer w php... szczególnie jeżeli jest do przesyłu plików protokół php - ale nie żebym był przeciwny smile.gif
adwol
Cytat
Najbardziej liczę na waszą pomoc jeżeli chodzi o dodanie wielowątkowości do serwera - tak by naraz z niego mogło korzystać wiele osób.

Zainteresuj się funkcją socket_select. Nie daje to prawdziwej wielowątkowości (nie są tworzone osobne wątki ani procesy dla każdego requestu), ale pozwala na obsługę wielu połączeń w obrębie jednego procesu. Niestety php w wersji 4 na windows nie ma porządnego wsparcia do tworzenia wątków i procesów (o funkcjach exec i system nie mówimy). Rozszerzenie pctnl w którym jest funkcja pctnl_fork istnieje tylko w wersji uniksowej, więc z niej nie skorzystasz. Będziesz się musiał zadowolić praktyczne chyba tylko selectem.
Cytat
Właśnie - najważniejsza sprawa - serwer jest pod windowsa!Nie mam zielonego pojęcia, czy i w jaki sposób będzie działał pod linuxem...

Sockety pochodzą orygnialnie z uniksa (dokładniej z BSD) i uniksy są ich ojczyzną. Jeśli pracuje to prawidłowo na windowsie to na linuksie też nie będzie większych problemów. smile.gif

Z ogólnych uwag:
:arrow: Masz troche bałaganu w kodzie. Napisałeś to bez użycia chociażby jednej funkcjii, że o klasach nawet nie wspomnę.
:arrow: Ustal sobie najpierw jakiś protokół komunikacji (możesz bazować na HTTP). Wymyśl jak będzie przebiegała transmisja i komunikacja, jakie będą wydawane komendy, itp. Np. niech będą na początek dwie istotne komendy: GET i PUT (znaczenie wiadome). Parametry do tych komend (np. nazwy plików) staraj się dawać w jednej linii z komendą, np.:
Kod
GET plik.txt

Niech serwer odpowiada coś po każdym wysłanym żądaniu od klienta. Linie z odpowiedzią niech będą poprzedzane jakimś kodem statusu operacji. Będzie im wtedy łatwiej się ,,dogadać'' przy bardziej rozbudowanym protokole, reagować na błędy, itp. Np.: (S -- server, K -- klient)
Kod
S: 00 Witamy na naszym serwerze

K: GET /katalog/plik.txt

S: 10 Błąd. Plik /katalog/plik.txt nie istnieje.

K: GET /katalog/plik2.txt

S: 20 572

S: Pierwsza linia pliku

S: Druga linia pliku

S: Trzecia linia pliku

K: PUT /katalog/plik3.txt 1092

K: Pierwsza linia pliku

K: Druga linia pliku

K: Trzecia linia pliku

S: 30 Dziekuje. Odebrano 1092 bajty danych.

K: QUIT

S: 00 Do widzenia

Generalnie przewiduj rozszerzenie protokołu w przyszłości (chyba, że napewno tego nie chcesz) o np. autoryzacje, listowanie zawartości katalogów, itp. Łatwiej jest później dodać jeden nagłówek w żądaniu, niż przerabiać pół protokołu.
:arrow: Po co kodujesz wysyłane pliki za pomocą base64? Niech klient i serwer wysyłają przed początkiem transmisji długość pliku. W przyszłości być może przyda Ci się to do optymalizacji.
:arrow: Zapisz sobie obsługę każdej komendy jako osobną funkcję ze jednym stałym interfejsem do wszystkich. Główna pętla programu niech tylko obsługuje połączenia i rozdziela zadania pomiędzy funkcje

Możesz mieć problemy z efektywnym wykorzystaniem socket_select(), ale na początek spróbuj chociaż uzyskać wiele połączeń naraz (bez jednoczesnego wysyłania danych).

Dobrze, że ktoś się zainteresował innym wykorzystaniem php niż tylko jako język dynamicznych stron WWW, bo dla większości jest on nieodłącznie związany z tym segementem internetu. Niestety nie był on projektowany do takich zastosowań, ale przy odrobinie chęci da się z tego coś sensownego wykrzesać. winksmiley.jpg
Bakus
Dzięki adwol za opdpowiedź...
Napisałem to bez użycia funkcji/klas, ponieważ jest to "bardzo wczesna wersja alfa" winksmiley.jpg tego serwera...
Na dobrą sprawę byłem tak zadowolony, że serwer działa, że odrazu wrzuciłem kod na forum...
base64 zastosowałem ze względu na przesył danych binarnych przez które serwer się wywalał...

Właśnie implementuje obsługę komend...
Pomysł z wysyłaniem wielkości pliku jest wyjątkowo trafiony... smile.gif - miałem z tym problemy...

Co do [manual:c94fbfa6a5]socket_select[/manual:c94fbfa6a5] dopiero po zaimplementowaniu komend się tym szażej zainteresuje... szkoda, że manual jest po angielsku, jeżeli chodzi o ten wątek... sad.gif

Jeszcze raz dzięki...

@Paul i spenalzo: Dzięki za podpowiedź, ale chyba w gotowym serwerze wykorzystam rozwiązanie adwol'a... Jeszcze niewiem jak będzie działać, ale zapowiada się interesująco...

@spenalzo: Zawsze chciałem tworzyć programy (teraz już wiem, że są to "serwery"), które służyły by do przesyłania informacji przez sieć...

P.S. Wykorzystując silnik z tego serwera można napisać fajny serwerek chata dla np. sieci lokalnych w firmach...
Bakus
Komentarz na stronie manuala:

Cytat
Please note that the timeout parameter has important side-effects on the CPU usage of your script.

Setting the timeout to 0 will make your CPU looping without any time to have some rest and handle other running processes on your system, causing the system load to increase heavily while your script is running.


To chyba dyskwalifikuje funkcje dla zadania jakie mam jej powierzyć...
spenalzo
No teraz, po tych postach widze, że jednak jest to ciekawy pomysł ...
orson
witam ...

w celu optymalizacji podpowiadam ze mozesz sie zainteresowac funkcjami kompresujacymi ... jezeli to sa dane binarne [ i sa raczej nie wielkie ... tak do 10 mb ] to chyba nie powinnno byc problemu ... i drugi tip dotyczy integralnosci danych ... dobrze by bylo robic md5 albo sha1 na pliku po stronie klienta i serwera ... takna wszeslki wypadek ...
pomysl fajny tylko interesuje mnie czy klient tylko w php-gtk questionmark.gif przez browser nie bedzie sie dalo ?

cya
uboottd
Cytat
Komentarz na stronie manuala:

Cytat
Setting the timeout to 0 will make your CPU looping without any time to have some rest and handle other running processes on your system, causing the system load to increase heavily while your script is running.


To chyba dyskwalifikuje funkcje dla zadania jakie mam jej powierzyć...


Nie. Zakladam ze jest to komentarz do selecta. Timeout okresla czas po jakim ta funkcja odda ci sterowanie jesli nie przyjda zadne dane. Jesli jakies dane sie pojawia to wtedy zakonczy sie od razu jak te dane sie pojawia. O ile Twoj program nie musi czegos robic poza czekaniem na dane to timeout ustawia na nieskonczonosc.
Bakus
Po co pisać klienta w php - jako skrypt na WWW?
Można odrazu przesłać pliki na serwer przez zwykły upload...

W takim układzie pisanie serwer w php nie ma żadnego sensu...

Napisałem ten serwerek by ominąć ograniczenie uploadu i móc pobierać pliki więklsze od 2 MB z compa użytkownika.
Przy Kliencie - przeglądarce - musisz wysłać dane do serwera na którym php je dopiero przetworzy...
Ja pisząc klienta w php-GTK omijam przesyłanie plików na serwer przez protokół HTTP.
Poza tym co byś nie zrobił zwiększając wielkość "max_upload_size" w php.ini na więcej niż 2MB możesz zapchać serwer jeżeli stoi na kiepskim łączu... mój serwer korzysta z niezależnego pasma - nie obciąża Apacha i dzięki temu użytkownicy w dalszym ciągu mogą oglądać sobie stronki... wolniej, ale mogą... winksmiley.jpg

Cytat
mozesz sie zainteresowac funkcjami kompresujacymi
Rozmyślałem nad tym, ale jeszcze się zastanawiam...

Cytat
No teraz, po tych postach widze, że jednak jest to ciekawy pomysł ...
On od początku był ciekawy... winksmiley.jpg
klops
witam,
mam pare pytan odnosnie tego projektu bo wlasnie cos takiego potrzebuje - przesylanie plikow do i z serwera,
rozumiem ze klient musi chodzic na komputerze z interpreterem php? bez tego ani rusz?
a jesli powyzsze spelnione to wiem ze mozna jeszcze przesylac pliki za pomoca PUT i GET, ale z lektury tematu wywnioskowalem ze sa jakies ograniczenia odnosnie wielkosci przesylu, czy one wystepuja zawsze czy mozna dajmy na to przesylac nieograniczone ilosci danych? a jesli juz przeslemy dajmy na to pliczek na serwer to jak ze sie tak wyraze dostac do niego, tzn gdzie on jest zapisywany pod jaka nazwa itd?

pozdrawiam
Kocurro
Bakus - limit uploadu możesz spokojnie ominąć innymi sposobami z o wiele ciekawszym efektem smile.gif
klops
a moglbys nieco rozwinac swoja wypowiedz:) bardzo mnie zainteresowales smile.gif i prosze o wiecej...
Kocurro
Ja przeważnie omijałem to poprzez zmianę ustawień php w plikach htaccess, działało bez zarzutu.

Potem potrzebowałem skryptu by pokazać postęp w uploadzie. W tym pomogło mi sourceforge - tam znalazłem dobry pomysł + wykonanie jako cgi, potem poprzerabiałem i działa extra smile.gif

Wykorzystanie CGI daje jedną dodatkową cechę - zawsze można w jakiś sposób przekazać informacje by przerwać upload.

Ja na przykład zrobiłem w panelu administratora monitor uploadu tak, że administrator widzi co jest aktualnie uploadowane oraz ma możliwość przerwania tego. Do tego opcje umożliwiające ustawianie limitów uploadu na podstawie zakresów ip i innych rzeczy.

Niestety na razie nie mogę tego nikomu zaprezentować - projekt częściowo na zamówienie.
Diwi
Hmm.. nie wiedziałem że w ankiecie odpowiedź może mieć 148.28%

Pozdrawiam
klops
dzieki, cos bede myslal smile.gif
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.