UDP Nachrichten versenden und empfangen
Das Transport Protokol UDP ist der kleine Bruder von TCP. UDP ist nicht verlässlich, die Reihenfolge der Pakete ist beim Empfänger eventuell eine andere als beim Absender und es gibt nur eine Fehler-Erkennung, aber keine Fehler-Korrektur. Doch UDP bietet auch Vorteile: Es ist deutlich schneller als TCP (schneller meint hier dass die Pakete schneller beim Empfänger sind), es muss kein aufwändiger Handshake durchgeführt werden, es werden insgesamt weniger Ressourcen verbraucht.
Ein kurzes Beispiel, wie ein UDP Client aussieht, der einfach die IP-Adresse des aktuellen Webbesuchers an einen Server schickt:
<?php $socket = fsockopen('udp://192.168.1.33:10000'); fputs($socket, $_SERVER['REMOTE_ADDR']);
So einfach kann es sein. Dies speichern wir als client.php auf unserem Webserver und lassen beispielsweise Apache Bench laufen:
ab -k -n 2000 -c 50 http://udp.localhost/client.php This is ApacheBench, Version 2.3 <$Revision: 655654 $> Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Licensed to The Apache Software Foundation, http://www.apache.org/ Benchmarking udp.localhost (be patient) Completed 200 requests Completed 400 requests Completed 600 requests Completed 800 requests Completed 1000 requests Completed 1200 requests Completed 1400 requests Completed 1600 requests Completed 1800 requests Completed 2000 requests Finished 2000 requests Server Software: Apache/2.2.12 Server Hostname: udp.localhost Server Port: 80 Document Path: /client.php Document Length: 0 bytes Concurrency Level: 50 Time taken for tests: 2.747 seconds Complete requests: 2000 Failed requests: 0 Write errors: 0 Keep-Alive requests: 2000 Total transferred: 540050 bytes HTML transferred: 0 bytes Requests per second: 728.03 [#/sec] (mean) Time per request: 68.679 [ms] (mean) Time per request: 1.374 [ms] (mean, across all concurrent requests) Transfer rate: 191.98 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 0 0.1 0 1 Processing: 13 68 4.6 68 86 Waiting: 13 68 4.6 68 86 Total: 13 68 4.5 68 86 Percentage of the requests served within a certain time (ms) 50% 68 66% 69 75% 70 80% 71 90% 72 95% 73 98% 75 99% 76 100% 86 (longest request)
Wir können also ungefähr 700 Requests pro Sekunde abfeuern. Aber halt, wohin werden die UDP-Pakete verschickt? Richtig, sie gehen ins Nirwana, es läuft noch kein entsprechender Server, und da UDP sich nicht darum kümmert ob die Pakete ankommen oder nicht (fire and forget) funktioniert es. Würden wir TCP verwenden, wäre unser Skript sehr langsam, es würde versuchen eine Verbindung aufzubauen, und nach X Sekunden würde der Versuch abgebrochen falls kein Server gefunden wird, und es hagelt Fehlermeldungen.
In diesem Fall wäre es uns egal falls der Server (Sammler) nicht läuft, denn es sollen nur IP-Adressen geloggt werden oder beispielsweise soll ein kleines Reporting-Tool einige Statistiken sammeln. Die Daten sind nicht so wichtig als dass die Webseite darunter leiden soll wenn der Reporting-Server mal nicht erreichbar ist.
Wie sieht ein einfacher Server aus?
<?php $socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); if (!$socket) die('Unable to create socket'); if (!socket_bind($socket, null, 10000)) die('Unable to bind socket'); while(true) { $data = @socket_read($socket, 15); echo $data . "\n"; // oder in eine Datei schreiben }
10000 ist der Port, auf dem wir die Nachrichten empfangen wollen. null bedeutet hier dass wir auf allen Interfaces lauschen wollen, hier könnte man auch nur bestimmte Adressen (bspw: 192.168.1.33 oder localhost) nehmen. Da es keine Authentifizierung gibt sollte natürlich darauf geachtet werden wo man den Port öffnet. Die 15 bedeutet dass wir maximal 15 Byte erwarten, da eine IPv4-Adresse nicht länger sein kann. Sollen beliebig große Nachrichten empfangen werden muss dies erhöht werden.