Avatar billede DGudiksen Nybegynder
19. december 2012 - 20:54 Der er 13 kommentarer og
1 løsning

Socket vil ikke bind.

Hej eksperter, er ny inden for PHP sockets. Men har kastet mig ud i det, og kan virkelig ikke få min socket til at bind.

Linje ser således ud:

[code]
@socket_bind($this->master, $this->address, $this->port) or die($this->log('Could not bind to socket'));
[/code]

Hele scriptet ser således her ud:

[code]
<?php
/**
* Class to handle a sockets server
* It's abstract class so you need to create another class that will extends ClsSocketServer to run your server
*
* @author Cyril Mazur    www.cyrilmazur.com    twitter.com/CyrilMazur    facebook.com/CyrilMazur
* @abstract
*/
abstract class ClsSocketServer {
    /**
    * The address the socket will be bound to
    * @var string
    */
    protected $address;
   
    /**
    * The port the socket will be bound to
    * @var int
    */
    protected $port;
   
    /**
    * The max number of clients authorized
    * @var int
    */
    protected $maxClients;
   
    /**
    * Array containing all the connected clients
    * @var array
    */
    protected $clients;
   
    /**
    * The master socket
    * @var resource
    */
    protected $master;
   
    /**
    * Constructor
    * @param string $address
    * @param int $port
    * @param int $maxClients
    * @return ClsSocketServer
    */
    public function __construct($address,$port,$maxClients) {
        $this->address        = $address;
        $this->port            = $port;
        $this->maxClients    = $maxClients;
        $this->clients        = array();
    }
   
    /**
    * Start the server
    */
    public function start() {
        // flush all the output directly
        ob_implicit_flush();
       
        // create master socket
        $this->master = @socket_create(AF_INET, SOCK_STREAM, 0) or die($this->log('Could not create socket'));

        // to prevent: address already in use
        socket_set_option($this->master, SOL_SOCKET, SO_REUSEADDR, 1) or die($this->log('Could not set up SO_REUSEADDR'));
       
        // bind socket to port
        @socket_bind($this->master, $this->address, $this->port) or die($this->log('Could not bind to socket'));
       
        // start listening for connections
        socket_listen($this->master) or die($this->log('Could not set up socket listener'));
       
        $this->log('Server started on ' . $this->address . ':' . $this->port);
       
        // infinite loop
        while(true) {
            // build the array of sockets to select
            $read    = array_merge(array($this->master),$this->clients);
           
            // if no socket has changed its status, continue the loop
            socket_select($read,$write = null,$except = null,$tv_sec = null);
           
            // if the master's status changed, it means a new client would like to connect
            if (in_array($this->master,$read)) {
               
                // if we didn't reach the maximum amount of connected clients
                if (sizeof($this->clients) < $this->maxClients) {
                   
                    // attempt to create a new socket
                    $socket = socket_accept($this->master);
                   
                    // if socket created successfuly, add it to the clients array and write message log
                    if ($socket !== false) {
                        $this->clients[] = $socket;
                       
                        if (socket_getpeername($socket,$ip)) {
                            $this->log('New client connected: ' . $socket . ' (' . $ip . ')');
                        } else {
                            $this->log('New client connected: ' . $socket);
                        }
                       
                        $this->onClientConnected($socket);
                       
                    // else display error message to the log console
                    } else {
                        $this->log('Impossible to connect new client',true);
                    }
               
                // else tell the client that there is not place available and display error message to the log console
                } else {
                    $socket = socket_accept($this->master);
                    socket_write($socket,'Max clients reached. Retry later.' . chr(0));
                    socket_close($socket);
                   
                    $this->log('Impossible to connect new client: maxClients reached');
                }
               
                if (sizeof($read) == 1)
                    continue;
            }
           
            // foreach client that is ready to be read
            foreach($read as $client) {
               
                // we don't read data from the master socket
                if ($client != $this->master) {
                   
                    // read input
                    $input = @socket_read($client, 1024, PHP_BINARY_READ);
                   
                    // if socket_read() returned false, the client has been disconnected
                    if (strlen($input) == 0) {
                        // disconnect client
                        $this->disconnect($client);
                       
                        // custom method called
                        $this->onClientDisconnected($client);
                   
                    // else, we received a normal message
                    } else {
                        $input = trim($input);
                       
                        // special case of a domain policy file request
                        if ($input == '<policy-file-request/>') {
                            $cmd = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><cross-domain-policy xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"http://www.adobe.com/xml/schemas/PolicyFileSocket.xsd\"><allow-access-from domain=\"*\" to-ports=\"*\" secure=\"false\" /><site-control permitted-cross-domain-policies=\"master-only\" /></cross-domain-policy>";
                           
                            $this->log('Policy file requested by ' . $client);
                            socket_write($client,$cmd . chr(0));
                           
                        // normal case, standard message
                        } else {
                            // custom method called
                            $this->onDataReceived($client,$input);
                        }
                    }
                }
            }
        }
    }
   
