Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask

Very Basic Perl Question about Sockets .. and IRC

by Contraversy (Initiate)
on Nov 06, 2012 at 00:08 UTC ( #1002402=perlquestion: print w/replies, xml ) Need Help??
Contraversy has asked for the wisdom of the Perl Monks concerning the following question:

Ok, I hope I am asking this in the correct place. I have a simple IRC Client that I want to make, there are a plethora of code snippets online for this. And I have 1/2 of a working client. It connects, responds to the PING requests and can even auto reply to any commands I want it to recognize and reply to. But my problem is, I don't want a bot that idles or auto-replies. I want a basic, bare-bones client that can send messages as well as receive them. If I try to add a loop/command to send a message it stops the entire loop and waits for me to input. I tried this in C++ using a non-blocking input command and still couldn't send any information. My Main Question, do I have to open an extra socket? Simply for sending messages that I input?
#!/usr/local/bin/perl -w # # A simple IRC robot. # Usage: perl use strict; # We will use a raw socket to connect to the IRC server. use IO::Socket; # The server to connect to and our details. my $server = ""; my $nick = "opti__"; my $login = "opti__"; # The channel which the bot will join. my $channel = "#contraversy"; # Connect to the IRC server. my $sock = new IO::Socket::INET(PeerAddr => $server, PeerPort => 6667, Proto => 'tcp') or die "Can't connect\n"; # Log on to the server. print $sock "NICK $nick\r\n"; print $sock "USER $login 8 * :contraIRC\r\n"; # Read lines from the server until it tells us we have connected. while (my $input = <$sock>) { # Check the numerical responses from the server. if ($input =~ /004/) { # We are now logged in. last; } elsif ($input =~ /433/) { die "Nickname is already in use."; } } # Join the channel. print $sock "JOIN $channel\r\n"; # Keep reading lines from the server. while (my $input = <$sock>) { chop $input; if ($input =~ /^PING(.*)$/i) { # We must respond to PINGs to avoid being disconnected. print $sock "PONG $1\r\n"; } else { # Print the raw line received by the bot. print "$input\n"; } }
PS if you run this and try to send a message its in the RFC format "PRIVMSG #channelornick :message here \r\n" <-- The CRLF is required also. Any help will be appreciated! Thanks!

Replies are listed 'Best First'.
Re: Very Basic Perl Question about IRC
by Tanktalus (Canon) on Nov 06, 2012 at 01:48 UTC

    There are a few approaches available here. The most obvious might be to use threads - one thread that would read from the socket (blocking), a second thread to write to the socket (blocks on the input queue used to feed it stuff to send), and a third to read from stdin (perhaps using Term::ReadLine). I'm not sure if that middle thread is quite needed, though it would handle race conditions between the first and last threads for sending stuff to the IRC server.

    Personally, I do this basic type of thing with a single thread using event-based code, usually AnyEvent/Coro, though some will swear by POE. And, with a new enough Term::ReadLine, you can integrate it with Coro fairly well, or other event loops not quite so well, but still passably if done with Term::ReadLine being your main event loop (see Term::ReadLine::Event for example code), though there's always the issue of spitting stuff to the screen (input from IRC server) while waiting at a prompt.

    That's for "this basic type of thing." For this specific type of thing (IRC), I use Xchat and perl plugins to Xchat.

      Thank you so much, more than enough info here to do what I need!
Re: Very Basic Perl Question about Sockets .. and IRC
by zentara (Archbishop) on Nov 06, 2012 at 10:47 UTC
    I want a basic, bare-bones client that can send messages as well as receive them.

    Try this basic forking client code.

    #!/usr/bin/perl -w use strict; use IO::Socket; my ( $host, $port, $kidpid, $handle, $line ); ( $host, $port ) = ('localhost',1200); my $name = shift || ''; if($name eq ''){print "What's your name?\n"} chomp ($name = <>); # create a tcp connection to the specified host and port $handle = IO::Socket::INET->new( Proto => "tcp", PeerAddr => $host, PeerPort => $port ) or die "can't connect to port $port on $host: $!"; $handle->autoflush(1); # so output gets there right away print STDERR "[Connected to $host:$port]\n"; # split the program into two processes, identical twins die "can't fork: $!" unless defined( $kidpid = fork() ); # the if{} block runs only in the parent process if ($kidpid) { # copy the socket to standard output while ( defined( $line = <$handle> ) ) { print STDOUT $line; } kill( "TERM", $kidpid ); # send SIGTERM to child } # the else{} block runs only in the child process else { # copy standard input to the socket while ( defined( $line = <STDIN> ) ) { print $handle "$name->$line"; } }

    I'm not really a human, but I play one on earth.
    Old Perl Programmer Haiku ................... flash japh
Re: Very Basic Perl Question about IRC
by Anonymous Monk on Nov 06, 2012 at 01:40 UTC

    My Main Question, do I have to open an extra socket? Simply for sending messages that I input?

    What does the RFC say?

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1002402]
Approved by muba
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others lurking in the Monastery: (6)
As of 2017-06-26 06:30 GMT
Find Nodes?
    Voting Booth?
    How many monitors do you use while coding?

    Results (572 votes). Check out past polls.