• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

PHP sockets dane z TCP do UDP i vice versa

Object Storage Arubacloud
0 głosów
658 wizyt
pytanie zadane 17 sierpnia 2019 w PHP przez ozi22 Nowicjusz (120 p.)

Witam wszystkich!!

W kilku zdaniach postaram się przedstawić ideę projektu i problemy na jakie natrafiłem.

Programowaniem zajmuje się od niedawna (jest to dla mnie ciekawe hobby), z wykształcenia elektronik, a że często elektronika idzie w parze z programowaniem postanowiłem że spróbuję zrealizować swój pomysł na tak zwany inteligętny dom którym będę mógł zarządzać z telefonu z dowolnego miejsca. Wiem ze w sieci jest sporo gotowców ale co to za frajda i przyjemność z zrobienia copy/paste !!.

Otóż cała idea wygląda tak w domu mam kilka mikrokontrolerów opartych na ESP8266(ESP12E) które zbierają dane temperatur,stanów przekaźników, różnych czujników i same mogą też coś załączyć, wszystkie sterowniki ESP komunikują (po WI-FI)się miedzy sobą i domowym serwerem po UDP (broadcast)  na danym porcie.

Na serwerze(Ubuntu server 16.04) napisałem w php (wiem że zasadniczo php do tego nie służy, ale ten język mi się spodobał) na miarę swoich możliwości program który jest uruchomiony w tle i jego zadaniem jest nasłuchiwanie czy do gniazda TCP został podłączony klient, jeżeli tak to po odebraniu danych od klienta (w tym przypadku aplikacja na telefonie) przekazuje je dalej ale już po UDP i następnie w drugą stronę dane z UDP wysyła po TCP do podłączone klienta.

np1: dane od klienta TCP w postaci (string) "U=" jest wysyłane co 100milisekund, server po otrzymaniu "U=" wysyła do klienta  dane które otrzymał ze sterowników ESP po UDP. (VP201=1/VP202=0/VP203=0/) aktualne stany logiczne przekaźników oznaczonych jako 201,202,203

np2: dane od klienta TCP w postaci (string) "?=" dane otrzymane od klienta zaczynające się od  "?=" informują server że wszystko co jest po '?=" ma być dalej przesłane po UDP(broadcast) do wszystkich sterowników ESP jednoczesnie.(?=?VP201=1  otrzymane z TCP po przemieleniu przez server będą wysłane przez UDP w postaci ?VP201=1  ,to załączy przekaźnik oznaczony jako 201)    

  Ogólnie ta komunikacja jakoś działa i nawet szybko ale problem jest taki ze server ma losowe zawieszki,  czasami działa bez problemu ponad tydzień a czasami kilka godzin. W serwerze nie ma przewidzianej obsługi wielu klientów i raczej nie będzie(nie przewiduję żeby jeszcze ktoś to obsługiwał)

Przedstawiam kod programu w komentarzach starałem się opisać do czego służy dana funkcja. Jeżeli przeoczyłem jakąś oczywistą informacje bądź coś jest niezrozumiałe proszę dać znać. Jestem otwarty na wszelkie sugestie co do zmian w programie lub ewentualnie napisanie od nowa.

Z góry dziękuję!

<?php
error_reporting(E_ALL);


set_time_limit(0);


ob_implicit_flush();

$address = '0.0.0.0';
$port =5555;   //nr portu nasłuchu TCP

//************UDP***************
$socket_UDP =socket_create(AF_INET,SOCK_DGRAM,SOL_UDP);
echo "Socket created \n";
socket_set_option($socket_UDP, SOL_SOCKET, SO_BROADCAST, 1);
socket_bind($socket_UDP,'0.0.0.0',1111) or die('Could not bind to address');  //otwarcie portu nasluchu UDP dla aktualnych danych nr portu 1111



//***********TCP******************

if (($sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) === false) {
    echo "socket_create() failed: reason: " . socket_strerror(socket_last_error()) . "\n";
}
socket_set_option($sock, SOL_SOCKET, SO_REUSEADDR, 1);
if (socket_bind($sock, $address, $port) === false) {
    echo "socket_bind() failed: reason: " . socket_strerror(socket_last_error($sock)) . "\n";
}

if (socket_listen($sock, 1) === false) {
    echo "socket_listen() failed: reason: " . socket_strerror(socket_last_error($sock)) . "\n";
}

socket_set_nonblock($socket_UDP);
socket_set_nonblock($sock);


