koraktor / steam-condenser

A multi-language library for querying the Steam Community, Source, GoldSrc servers and Steam master servers
https://koraktor.de/steam-condenser
Other
356 stars 67 forks source link

Catching TimeoutException. #90

Closed Dekkenn closed 13 years ago

Dekkenn commented 13 years ago

Well, I get it very very often, so I tried catching it and retrying the function again. But what this caused is, that even thought that the exception is caught, the rcon command is already sent successfully. So basically sometimes I send the same rcon command few times, instead of one time, because the exception is thrown few times in a row. Is there any way to know if the rcon command was successfully received? or catch the exception earlier in the code before it is 100% sent and received by the server?

The exception is thrown at line 61 in SteamCondenser\lib\steam\sockets\SteamSocket.php

public function receivePacket($bufferLength = 0)
{
    if(!$this->channel->socket()->select(1))
    {
        throw new TimeoutException();
    }

    if($bufferLength == 0)
    {
        $this->buffer->clear();
    }
    else
    {
        $this->buffer = ByteBuffer::allocate($bufferLength);
    }

    $this->channel->read($this->buffer);
    $bytesRead = $this->buffer->position();
    $this->buffer->rewind();
    $this->buffer->limit($bytesRead);

    return $bytesRead;
}

I used something like this to retry the command, maybe you got a better way?

$failed = true;
while($failed == true)
{
    try
    {
        $servers[1]->rcon("say Hello");
        $failed = false;
    }
    catch(TimeoutException $e)
    {
        $failed = true;
    }
}

This results in Hello being sent few times, when an exception is caught.

koraktor commented 13 years ago

Source's RCON uses TCP as the underlying protocol. That way, you can be sure, that your request has been received, once the first line of SourceServer#rconExec has been executed without error. A TimeoutExeception is only generated while receiving the server's reply. That way, you can simply ignore the exception, if you're not interested in the server's response.

If you're controlling a GoldSrc server, the solution isn't as simple. As GoldSrc uses UDP for RCON you can never be 100% sure if the server received your request until you get a response.

The main problem seems to be located elsewhere, though. It's pretty unusual that you get so many timeouts.

Dekkenn commented 13 years ago

Well, I am using a Team Fortress 2 server, and I do indeed need the response in some cases. Is there any workaround so I will get the response every single time, without sending the command dozen of times?

koraktor commented 13 years ago

Lik said before, there seems to be an essential problem with your setup. Maybe the server is responding slowly, your firewall interferes with the queries or something similar. The protocol (and my implementation) aren't very smart when it comes to RCON responses, but it it should work flawlessly though. Maybe you can give some additional details on your use case.

Dekkenn commented 13 years ago

Well, I use it to retrieve the status command, and then from there I take out the current sourceTV port, I use also allot of chat commands that don't require a response, and also checking the timeleft on the server. I send commands, and execute long configs. That is mostly what I use this for. My server is located in the UK, and my game server is located in Israel. It is located in the UK because I am connecting with my bot to the irc quakenet network. so its in the UK for the fastest response possible, and also because the same setup server in Israel would cost 5times more. The firewall is interfering with the connection, and the ping from my server to the server in Israel is around 120~, which shouldn't be that much of a problem.

I hope this is what you mean by "your use case".

koraktor commented 13 years ago

Thanks for the info.

Maybe you want to try the current development version which allows for customizing the socket timeouts. That way you could try even longer timeouts (1 second is default, which is already quite long). GitHub provides a source archive, if you are not familiar with Git.

Dekkenn commented 13 years ago

Okay, I will be sure to try it. I will report how it goes. thanks!

Dekkenn commented 13 years ago

Where do I adjust the socket timeout? :D In the UDPSocket.php file? if(!$this->socket = fsockopen("udp://$ipAddress", $portNumber, $socketErrno, $socketErrstr, 2))

koraktor commented 13 years ago

No, it's even simpler:

SteamSocket::setTimeout(2000); // 2000ms = 2s
Dekkenn commented 13 years ago

Can you show me an example of a piece of code? Not so sure about the proper usage.

koraktor commented 13 years ago

It's nothing special, use it just like an option. Any Steam Condenser query after SteamSocket::setTimeout() will use the new timeout.

SteamSocket::setTimeout(2000);
// Your code here...

SteamSocket::setTimeout(100);
// There's other code which doesn't need long timeouts
Dekkenn commented 13 years ago

Fatal error: Call to undefined method SteamSocket::settimeout()

What I meant is, embed it in some piece of code, like in the "RCONTests.php" file, so I could see this in action. Because for some reason I am having hard time to figure this out :o Or maybe I am just not using the latest version? grabbed it from the source tab.

koraktor commented 13 years ago

Sorry, it took me some time to reply.

The version you have should be the right one, although I released v0.12.0 yesterday. So you might take this.

Here's a code snippet which should demonstrate how to use timeout settings: https://gist.github.com/759593

Dekkenn commented 13 years ago

I did exactly what you did, it did not work on the other version. But 0.12 as it seems, works just fine now. Thank you!