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

Well, I cant figure out how to get a line into a variable from a socket, and do some checking on it. Its this piece of code iam troubled with:
print $client "username:"; $login=<$client>; print $login;
Ignore the last code, since I first have to figure out this line to fix the others :) I need the user to type down a username, and put it in the variable $login. Then the script does some checking on it. Doesnt seem to work though.. :( This is the entire script as it is now :
#!/bin/perl use IO::Socket; use IO::Select; $nconnections_new = 0; $login = ""; $maxconn = SOMAXONN; $local=IO::Socket::INET->new(Proto=>"tcp", LocalPort=>"1234", Listen=> +$maxconn, Reuse=>1) or die "Can't open socket\n"; while ($client = $local->accept) { $client->autoflush(1); &start; sub start { print $client "This is a test BBS!\n\r"; print $client "(C)reate new user (L)ogin"; print $client "\n\r"; $msg = ""; while ( <$client>) { next unless /\S/; if (/c|C/i) { print $client "<<<Create new user>>>\n\r"; print $client "Login must be at least 6 characters.\n\r"; &login; } elsif (/l|L/i) { &logon; } } sub login { print $client "username:"; $login=<$client>; print $login; chop $login; if ($login eq "") { print $client "Must enter a username!\n\r"; &login; } open (FILE1, "users.txt") || print "Error occured while opening file"; while (<FILE1>) { ($first, $second ) = split /:/; if ($login eq $first) { do { print $client "Sorry this username has been taken, try again!\n\r"; &login; } while ($login eq $first); } } if (length($login) > 6) { print $client "Your username was longer than 6 characters!\n\r"; &login; } close (FILE1); $pass = password(); sub password { print $client "Password:"; $password=<STDIN>; chop $password; print $client "\n\rRe-enter password:"; $password2=<STDIN>; chop $password2; if ($password ne $password2) { print $client "Passwords do not match, try again!"; &password; } return $password; } open (FILE, ">>users.txt") || print "Error occured while opening file" +; print FILE "$login:$pass\n"; close (FILE); print "File written..\n\r"; exit; } } sub logon { print $client "test"; } close $client; }

Replies are listed 'Best First'.
Re: Cant get user input from sockets into variables.
by wog (Curate) on Sep 22, 2001 at 17:18 UTC
    Your problem has to do with newline terminators. The telnet protocol requires that you use CRLF for newlines in both directions, and thus attempting to read a line until a \n (update: the default) will not work, because there will be an extra character (either at the beginning or end, depending on your platform). To fix this you can set $/ to \x0A\x0D (or \012\015 if you prefer, or you may import it from the Socket module with use Socket qw(:crlf) and then use $CRLF for this) so that <$filehandle> will read until CRLF, and so that you can use chomp to take it off the end of the string.

    Also note that you should not output \n\r to end lines, because the value of the \n and \r is not portable across platforms. On Windows and UNIX perl it corresponds to NL and CR respectively, but on MacPerl it corresponds to CR and NL respectively. Best off using $CRLF from Socket for clarity, or just enter the hex or octal escapes.

    And please use strict and warnings.

Re: Cant get user input from sockets into variables.
by alien_life_form (Pilgrim) on Sep 22, 2001 at 18:17 UTC
    Greetings.
    If you described what and how does not work, it would be helpful.
    But from the looks of it, I'd call binmode() on all the filehandles, then remove lone <CR>, <NL>, or <CR><NL> pairs (it' is \r\n, not the other way around, by the way).

    I'd also like to point out that the telnet protocol - accused in the comment of another monk - is completely innocent and quite different from what is going on here :). It is nevertheless true that EOL terminators on the network are tricky to get right... I believe that there is a good discussion of them in the docs, (perlipc ?)

    Cheers,
    alf

      The telnet standard says that LF should be considered to move the printer to the next line in the same horizontal position and that CR should be considered to move the printer to beginning of the current line, and that...
      the sequence "CR LF" must be treated as a single "new line" character and used whenever their combined action is intended
      Implying that CR LF is going to be the only newline sequence you will recieve in a telnet stream which is presumably being used here. So there is no need to check for just CR or LF/NL.

      Also, note that \r\n is not portable between platforms -- \n and \r are swapped on Macs (because CR is used to terminate lines on Macs, not LF/NL.)