    /**
    * Stop the server: disconnect all the coonected clients, close the master socket
    */
    public function stop() {
        foreach($this->clients as $client) {
            socket_close($client);
        }
       
        $this->clients = array();
       
        socket_close($this->master);
    }
   
    /**
    * Disconnect a client
    * @param resource $client
    * @return bool
    */
    protected function disconnect($client) {
        // close socket
        socket_close($client);
       
        // unset variable in the clients array
        $key = array_keys($this->clients,$client);
        unset($this->clients[$key[0]]);
       
        $this->log('Client disconnected: ' . $client);
       
        return true;
    }
   
    /**
    * Send data to a client
    * @param resource $client
    * @param string $data
    * @return bool
    */
    protected function send($client,$data) {
        return @socket_write($client, $data . chr(0));
    }
   
    /**
    * Send data to everybody
    * @param string $data
    * @return bool
    */
    protected function sendBroadcast($data) {
        $return = true;
        foreach($this->clients as $client) {
            $return = $return && socket_write($client, $data . chr(0));
        }
       
        return $return;
    }
   
    /**
    * Method called after a value had been read
    * @abstract
    * @param resource $socket
    * @param string $data
    */
    abstract protected function onDataReceived($socket,$data);
   
    /**
    * Method called after a new client is connected
    * @param resource $socket
    */
    abstract protected function onClientConnected($socket);
   
    /**
    * Method called after a new client is disconnected
    * @param resource $socket
    */
    abstract protected function onClientDisconnected($socket);
   
    /**
    * Write log messages to the console
    * @param string $message
    * @param bool $socketError
    */
    public function log($message,$socketError = false) {
        echo '[' . date('d/m/Y H:i:s') . '] ' . $message;
       
        if ($socketError) {
            $errNo    = socket_last_error();
            $errMsg    = socket_strerror($errNo);
           
            echo ' : #' . $errNo . ' ' . $errMsg;
        }
       
        echo "\n";
    }
}
?>
[/code]
Avatar billede olebole Juniormester
19. december 2012 - 21:13 #1
<ole>

Hvad sker der? Hvad sker der ikke? Hvad havde du forventet skulle ske? Får du fejl? Hvilket niveau er dine PHP fejlmeldinger sat til?

/mvh
</bole>
Avatar billede erikjacobsen Ekspert
19. december 2012 - 21:19 #2
Og hvordan udfører du dette script? Hvad skal du bruge det til?
Avatar billede DGudiksen Nybegynder
20. december 2012 - 19:23 #3
Der sker ikke noget, udover at den skriver "Could not bind to socket" . Der skulle gerne skrive f.eks "User connected" osv. Det henter jeg i en anden fil. Men det er i den fil som jeg har postet den skriver fejlen.
Avatar billede olebole Juniormester
20. december 2012 - 19:36 #4
Prøv at svare på de andre spørgsmål:

Hvad skal du bruge det til?
Hvordan bruger du det?
Hvilket niveau er dine PHP fejlmeldinger sat til?
Avatar billede DGudiksen Nybegynder
20. december 2012 - 21:01 #5
Jamen jeg skal bruge det til at "fange" alt der sker på min webside, skal senere bruges til noget chat system.

Bruger det bare ved at loade siden :).
Avatar billede erikjacobsen Ekspert
20. december 2012 - 21:07 #6
Det kan du ikke. Det script du viser et udsnit af, skal køre hele tiden, og på et webhotel kører det kun i de par millisekunder det tager at lave HTML-koden. Desuden har du ikke administratorrettighder, og derfor er der i hvert fald porte du slet ikke kan åbne.

