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

hello monks,i have writen a code for a udp client,it just sends a packet to the server. the problem is that i have to press Enter/return two times to get the packet on the other side.and one more question, if we have data more than MSS of UDP packet which is 534 bytes, how do we send it? e.g. if the client requests a file, how do we send it back? any help is appreciated. the code of client:
#!/usr/bin/perl use IO::Socket; my $sock = &rdt_connect($ARGV[0],$ARGV[1]); $msg = "get $ARGV[2]"; $sendmsg = &rdt_send($msg); print length($sendmsg); &sendall($sock,$sendmsg); sub rdt_connect { #takes necessary parameters, creates socket and connects to that c +lient. my ($serverconnect,$portconnect) = @_; $proto = 'udp'; $socket = IO::Socket::INET->new (PeerAddr=>$_[0],PeerPort=>$_[1],P +roto=>'udp') or die "Can't Connect $!"; return $socket; } sub rdt_send{ #makes packet and sends it to the socket. my $datatosend = @_; $lengthpayload = length($_[0]); $r = 'R';$d='D';$t='T';$one=1;$point = '.';$zero=0;$null1=00000000 +;$null2=00000000;$null3=00000000;$null4=00000000;$null5=00000000;$nul +l6=00000000;$null7=00000000; $protocol = pack("a"x6,$r,$d,$t,$one,$point,$zero); $packetheader = pack('N3 n N3 n',$null1,$null2,$null3,$lengthpaylo +ad,$null4,$null5,$null6,$null7); #$packetpayload = $packetheader.$datatosend; $packetpayload = pack('a*',$_[0]); $tobuffer = ($protocol.$packetheader.$packetpayload); return $tobuffer; } sub sendall{ my ($socket,$packet) = @_; if ($packet ne ''){$_[0]->send($_[1]) or die "Send error: $!\n";} }
and the server code

#!/usr/bin/perl -w use IO::Socket; ($server,$port1) = &rdt_listen($ARGV[0]); print"LISTENING ON PORT $port1\n"; $serverhasdata = &select($server); ($thehost,$request) = &rcv_from($serverhasdata); $thedata = &statmachine_send($request); @payloadwoh = &statemachine_rcv($thedata); @payld = &rdt_recv(@payloadwoh); @payloadwoh = split(/\t/,$line); print"u have got a request from:$thehost and the request is:@paylo +adwoh\n\n"; sub rdt_listen{ #takes necessary parameters creates a socket and listens on that p +ort. my $port1 = $_[0]; $protocol = 'udp'; $socket1 = IO::Socket::INET->new(LocalPort=>$port1,Proto=>$protoc +ol)or die "Cannot Listen On The Socket $@"; return $socket1,$port1; } sub select{ #it selects the socket(socket is given as a parameter) and receive +s data from that socket my ($rcvsocket) = @_; $_[0]->recv($buf,534); if ( length($buf) != 0 ){ return $_[0]; } } sub rcv_from{ #takes data from the socket which is selected by the select functi +on my $sock = @_; while($_[0]->recv($msg, 534)){ my($port, $ipaddr) = sockaddr_in($_[0]->peername); $hishost = gethostbyaddr($ipaddr,AF_INET); return ($hishost,$msg); } } sub statmachine_send { #takes data from rcv_from and returns it my $comingdata = @_; return $_[0]; } sub statemachine_rcv { #it takes the packet from the statmachine_send function; my $packet = @_; #unpack the packet my($r,$d,$t,$one,$point,$zero,$null1,$null2,$null3,$lengthpayload, +$null4,$null5,$null6,$null7) = unpack('a3 C3 N3 n N3 n',$_[0]); $lengthpayload1 = $lengthpayload; @payload = unpack('a*',substr($_[0],34,$lengthpayload1+34)); #check if payload contains data or its empty if ( length(@payload) != 0){ return @payload; }else { return ;} } sub rdt_recv{ #it reads data from recive buffer. my @read = $_[0]; while (@read){ return "$_[0]"; } }

Replies are listed 'Best First'.
Re: Sending problem in UDP
by gone2015 (Deacon) on Dec 05, 2008 at 10:15 UTC

    With UDP what you see is what you get -- you can launch a packet towards its destination, but that's as far as it goes. The network will do its best to deliver, but it offers no guarantee of success, and cannot tell whether it succeeded or not.

    If you want to send more than one packet's worth of data, you'll have to wrap each fragment of data in something to tell the other end which part of the data each packet contains -- so the receiver can tell if any fragment goes missing. If you want to know the data has arrived, you'll need to get the receiver to send packet(s) back, telling you how it is for them (consider what happens if those packets do not arrive). From that information, you might be able to deduce that some packets need to be resent. There's a bit of a special case to deal with when you've sent all the data. Alternatively, if you are confident that UDP packets will be delivered, you could get the client to repeat the entire request when it finds a packet has gone astray. (Don't forget to deal with the case of packets being delayed in the network and turning up at the receiver some time later; in particular in the middle of a different request/response cycle.)

    Or you could use TCP. The obvious model here is DNS. Most DNS requests are dealt with using UDP. The client gets to repeat the request if it doesn't hear a response in some reasonable time, and there's a mechanism to detect multiple responses rolling up (the server does not attempt to care -- a request arrives, a response is sent, job done). If the response is too big for a single UDP packet (of minimum size), the server says so -- it's up to the client to repeat the request, but using TCP.

    I recommend Stevens.

Re: Sending problem in UDP
by quester (Vicar) on Dec 05, 2008 at 08:06 UTC
    It works for me without pressing return twice. This is under Fedora 9 Linux:
    $ perl -w rdt.pl 10.1.2.3 12345 abc Name "main::proto" used only once: possible typo at rdt.pl line 15.

    In a separate session:
    # tshark Capturing on eth0 0.000000 nnn.nnn.nnn.nnn -> 10.1.2.3 UDP Source port: 51531 Des +tination port: 12345

    Update: if the problem is somewhere in your Perl script, you could single step through your code in the perl debugger to find where it's hanging. On the other hand, I would suspect that you might be running it from a script that waits for a line of input from the user, for example with the bash read command.

Re: Sending problem in UDP
by zwon (Abbot) on Dec 05, 2008 at 18:58 UTC

    Size of UDP datagram is limited by the size of IP datagram (65535 bytes), but some system limit it even more, usually 8k. If size of resulting IP datagram more than MTU size it will be fragmented. If you plan to send file using UDP you should split into chunks and send as sequence of UDP packets, note that you should include some information into UDP packets which allow you to check that all packets are received and their order is right. But probably TCP is your choice. If you still wanna use UDP, took a look onto TFTP specification RFC 1350.

    Stevens mentioned in the above post is great.