do {

	usleep(10000);  //zeby nie zamulać procka gdy brak podlaczonego klienta
//	@socket_recvfrom($socket_UDP, $dane_UDP, 512,MSG_DONTWAIT, $remote_ip, $remote_port);
 //if (strlen($dane_UDP)>1){
 //echo $dane_UDP."\n";

    $odczyt_UDP =  socket_read($socket_UDP,512);
	if (($msgsock = @socket_accept($sock)) === false) {
      //  echo "socket_accept() failed: reason: " . socket_strerror(socket_last_error($sock)) . "\n";
    unset($msmsock);
	//continue;
   }else {
	
		$send_info="Start";  
		socket_write($msgsock, $send_info, strlen($send_info));
		
		 do {
			
	
		 if (false === ($buf = @socket_read($msgsock, 2048, PHP_NORMAL_READ))) {
         //   echo "socket_read() failed: reason: " . socket_strerror(socket_last_error($msgsock)) . "\n";
			//echo "w false socket read \n";
			if ($buf==False ||$buf==0){    //echo"kasowanie rozlaczonego  klienta nr ".$msgsock;
				
				unset($msgsock);
				flush();
				break;
			}
		  break ;
			
        }
	
		$buf = trim($buf);                 //parsowane danych od klienta z TCP
        if (!$buf = trim($buf)) {
            continue;
		
        }
	/*	//echo "3\n";
        if ($buf == 'quit') {
            break;
			
        }
		//echo "4\n"; 
        if ($buf == 'shutdown') {
            socket_close($msgsock);
            break 2;
        }
		*/
		if(strlen($buf)>1){
	
						
						$rozkaz =substr($buf,0,strpos($buf,"="));  //wyłuskanie komendy rozkazu
	
							if($rozkaz =="U"){							  //update danych . odebrane dane z UDP wysyła do podłaczonego klienta z TCP
							$odczyt_UDP =  @socket_read($socket_UDP,512);
								if(strlen($odczyt_UDP)>1){
								socket_write($msgsock,$odczyt_UDP,strlen($odczyt_UDP)); 
								$odczyt_UDP="";
								}
								
							$odczyt_UDP="";
								
							}
							elseif($rozkaz == "?"){                       //wysyłanie danych otrzymanych od klienta z TCP na UDP broadcast (sterowniki na esp8266)
								try {
								$wartosc =substr($buf,strpos($buf,"=")+1);
								$string_txt="?".$wartosc;
								//socket_sendto($socket_UDP,$string_txt,strlen($string_txt),0,'192.168.1.255',2222);
								send_udp($socket_UDP,$string_txt);
								}
								catch(Exception $e){
									echo 'Wystąpił wyjątek nr '.$e->getCode().', jego komunikat to:'.$e->getMessage();
								}
		
							}
							elseif($rozkaz == "R"){                     //pobieranie danych z mysql do klienta TCP w celu rysowania wykresu (np R100 (indeks 100) to temperatura zewnetrzna) 
								
								$wartosc =substr($buf,strpos($buf,"=")+1);
								$output= odczyt_mysql($wartosc);
								
								socket_write($msgsock, $output, strlen($output));	//wysłanie logu do klienta
			
									} 
			
							}
						
		$odczyt_UDP="";
		 }while (true);
	
	
	
   
	flush();

	$odczyt_UDP="";
		 
  @socket_close($msgsock);
		 
		 }	
} while (true);
 flush();

/*function read($sock){
    while($buf = @socket_read($sock, 1024, PHP_NORMAL_READ))
        if($buf = trim($buf))
            break;

    return $buf;
}*/
/*
function UDP_odczyt($UDP_socket){
	$r = socket_recvfrom($UDP_socket, $dane_UDP, 512,MSG_DONTWAIT, $remote_ip, $remote_port);
return $dane_UDP;	
}
function send_udp($socket,$text_to_send){
	socket_sendto($socket,$text_to_send,strlen($text_to_send),0,'255.255.255.255',2222);
	
} */
function odczyt_mysql($wartosc){
	$servername = "localhost";
$username = "xxxx";
$password = "xxxxxxxxx";
$dbname = "log_parametrow";
$output_msg="R$wartosc=";
$conn = new mysqli($servername, $username, $password, $dbname);
if ($conn->connect_error) {
    die("Connection failed: " . $conn->connect_error);
} 
$sql = "SELECT VP$wartosc FROM (SELECT * FROM VP$wartosc ORDER BY Lp DESC LIMIT 2880) sub ORDER BY Lp ASC";// limit do 2880 pomiarow co daje wykres z ostatnich 9 dni
//$sql = "SELECT VP$wartosc FROM VP$wartosc";
$result = $conn->query($sql);

if ($result->num_rows > 0) {
    while($row = $result->fetch_assoc()) {
        $output_msg.= $row["VP$wartosc"] . ":";
    }
	//echo $output_msg;
} else {
  //  echo "0 results";
}
return $output_msg;
$conn->close();

}
?>

 

1 odpowiedź

–2 głosów
odpowiedź 17 sierpnia 2019 przez Wraith Gaduła (4,370 p.)
edycja 17 sierpnia 2019 przez Wraith
Przepisz to na jezyk C++

Podobne pytania

0 głosów
0 odpowiedzi 262 wizyt
pytanie zadane 21 stycznia 2019 w C# przez kubekszklany Gaduła (3,190 p.)
0 głosów
1 odpowiedź 711 wizyt
pytanie zadane 30 stycznia 2018 w Sieci komputerowe, internet przez niezalogowany
+1 głos
1 odpowiedź 245 wizyt
pytanie zadane 22 grudnia 2016 w Sieci komputerowe, internet przez Marecki Obywatel (1,690 p.)

92,576 zapytań

141,426 odpowiedzi

319,652 komentarzy

61,961 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...