Skal du lege med det, så er det på egen webserver, evt. en virtuel server. Så skal PHP-scriptet køre uafhængigt af webserveren... og så kan man tænke over om lige PHP er mest velegnet.
Avatar billede erikjacobsen Ekspert
20. december 2012 - 21:08 #7
Ok, et "web" for meget:
Skal du lege med det, så er det på egen *server* ...
Avatar billede DGudiksen Nybegynder
20. december 2012 - 21:50 #8
jeg bruger egen server. Og tjae måske er PHP ikke det mest venegnede, men nu er det sådan at jeg kun kan kode PHP . Og chatten er et projekt, ikke noget der skal videre ud i livet som sådan.
Avatar billede erikjacobsen Ekspert
20. december 2012 - 21:59 #9
Hvilken port prøver du med?  Du kan prøve at køre dit script fra en kommandolinie på serveren.
Avatar billede DGudiksen Nybegynder
20. december 2012 - 22:03 #10
kan jeg ikke kører det gennem browseren? - kører port 9283
Avatar billede DGudiksen Nybegynder
20. december 2012 - 23:28 #11
Jeg fandt ud af at det bare var mig som var idiot, jeg kørte det via CMD promt, som gjorde at "serveren" kørte hele tiden, så kunne jeg sagtens få den til at modtage data. Men jeg har så lige et spørgsmål.

Jeg har en PHP side, hvor jeg gerne vil modtage det der sker på serveren. hvordan henter jeg via PHP det ud? - Kan kun få det til at hente en linje af gangen, hvorefter jeg skal opdatere for at hente den nyeste igen. Vil gerne den selv bare opdatede det.

<?php
error_reporting(E_ALL);

echo "<h2>TCP/IP Connection</h2>\n";

/* Get the port for the WWW service. */
$service_port = 8001;

/* Get the IP address for the target host. */
$address = gethostbyname('127.0.0.1');

/* Create a TCP/IP socket. */
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
$result = socket_connect($socket, $address, $service_port);
$buf = 'This is my buffer.';
if (false !== ($bytes = socket_recv($socket, $buf, 100048, MSG_WAITALL))) {
    echo "Read $bytes bytes from socket_recv(). Closing socket...";
} else {
    echo "socket_recv() failed; reason: " . socket_strerror(socket_last_error($socket)) . "\n";
}
socket_close($socket);

echo $buf . "\n";
echo "OK.\n\n";
?>

Det er velogmærket taget fra php.net - Da jeg slet ikke har styr på sockets, men ønsker at få det. Håber i kan hjælpe mig her :)
Avatar billede erikjacobsen Ekspert
21. december 2012 - 00:24 #12
Hvis din server kun giver een linie, så får du kun een linie. Jeg kan ikke lige gennemskue hvad din server gør.
Avatar billede olebole Juniormester
21. december 2012 - 00:38 #13
Det var nok en af grundene til, erikjacobsen nævnte det faktum, at PHP ikke er særlig egnet til chat applikationer  *o)

PHP virker udelukkende på serveren. Når først dokumentet har forladt serveren og ligger i brugerens browser, kan PHP ikke gøre noget ved dokumentet. Brugerens browser er nødt til at forespørge serveren igen for at få nye data at vise. PHP kan ikke push'e data til klienten. PHP skal poll'es.

Du kan hente data med Ajax (JavaScript) f.eks. hver 5-10 sekunder. Så er du dog nødt til at holde styr på, hvad brugeren allerede har downloaded, så hun ikke tvinges til at downloade samme data om og om igen.

I så fald gemmes beskeder i en database sammen med et timestamp. Hvergang klienten forespørger serveren, medsender den timestamp for seneste hentning - og får kun beskeder med tilbage, som er yngre end dette timestamp.

Den slags polling er særlig effektiv, hvorfor man normalt bruger andre sprog til chats - f.eks. Java - og evt. selv skriver selve webserveren.
Avatar billede DGudiksen Nybegynder
15. april 2014 - 17:57 #14
lukket
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Vi tilbyder markedets bedste kurser inden for webudvikling

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester