Re: [GENERAL-BG] Socekt Server Problem

From: Date: Sun, 13 Feb 2005 18:26:16 +0000
Subject: Re: [GENERAL-BG] Socekt Server Problem
References: 1  Groups: php.general.bg 
Request: Send a blank email to general-bg+get-238@lists.php.net to get a copy of this message
Здравей, този скрипт под уиндоус ли го пускаш? Ако не е под уиндоус, може да опиташ с ext/pcntl, и да правиш pcntl_fork(), вместо да стартираш външен процес. Само мога да ти кажа, че имаш race condition, като извикваш нов интерпретатор, защото при високо натоварване в главният ти сървър свободният порт може да се bind-не отново докато се стартира "детският"(child) ти сървър. Доколкото съм си играл, тази грешка, че другата страна е затворила връзката, идва когато се разпадне връзката. Например ако клиента ти затвори връзката. Грешката, която получаваш, при повторно стартиране е защото сървърският ти порт вече е закачен. Beej's Guide To Network Progamming казва следното : ------------------ "Sometimes, you might notice, you try to rerun a server and bind() fails, claiming "Address already in use." What does that mean? Well, a bit a of socket that was connected is still hanging around in the kernel, and it s hogging the port. You can either wait for it to clear (a minute or so), or add code to your program allowing it to reuse the port, like this: int yes=1; //char yes= 1 ; // Solaris people use this // lose the pesky "Address already in use" error message if (setsockopt(listener,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) { perror("setsockopt"); exit(1); } ------------------ setsockopt() в PHP е socket_set_option(). Има един коментар, който казва следното: ------------------------ I am not sure if the fourth argument (optval) is used in SO_REUSEADDR ... I don't think it is... In that case, this is how you set your socket re-usable: socket_set_option($socket,SOL_SOCKET,SO_REUSEADDR,1); ------------------------ Като допълнения искам да те посъветвам, че може да използваш __LINE__ и __FILE__, константите, в съобщенията ти за грешка. Например : printf("Bad error [%s::%d]", __FILE__, __LINE__) и така няма да ти се налага да сменяш всяко съобщения, като му промениш мястото във файла. Ако използваш PHP5, тогава може да пробваш stream_socket_server() и компания вместо ext/sockets, който все още си е експериментален модул (след 4 години мисля) и си няма програмист, който да го поддържа активно. Докато потоците се поддържат от Уез Фърлонг. За съжаление понякога са по-малко гъвкави. Например не можеш да сменяш беклога на сървърското гнездо (сокет). Мисля, че в сорса на PHP е настроен да е 5, но това е поправима грешка, като се хакне сорса :) Преди няколко месеца се занимавах да пиша една чудесия, която позволява отдалечено извикване на процедури (RPC) с PHP5 и написана на ПХП. Т.е : <?php $a = new RPCClient("some_obj.hristov.com"); $a->testMethod(); ?> some_obj.hristov.com e име на обект, който е регистриран в сървър за имена. Цялата идеология е като при Corba и подобни Джава технологии. А отдолу лежи върху сокети или върху опашки от съобщения (SysV message queue). Само, че не знам вече докъде го докарах :), защото междувременно се занимавах с дипломната си работа основно. Надявам се, че поне малко съм ти помогнал, Андрей martin.nikolov@gmail.com wrote:
Imam problem sys sledniq socket server: <?php $start = date("Y-m-d H:i:s"); echo "Skriptyt e startiran: $start\n"; include("../includes/config.inc.php"); //Iztrivame wsichki online users - initialisation //$db->query("TRUNCATE online_users"); // VKLIUCHVAME FUNKCIITE ZA OBRABOTKA NA XML. include ("xml_parser_functions.php"); $file = "xml.log"; // VZEMAME ID-to NA USER-a. function get_uid_by_username($username) {
    global $db1;
    $query = "SELECT id FROM users WHERE username = '$username'";
    $db1->query($query);
    if (!$db1->nf())    {
        $uid = 0;
    } else {
        $db1->next_record();
        $uid = $db1->f("id");
    }
    return $uid;
} // VZEMAME ACCESS-a NA USER-a. function get_uaccess_by_username($username) {
    global $db1;
    $query = "SELECT access FROM users WHERE username = '$username'";
    $db1->query($query);
    if (!$db1->nf())    {
        $uaccess = 0;
    } else {
        $db1->next_record();
        $uaccess = $db1->f("access");
    }
    return $uaccess;
} error_reporting(E_ALL); /* Allow the script to hang around waiting for connections. */ set_time_limit(0); /* Turn on implicit output flushing so we see what we're getting * as it comes in. */ ob_implicit_flush(); if (($sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) < 0) { echo "socket_server.php line 52; socket_create() failed: reason: " . socket_strerror($sock) . "\n"; } if (($ret = socket_bind($sock, $net_address, $portnr)) < 0) { echo "socket_server.php line 56; socket_bind() failed: reason: " . socket_strerror($ret) . "\n";
     socket_close($sock);
} if (($ret = socket_listen($sock, 5)) < 0) { echo "socket_server.php line 61; socket_listen() failed: reason: " . socket_strerror($ret) . "\n";
     socket_close($sock);
} // Iztrivame vsichki zapisi ot tablica "online_users" ako ima takiva. $q = "DELETE FROM online_users"; $db->query($q); // Inicializirame broqcha, chrez koito tyrsim svobodni portove. $i = $min_sock; do {
    if (($msgsock = socket_accept($sock)) < 0) {
        echo "socket_server.php line 72; socket_accept() failed: reason: " . socket_strerror($msgsock) . "\n";
        socket_close($sock);
      break;
    }
    /* Send instructions. */
    echo "New user connected!\n";
    $msg = "\nWelcome to the PHP Test Server. \n" .
        "To quit, type 'quit'. To shut down the server type 'exit'.\n";
    socket_write($msgsock, $msg, strlen($msg));
    $msg_u_p = "\nEnter user and pass :";
    socket_write($msgsock, $msg_u_p, strlen($msg_u_p));
    do {
        if (false === ($buf = @socket_read($msgsock, 2048, PHP_NORMAL_READ))) {
            echo "socket_server.php line 86; socket_read() failed: reason: " . socket_strerror($ret) . "\n";
            socket_close($msgsock);
            break 2;
        }
        if (!($buf = trim($buf))) {
            continue;
        }
    } while (!$buf);
    // VZIMAME IP-to NA KLIENTA.
    socket_getpeername ($msgsock, $rip);
    $rip = trim($rip);
    // ZAPISVAME VHODQSHTATA INFORMACIQ V LOG FILE.
    $f = fopen($file, "a");
    $message = "INPUT :\n";
    $message .= $buf;
    $message .= "\n\n";
    fwrite($f, $message, strlen($message));
    fclose($f);
    // ZAPOCHVAME PARSVANETO NA XML-A, KOITO SE NAMIRA V BUFERA.
    include("xml_parse.php");
    // KRAI NA PARSVANETO NA XML-A, KOITO SE NAMIRA V BUFERA.
    $username = $els["login"]["username"];
    $pass = $els["login"]["password"];
    $pass = md5($pass);
    $q = "SELECT * FROM users WHERE username = '$username' AND password = '$pass' AND active = '1'";
    $db->query($q);
    if (!$db->nf()) {
        echo "Greshen Username ili Parola!\n";
        $out = "GRESHEN USERNAME OR PASSWORD !";
        socket_write($msgsock, $out, strlen($out));
        $msg_u_p = "\nCONNECTION IS CLOSED !";
        socket_write($msgsock, $msg_u_p, strlen($msg_u_p));
        continue;
    } else    {
        echo "Uspeshen whod!\n";
        $uid = get_uid_by_username($username);
        $uaccess = get_uaccess_by_username($username);
        if (($sock1 = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) < 0) {
            echo "socket_server.php line 130; socket_create() failed: reason: " . socket_strerror($sock1) . "\n";
        }
        if (($sock2 = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) < 0) {
            echo "socket_server.php line 133; socket_create() failed: reason: " . socket_strerror($sock2) . "\n";
        }
        // NAMIRAME PYRVITE 2 SVOBODNI PORT-a.
        do {
            if ($i > $max_sock) $i = $min_sock;
            if (($ret = socket_bind($sock1, $net_address, $i)) < 0) {
                echo "socket_server.php line 140; socket_bind() failed: reason: " . socket_strerror($ret) . "\n";
                $i++;
            } else {
                socket_close($sock1);
                // PORT, NA KOITO CLIENTA SHTE PRASHTA ZAQVKI NA SERVER-a I SHTE POLUCHAVA OTGOVOR.
                $port1 = $i;
                $j = $i + 1;
                do {
                    if ($j > $max_sock)$j = $min_sock;
                    if (($ret = socket_bind($sock2, $net_address, $j)) < 0) {
                        echo "socket_server.php line 150; socket_bind() failed: reason: " . socket_strerror($ret) . "\n";
                        $j++;
                    } else {
                        socket_close($sock2);
                        // PORT, NA KOITO CLIENTA SHTE POLUCHAVA DANNI NA VSEKI 20 SEC.
                        $port2 = $j;
                        // STARTIRANE NA SCRIPTA, KOITO SHTE RABOTI S CLIENT-a.
                        $q = "DELETE FROM online_users WHERE uid = '$uid'";
                        $db->query($q);
                        $q = "INSERT INTO online_users (uid, ip, port1, port2, connected) VALUES ('$uid', '$rip', '$port1', '$port2', 'false')";
                        $db->query($q);
                        echo "Startirane na market_child_socket.php $port1 $rip $uid $uaccess >> log &\n";
                        exec ("php market_child_socket.php $port1 $rip $uid $uaccess >> log &");
                        echo "Startirane na market_xml_send.php $uid >> /var/log/steinx/market_xml_send.log &\n";
                        exec ("php send/market_xml_send.php $uid $port2 
/var/log/steinx/market_xml_send.log &");
break; } } while (true); $i = $j + 1; break; } } while (true);
        // PRASHTAME XML NA KLIENTA I ZAPISVAME IZHODQSHTATA INFORMACIQ V LOG FILE.
        $xml_out = "<ports><port1>$port1</port1><port2>$port2</port2></ports>";
        socket_write($msgsock, $xml_out, strlen($xml_out));
        $msg_u_p = "\nCONNECTION IS CLOSED !";
        socket_write($msgsock, $msg_u_p, strlen($msg_u_p));
        $f = fopen($file, "a");
         $message = "OUTPUT :\n";
         $message .= $xml_out;
         $message .= "\n\n";
         fwrite($f, $message, strlen($message));
         fclose($f);
         $xml_out = "";
        unset ($els);
    }
    socket_close($msgsock);
} while (true); socket_close($sock); ?> Ot wreme na wreme serwyra se restartira sys slednoto syobstenie: Warning: socket_read(): unable to read from socket [104]: Connection reset by peer in /home/pub/market/xml_files/market_socket_server.php on line 86 socket_server.php line 86; socket_read() failed: reason: Operation not permitted Sled restarta izkarwa slednoo syobstenie: Warning: socket_bind(): unable to bind address [98]: Address already in use in /home/pub/market/xml_files/market_socket_server.php on line 56 i se nalaga da spra wsichki klientiand i da restartiram servera... Nakoj move li da mi pomogne ... da go naprawq po ustojchiw po nqkakyw nachin... ako ne da se restartira to pone sled restart da ne se nalaga da spiram wkliuchenite do sega klienti...


« previous php.general.bg (#238) next »