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

Hi all, I'm trying to write a simple UDP server starting with the following code:
use IO::Socket; my $server = IO::Socket::INET->new( Listen => 5, LocalAddr => 'localhost', LocalPort => 2224, Proto => 'udp', Reuse => 1 ) or die "Can't create server socket: $!"; while (my $client = $server->accept()) { while (<$client>) { print $_; } }
When I try to run this code I get: Can't create server socket: Operation not supported at ./test.pl line 7.
Can anyone tell me what I'm doing wrong?

Replies are listed 'Best First'.
(jcwren) RE: UDP server
by jcwren (Prior) on Jul 11, 2000 at 21:29 UTC
    Stolen from Perl Cookbook, Chapter 17

    Problem

    You want to write a UDP server.

    Solution

    First bind to the port the server is to be contacted on. With IO::Socket, this is easily accomplished:
    use IO::Socket; $server = IO::Socket::INET->new(LocalPort => $server_port, Proto => "udp") or die "Couldn't be a udp server on port $server_port : $@\n";
    Then, go into a loop receiving messages:
    while ($him = $server->recv($datagram, $MAX_TO_READ, $flags)) { # do something }
    I haven't written anything that runs as a UDP server. It's all been TCP with what I've done. This may help. I'd recommend taking a look at this whole chapter, if you can.

    --Chris

    e-mail jcwren
      Awesome! Thanks a lot, that did exactly what I needed it to do. /me runs out to purchase Perl Cookbook.
(jcwren) Re: UDP server
by jcwren (Prior) on Jul 11, 2000 at 19:39 UTC
    You can't set a Listen size when using UDP. It works fine if you use either a TCP protocol, or use UDP and remove the Listen parameter.

    --Chris

    e-mail jcwren
      Darn, so I guess you can't write a UDP server with IO::Socket because the Listen parameter is what switches it into server mode, right? I think I'm going to have to use the plain Socket module. :(
Re: UDP server
by ahunter (Monk) on Jul 11, 2000 at 21:39 UTC
    What's more, accept is meaningless in the context of a UDP socket (it's packet-based, not connection-based). You never receive a connect request on a UDP socket...

    All you need to do to make a UDP socket is bind it to the appropriate port, and sysread the packets from it. Maximum packet size is 64k or the size you specify to sysread, whichever is smaller. Untested, but try this:

    use strict; use IO::Socket; my $socket=IO::Socket::INET->new(LocalAddr => 'localhost', LocalPort => 2224, Proto => 'udp') or die "socket: $!"; while ((my $length=sysread($socket, my $buffer, 65536)) != 0) { die "sysread: $!" if (!defined($length)); # $buffer contains the received packet }
    From perusing the IO::Socket code, it looks like it'll do the right thing.

    To send a packet, use this (NOTE: this uses the perl 5.6.0 form of syswrite. In previous versions, you need to supply a length argument):

    use strict; use IO::Socket; my $socket=IO::Socket::INET->new(PeerAddr => 'localhost', PeerPort => 2224, Proto => 'udp') or die "socket: $!"; syswrite($socket, "Hello, there\n");

    Andrew.

    Update: Oops, should have mentioned this, but use recv instead of sysread if you want to know the source of your packets ;-) (sysread still works, though)

    Update II: I'm really not on form - the while (sysread) stuff in the first example is probably bad perl - if sysread returns undef, you'll get a warning, *and* the die condition will be skipped. D'oh. Try this instead:

    my $length; while (defined($length=sysread($socket, my $buffer, 65536)) && $length + != 0) { ... } die "sysread: $!" if (!defined($length));
    This shouldn't warn due to the short-circuit nature of &&...
Re: UDP server
by tye (Sage) on Jul 23, 2000 at 23:51 UTC

    Please don't set a LocalAddr. This is a classic mistake. Perhaps this isn't true on all systems, but on most systems I've run into, setting the LocalAddr will prevent packets from getting to you unless the client used that address to try to reach you. So a LocalAddr of 'localhost' means that you won't receive any packets unless they came from the machine that you run the server on (because that is the only source from which packets addressed to 'localhost' could reach the server). Leave the LocalAddr off and it will default to match any local address which is almost always what you want for a server.