views:

339

answers:

4

I made an IRC bot which uses a while true loop to receive whatever is said.
To receive I use recv(500), but that stops the loop if there isn't anything to receive, but i need the loop to continue even if there isn't anything to receive.
I need a makeshift timer to continue running.

Example code:

/A lot of stuff/
timer=0
while 1:
    timer=timer+1
    line=s.recv(500) #If there is nothing to receive, the loop and thus the timer stop.
/A lot of stuff/

So either I need a way to stop it stopping the loop, or I need a better timer.

+1  A: 

This is going to prove a bad way to design a network application. I recommend looking into twisted, a networking library with an excellent implementation of the IRC protocol for making a client (like your bot) in twisted.words.protocols.irc.

http://www.habnabit.org/twistedex.html is an example of a very basic IRC bot written using twisted. With very little code, you are able to access a whole, correct, efficient, reconnecting implementation of IRC.

If you are intent on writing this from a socket level yourself, I still recommend studying a networking library like twisted to learn about how to effectively implement network apps. Your current technique will prove less effective than desired.

Mike Graham
I want to make the bot from scratch like I said before. Thanks anyway.
ImTooStupidForThis
You should reconsider that goal. That is not the best approach to make a good IRC bot nor is it the best approach to learn sockets.
Mike Graham
Why should it be a good irc bot?Its my first "real" python project.And I am doing it for fun. Solving problems that arise because I don't use libs is fun.
ImTooStupidForThis
I presumed you may have wanted it to be a good IRC bot because I know I personally do not like writing bad software (and left room for that not being your goal!). Further, I didn't insist you use twisted—I predicted before you said so that you might insist on using socket (a different library!) instead. What I really recommended against is your current approach to implementing it.
Mike Graham
A: 

You can settimeout on the socket so that the call returns promptly (with a suitable exception, so you'll need a try/except around it) if nothing's there -- a timeout of 0.1 seconds actually works better than non-blocking sockets in most conditions.

Alex Martelli
+1 not that bad an idea. I prefer select because it can be extended to multiple sockets, but a timeout on the socket is a fair solution to the OP question.
Heath Hunnicutt
You sir solved my problem.
ImTooStupidForThis
Alex Martelli
+1  A: 

I usually use irclib which takes care of this sort of detail for you.

Greg Hewgill
When I made the bot I decided I wanted to try to make it from "scratch".
ImTooStupidForThis
That's fair. Having said that, you could have a look at the `irclib` source, it's not too long and doesn't have such a complex framework as Twisted, so it's a good place to pick up ideas.
Greg Hewgill
@ImTooStupidForThis, implementing protocols at a socket level is hard and tedious if done right, which is one reason it is so seldom done right. If you have not studied other implementations of a protocol similar to IRC, you should really do so before trying to implement such a framework yourself.
Mike Graham
Im doing it for fun.
ImTooStupidForThis
+1  A: 

If you want to do this with low-level python, consider using the ready_sockets = select.select([s.fileno()], [], [], 0.1) -- this will test the socket s for readability. If your socket's file number is not returned in ready_sockets, then there is no data to read.

Be careful not to use the timout of "0" if you are going to call select repeatedly in a loop that does not otherwise yield the CPU -- that would consume 100% of the CPU as the loop executes. I gave 0.1 seconds timeout as an example; in this case, your timer variable would be counting tenths of a second.

Here's an example:

timer=0    
sockets_to_check = [s.fileno()]

while 1:
    ready_sockets = select.select(sockets_to_check, [], sockets_to_check, 0.1)
    if (len(ready_sockets[2]) > 0):
        # Handle socket error or closed connection here -- our socket appeared
        # in the 'exceptional sockets' return value so something has happened to 
        # it.
    elif (len(ready_sockets[0]) > 0):
        line = s.recv(500)
    else:
        timer=timer+1  # Note that timer is not incremented if the select did not
                       # incur a full 0.1 second delay.  Although we may have just
                       # waited for 0.09999 seconds without accounting for that.  If
                       # your timer must be perfect, you will need to implement it
                       # differently.  If it is used only for time-out testing, this 
                       # is fine.

Note that the above code takes advantage of the fact that your input lists contain only one socket. If you were to use this approach with multiple sockets, which select.select does support, the len(ready_sockets[x]) > 0 test would not reveal which socket is ready for reading or has an exception.

Heath Hunnicutt
Could you by any chance post some example code please?
ImTooStupidForThis
Thanks for the example but someone already helped me with something a bit simpler.Thanks a lot though.
ImTooStupidForThis
Yep, the "0.1 timeout" idea is indeed good (I suggest that on my answer too, albeit w/`settimeout`) -- nonblocking sockets, and equivalently 0-timeouts, can have bad performance impacts.
Alex Martelli
`if len(foo) > 0` is typically spelled `if foo`.
Mike Graham
@Mike Graham: Typically not by me. I guess it's a subjective comment.
Heath Hunnicutt
@ImTooStupidForThis: No worries. But you do owe both myself and Alex a +1 vote. Especially me, since I modified my answer for you, not as much him, since you already gave him a check mark.
Heath Hunnicutt