PHP & Gameserver Socket

  • Da ich gefragt wurde, wie man Funktionen über das UCP / Forum ausführen kann,
    wollte ich hier mal ein kleinen Code Schnipsel releasen.
    Es handelt sich um das Socket Plugin von BlueG


    PHP
    $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);socket_connect($socket, '127.0.0.1' , 13377);$message = "SPAWN:xGreekz7x";socket_send($socket, $message, strlen($message), 0);$buffer = socket_read ($socket, 1024);if( intval($buffer) == true )	echo "Der Spieler konnte gespawnt werden!\n";else	echo "Der Spieler konnte nicht gespawnt werden, Fehler: ". $buffer ."!\n";$message_ = "GIVEMONEY:xGreekz7x:-1200";socket_send($socket, $message_, strlen($message_), 0);$buffer = socket_read ($socket,  1024);if( intval($buffer) == true ) 	echo "Der Spieler hat das Geld erfolgreich erhalten!\n";else	echo "Fehler beim vergeben des Geldes: Error: ". $buffer ." \n";


    PAWN Quelltext


    enum playerData {
    pCash
    }

    PAWN Quelltext
    new pInfo[MAX_PLAYERS][playerData],
    Socket:_socket;

    PAWN Quelltext
    main(){}

    PAWN Quelltext
    public OnGameModeInit()
    {
    SetGameModeText("Blank Script");
    AddPlayerClass(0, 1958.3783, 1343.1572, 15.3746, 269.1425, 0, 0, 0, 0, 0, 0);

    _socket = socket_create( TCP );
    if( is_socket_valid( _socket ) ) {
    socket_set_max_connections( _socket, 10 );
    socket_listen( _socket, 13377 );
    }
    return 1;
    }

    PAWN Quelltext
    public OnGameModeExit()
    {
    if(is_socket_valid(_socket))
    socket_destroy(_socket);
    }

    PAWN Quelltext
    public onSocketReceiveData(Socket:id, remote_clientid, data[], data_len)
    {
    new command[20], ucp_command[34];

    if( sscanf( data, "p<:>s[20]{}", command) )
    return socket_sendto_remote_client(id, remote_clientid, "Fehlende Parameter!");

    format( ucp_command, 34, "UCP_Function_%s", command );

    CallRemoteFunction(ucp_command, "si", data, remote_clientid);
    return 1;
    }

    PAWN Quelltext
    forward UCP_Function_SPAWN( data[], remote_clientid );
    public UCP_Function_SPAWN( data[], remote_clientid ) {
    print("Call -> Socket -> Spawn");
    new
    userID;

    if( sscanf( data, "p<:>{s[20]}u", userID))
    return socket_sendto_remote_client(_socket, remote_clientid, "Fehlende Parameter!");

    if( !IsPlayerConnected( userID ) )
    return socket_sendto_remote_client(_socket, remote_clientid, "Dieser Spieler ist offline!");

    if(SpawnPlayer(userID))
    return socket_sendto_remote_client(_socket, remote_clientid, "1");

    return socket_sendto_remote_client(_socket, remote_clientid, "Unbekannter Fehler!");
    }

    PAWN Quelltext
    forward UCP_Function_GIVEMONEY( data[], remote_clientid );
    public UCP_Function_GIVEMONEY( data[], remote_clientid ) {
    print("Call -> Socket -> Givemoney");
    new
    userID, money;
    if( sscanf( data, "p<:>{s[20]}ui", userID, money))
    return socket_sendto_remote_client(_socket, remote_clientid, "Fehlende Parameter!");

    PAWN Quelltext
    if( !IsPlayerConnected( userID ) )
    return socket_sendto_remote_client(_socket, remote_clientid, "Dieser Spieler ist offline!");

    if( GivePlayerMoney(userID, money) )
    return pInfo[userID][pCash] += money, socket_sendto_remote_client(_socket, remote_clientid, "1");

    return socket_sendto_remote_client(_socket, remote_clientid, "Unbekannter Fehler!");
    }


    Viel Glück damit! ;)

  • Wäre das nicht einfacher möglich, indem man die SAMP Rcon API verwendet und Custom RCON Befehle an den Server sendet? Diese kann man ja dann in OnRconCommand() prüfen und entsprechend auswerten.
    Denn im Endeffekt ist ein Socket genauso eine Verbindung wie die RCON-Querys, also eigentlich das Rad neu erfunden ;)

    Professioneller Webentwickler.

  • Das ist richtig. Man könnte das aber z.B. auch mit HTTP Post-Daten einfach realisieren.
    Aber das ist eine Frage des Einsatzgebiets. Die Lösung mit den Sockets ist jedenfalls auch machbar und für manche sicher hilfreich.

    Professioneller Webentwickler.

  • Diese Sockets, sind der absolute Schwachpunkt bei SA:MP Servern, nicht nur das man Threads in Threads laufen lässt,
    sondern gefährlich wird es dann, nicht nur für den SA:MP Server, wenn jemand den Port für die Sockets rausfindet und damit den Server floodet.


    Außerdem fehlt bei deinem Code die Absicherung gegen unendliche Socketverbindungen.


    Wenn ich 5 Überweisungen mache, werden auch 5 Verbindungen aufgebaut ohne diese zu schließen.
    Der Thread des Servers wird dann immer im Listen hängen bleiben, was irgendwann zum absturz des Server führen kann.

    "Bevor ich mir Informationen aus der "Bild" hole,
    werde ich anfangen, Wahlergebnisse danach vorauszusagen,
    neben welchen Busch unsere Katze gepinkelt hat."

    Margarete Stokowski

  • Diese Sockets, sind der absolute Schwachpunkt bei SA:MP Servern, nicht nur das man Threads in Threads laufen lässt,
    sondern gefährlich wird es dann, nicht nur für den SA:MP Server, wenn jemand den Port für die Sockets rausfindet und damit den Server floodet.


    Außerdem fehlt bei deinem Code die Absicherung gegen unendliche Socketverbindungen.


    Wenn ich 5 Überweisungen mache, werden auch 5 Verbindungen aufgebaut ohne diese zu schließen.
    Der Thread des Servers wird dann immer im Listen hängen bleiben, was irgendwann zum absturz des Server führen kann.

    Das ist doch nur ein Codeschnipsel ^^

  • do.de - Domain-Offensive - Domains für alle und zu super Preisen
  • Dadurch 'socket_sendto_remote_client' sendet er die antwort und der client wird disconnected.
    Ich habe dies einfach mal als ganz kleines beispiel gemacht, da ich gefragt wurde.
    Richtig gearbeitet habe ich damit noch nie.


    edit:// Die Absicherung gegen unendliche Socketverbindungen ist drin:

    Zitat

    socket_set_max_connections( _socket, 10 );

  • Die Absicherung gegen unendliche Socketverbindungen ist drin:


    Du baust trotzdem immer wieder eine neue Verbindung auf.


    mit "socket_sendto_remote_client" sendest du zwar eine antwort, beendest den Socket aber nicht.
    Das würde dann über "socket_close_remote_client" Funktionieren.


    Wenn ich mir das so anschaue, würde es theoretisch sowieso nur 10 mal funktionieren, sofern im Pugin nicht irgendwann ein Timeout mit drin steckt,
    weil wie gesagt du beendest die Sockets nicht

    "Bevor ich mir Informationen aus der "Bild" hole,
    werde ich anfangen, Wahlergebnisse danach vorauszusagen,
    neben welchen Busch unsere Katze gepinkelt hat."

    Margarete Stokowski

  • Den Socket beende ich nicht


    Wie erst sagst du, du trennst die Verbindung, was du in deinem Code allerdings nicht tust, außer in OnGameModeExit.
    Dann sagst du, du beendest ihn nicht.
    Widerspruch :P


    Ich disconnecte immer den Client indem ich die Antwort abgebe.


    Tust du nicht.
    Zumindest nicht in deinem Beispiel.

    "Bevor ich mir Informationen aus der "Bild" hole,
    werde ich anfangen, Wahlergebnisse danach vorauszusagen,
    neben welchen Busch unsere Katze gepinkelt hat."

    Margarete Stokowski

  • Wurde in der Konsole geschrieben:


    public onSocketRemoteConnect(Socket:id, remote_client[], remote_clientid)
    {
    printf("\nIncoming connection from [%d:%s]", remote_clientid, remote_client);
    return 1;
    }


    public onSocketRemoteDisconnect(Socket:id, remote_clientid)
    {
    printf("\nRemote client [%d] has disconnected.", remote_clientid); // [id:ip]
    return 1;
    }

  • do.de - Domain-Offensive - Domains für alle und zu super Preisen