Beefy Boxes and Bandwidth Generously Provided by pair Networks
Welcome to the Monastery
 
PerlMonks  

Net::IRC and IO::Socket

by Anonymous Monk
on Jun 20, 2001 at 09:42 UTC ( [id://89924]=perlquestion: print w/replies, xml ) Need Help??

Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

I am setting up a script to act as a "middle-man" between an IRC "front end" and another Perl script. (I may eventually merge the two together if I get it working, but thats not the point.)

Basically, I'd like to send packets (UDP; IO::Socket) to a script that parses the packet and relays relevant information to a channel on IRC. I do not have a problem with using Net::IRC by itself, and I do not have a problem with IO::Socket by itself. Maybe I'm being ignorant, but I really have no idea how to put the two together. To watch the chat room and for incoming packets.

$irc->start; while ($socket->recv(my $in, 1024) ) { .. }

Both seem to "monopolize" the program. Can two "monopolistic" processes share? After thinking that, I immediately think of fork, but am still unsure of how to implement it.

Any help you monks could offer would be greatly appreciated. Thanks

Replies are listed 'Best First'.
Re: Net::IRC and IO::Socket
by btrott (Parson) on Jun 20, 2001 at 10:03 UTC
    Two "monopolistic" processes can share, and that sharing is done through the use of select; select is used to wait on a set of sockets, and to pass control back to you when at least one of those handles is "ready". However "ready" is defined: for example, you may be waiting for the socket to be have data that can be read from it; or you could be waiting for the socket to be ready for writing, etc.

    In this case, it's slightly tricky, because you want to intermix a socket "contained" by Net::IRC and one that you're using in your own application. After a look at the Net::IRC docs, it looks like you might be able to use the 'addfh' method to add your UDP socket handle to the list of handles in the select loop that is entered when you call the 'start' method.

    When you use 'addfh', it looks like you give Net::IRC a filehandle, a callback function to call when the handle is "ready", and a flag saying what kind of handle this is (reading/writing/error).

    So, in other words, you might do something like this (note: untested)--

    $irc->addfh($socket, \&has_data, "r"); $irc->start; sub has_data { my $socket = shift; $socket->recv(my $data, 1024); ## Now trigger some Net::IRC event based on $data }
    Note that you may need to investigate the exact args that get passed to your callback function; I'm not sure if the filehandle is the only thing passed. Note also that you'll need to get the Net::IRC object somehow, I believe, in order to send an event based on $data; one way to do this would be to create the callback function as a closure.
Re: Net::IRC and IO::Socket
by jbert (Priest) on Jun 20, 2001 at 12:26 UTC

    I agree that 'select' is the traditional (and fastest and probably best etc) way to do this, but I fancy talking about this a bit (to put my own thoughts straight if nothing else).

    You are writing a case of an application which would like to do I/O on more than one source at a time. I/O is slow (compared to almost everything else) and so the normal interface the operating system offers you is that when you request some I/O it puts your process to sleep until the I/O completes. (This is called 'blocking' I/O). It doesn't matter whether you are doing a read or write from a file or a socket or whatever (OK - so there are special cases, but we mostly care about these ones). The reason it does this is to more efficiently share resources amongst many processes on one system.

    In your case (and in many other important cases, e.g. many network server applications) you want to get on with doing other things whilst your I/O chugs away, but come back to your I/O whenever it needs care and attention (more data, or finish things off).

    You can generally ask for your read or write operations to be performed in a 'non-blocking' way, in which case they simply fail with an 'EAGAIN' error until the operating system has enough data to give you a chunk (read) or enough buffer space to accept a chunk from you (write).

    If you aren't careful the above leads you down the road of the 'busy loop' which is annoying. You can put in your own 'sleep' calls but since your program won't be woken up from the sleep when the operating system is ready for you to do I/O, you waste a bit of time (otherwise known as the all-important 'latency') before responding.

    The original Unix answer to this is 'select'. This allows your process to sleep for a (short or long) timeout until one of your file descriptors (your handle to some I/O) is ready for action. If you wake up from your timeout and there is no I/O to do, you can have a quick go at performing some other chores and then go back to your select. This is a "select loop".

    Another way of handling the situation is to use threads. These can raise strong passions in people both for and against but lets not go there right now. The problem of blocking operations was (I think) one of the major original rationals behind threads. The idea is that you can spawn a new thread to handle the blocking I/O whilst the rest of your program gets on with things. Only one thread is blocked (or 'monopolised') by the I/O and so everything is hunky dory.

    Well it obviously isn't that simple and adding threads gives you a new set of challenges, not least in perl where there are a significant number of 'gotchas', in theory if not in practice, to the use of threads. But you see how some people at least might like this programming paradigm.

    NB. Your idea of using 'fork' is related to this idea of using threads. Each non-blocking I/O stalls a 'thread of execution'. In the 'fork' model these are two processes, in the threading model they are two threads. In both cases the unpleasantness comes from how these two "threads of execution" share memory and avoid stomping on each other.

    Windows NT systems support 'select' but native Win32 implementations would do better to use 'WaitForMultipleObjects' (or whatever it is called) which is broadly similar but more in tune with the way NT does things.

    Also, 'select' has some problems scaling up to lots and lots of file descriptors and so a 'poll' call is supported by modern Unices. This is broadly similar to select (and doesn't do any 'polling' really, it does put you to sleep until activity occurs) but scales better to larger numbers of file descriptors.

    Lastly, on Linux (and I'm sure on other modern Unices) there are funky things like real time signals delivered when async I/O (another name for non-blocking I/O) completes.

    So, as has already been said, the simple answer to your question is 'select' (or 'fork' and some interprocess memory sharing or similar unpleasantness) - but you touch on an important area of interest to people doing high performance server work.

    Sorry for the rant. Some of the above interfaces will be easily acessible from perl some won't. I don't advise using the 'select' function call natively, instead use IO::Socket. Much easier.

    Bye.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://89924]
Approved by root
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others wandering the Monastery: (6)
As of 2024-03-29 11:57 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found