problem with IO::Socket TCP connection - perl

I am trying to write a simple IO::Socket connection in perl. However, I am running into some problems. Here is the code on the server side:
my $listener =
IO::Socket::INET->new( LocalPort => 8000, Listen => 1, Reuse => 1 );
die "Can't create socket for listening: $!" unless $listener;
print "Listening for connections on port 8000\n";
while(1) {
while ($client = $listener->accept()) {
while ( <$client>) {
my #arguments = split(/ /, $_ );
my $result = "something" ;# here we do something in my code
warn $result;
print $client $result;
close $client;
}
}
}
And the client code:
use IO::Socket;
my $sock = new IO::Socket::INET (
PeerAddr => 'xx.xxx.xxx.xxx',
PeerPort => '8000',
Proto => 'tcp',
);
die "Could not create socket: $!\n" unless $sock;
$sock->autoflush(1);
print $sock "somethin something";
print "sent\n";
while ( <$sock> ) { print }
close $sock;
My problem now is that the data seems to be only sent from the client to teh sever when I close the client Perl program. I get the "sent" message on the client side, but the "something" message on the server side does not appear until after I have manually closed the client side.
Also, I want to get the server response. Thus far, since I have to close the script manually, the response does not et to the client side.
Can anyone help?

while ( <$sock> ) -- waits for a line. That is for a string, ended by "\n" character.
You must add "\n" to strings, or use 'read' function instead.

Related

Programming a chat room in perl, I'm having issues with the client?

I'm following this guide explaining how to do a server using IO::Async but I'm having issues with my client code. I have it where I send first then receive. This makes me press enter on each client before receiving any data. I figured I'd have to listen till I wanted to type something but I'm not really sure how. Below is my current client code.
use IO::Socket::INET;
# auto-flush on socket
$| = 1;
# create a connecting socket
my $socket = new IO::Socket::INET (
PeerHost => 'localhost',
PeerPort => '12345',
Proto => 'tcp',
);
die "cannot connect to the server $!\n" unless $socket;
print "My chat room client. Version One.\n";
while (1) {
my $data = <STDIN>;
$socket->send($data);
my $response = "";
$socket->recv($response, 1024);
print ">$response";
last if (index($data, "logout") == 0);
}
$socket->close();
I actually had this problem myself a few weeks ago when trying to make a client/server chat for fun.
Put it off until now.
The answer to your problem of having to hit enter to receive data, is that you need to use threads. But even if you use threads, if you do $socket->recv(my $data, 1024) you won't be able to write anything on the command line.
This isn't using your code, but here is my solution after banging my head against a wall for the last 24hrs. I wanted to add this as an answer, because though the question is out there on stackoverflow, none of the answers seemed to show how to use IO::Select.
Here is the server.pl script, it does not use threading:
#!/usr/bin/perl
use strict;
use warnings;
use IO::Socket::INET;
use IO::Select;
$| = 1;
my $serv = IO::Socket::INET->new(
LocalAddr => '0.0.0.0',
LocalPort => '5000',
Reuse => 1,
Listen => 1,
);
$serv or die "$!";
print 'server up...';
my $sel = IO::Select->new($serv); #initializing IO::Select with an IO::Handle / Socket
print "\nAwaiting Connections\n";
#can_read ( [ TIMEOUT ] )
#can_write ( [ TIMEOUT ] )
#add ( HANDLES )
#http://perldoc.perl.org/IO/Select.html
while(1){
if(my #ready = $sel->can_read(0)){ #polls the IO::Select object for IO::Handles / Sockets that can be read from
while(my $sock = shift(#ready)){
if($sock == $serv){
my $client = $sock->accept();
my $paddr = $client->peeraddr();
my $pport = $client->peerport();
print "New connection from $paddr on $pport";
$sel->add($client); #Adds new IO::Handle /Socket to IO::Select, so that it can be polled
#for read/writability with can_read and can_write
}
else{
$sock->recv(my $data, 1024) or die "$!";
if($data){
for my $clients ($sel->can_write(0)){
if($clients == $serv){next}
print $clients $data;
}
}
}
}
}
}
And the client.pl, which uses threads:
#!/usr/bin/perl
use strict;
use warnings;
use IO::Socket::INET;
use threads;
use IO::Select;
$| = 1;
my $sock = IO::Socket::INET->new("localhost:5000");
$sock or die "$!";
my $sel = IO::Select->new($sock);
print "Connected to Socket ". $sock->peeraddr().":" . $sock->peerport() . "\n";
#This creates a thread that will be used to take info from STDIN and send it out
#through the socket.
threads->create(
sub {
while(1){
my $line = <>;
chomp($line);
for my $out (my #ready = $sel->can_write(0)){
print $out $line;
}
}
}
);
while(1){
if(my #ready = $sel->can_read(0)){
for my $sock(#ready){
$sock->recv(my $data, 1024) or die $!;
print "$data\n" if $data;
}
}
}
There is one other problem that arises though, when the client receives data and prints it to the console, your cursor goes to a new line, leaving behind any characters you had typed.
Hope this helps and answers your question.
For a simple "just send from STDIN, receive to STDOUT" client, you could use any of telnet, nc or socat. These will be simple enough to use for testing.
$ telnet localhost 12345
$ nc localhost 12345
$ socat stdio tcp:localhost:12345
If you actually want to write something in Perl, because you want to use it as an initial base to start a better client from, you probably want to base that on IO::Async. You could then use the netcat-like example here. That will give you a client that looks-and-feels a lot like a simple netcat.
I am guessing you need to set the MSG_DONTWAIT flag on your recv call, and print the response only if it is non-null.
$socket->recv($response, 1024, MSG_DONTWAIT);
print ">$response" if ($response ne "");

Not able to send data to remote TCP port using Socket programming in Perl

My Procedure: i am opening a file "output.txt , readin gits last line which will have the String "PASS" or "FAIL" , if PASS if found then i want to send string "OK" to server else i have to send string "ERROR"
Issue Observed: I am not able to recieve anything on Remote Server(IP 10.5.62.1) but if try using Localhost (IP 127.0.0.1) , i am able receive the string from the client. Please help to receive the string on the remote server.
I am getting the following error
:send: Cannot determine peer address at C:\client.pl line 44
IO::Socket::send('IO::Socket::INET=GLOB(0x31cc20)', 'ERROR') called at
C:\client.pl line 44
client code :
#standard includes
use strict;
use warnings;
use diagnostics;
use IO::Socket::INET;
use IO::File;
use English;
#local variables
my $Socket;
#Create Socket for a specified port number
$Socket = new IO::Socket::INET (
PeerAddr => '10.5.62.1',
PeerPort => '4754',
Proto => 'tcp',
Listen => 1,
);
die "Could not create socket: $!\n" unless $Socket;
#open the file which is required , mapping file to INPUT Macro
open INPUT, "<output.txt";
#Reading all lines from a file and storing in #lines array
my #lines = <INPUT>;
close INPUT;
#Now #lines holds all the lines, one line in each element.
print "Last line is:\n";
#checking the last line in the file as it will have the verdict "Pass" or "Fail"
print $lines[-1];
if($lines[-1]=~ 'Pass')
{
print "Setting verdict PASS and sending OK";
#Sending Ok to Server on Ping Success
# print $Socket "\r\nOK\r\n";
$Socket->send("\r\nOK\r\n");
}
else
{
print "Setting verdict FAIL and sending ERROR";
#Sending ERROR to Server on failure
# print $Socket "\r\nERROR\r\n";
$Socket->send("ERROR");
}
#Now closing the socket as my job is done
close($Socket);
Server Code:
use IO::Socket;
my $sock = new IO::Socket::INET (
LocalHost => '10.5.62.1',
LocalPort => '4754',
Proto => 'tcp',
Listen => 1,
Reuse => 1,
);
die "Could not create socket: $!\n" unless $sock;
my $new_sock = $sock->accept();
while(<$new_sock>) {
print $_;
}
close($sock);

use IO::Socket::IP ??? how to make a client in perl Ipv6

I have been trying to find a simple client ipv6 script
that would work with Evens server script , of course I
dont know what Im doing, so all I can do is rewrite someone
else's work until I know what Im doing ...
so here is a server script that works on Microsoft widows server
use IO::Socket::IP -register;
my $sock = IO::Socket->new(
Domain => PF_INET6,
LocalHost => "::1",
Listen => 1,
) or die "Cannot create socket - $#\n";
print "Created a socket of type " . ref($sock) . "\n";
{
$in = <STDIN>;
print $in->$sock;
redo }
of course the $in->$sock is not working, cause I dont know how to send
data using just $sock ???
so I need to know how to send information properly and
what I need is A client script to connect to the above script
using the ipv6 protocol
can anyone help with this ???
I would like to be able to send information from one
perl program to another perl program using this
being able to send information back and forth would
be Ideal ...
Thanks in advance
-Mark
That's a server socket (Listen => 1), so you have to accept a connection.
use IO::Socket::IP -register;
my $listen_sock = IO::Socket::IP->new(
LocalHost => "::1", # bind()
Listen => 1, # listen()
) or die "Cannot create socket - $#\n";
print("Listening to ".$listen_sock->sockhost()." "
.$listen_sock->sockport()."\n");
while (1) {
my $sock = $listen_sock->accept()
or die $!;
print("Connection received from ".$sock->peerhost()." "
.$sock->peerport()."\n");
while (<$sock>) {
print $sock "echo: $_";
}
}
A client:
use IO::Socket::IP -register;
#ARGV == 2 or die("usage");
my ($host, $port) = #ARGV;
my $sock = IO::Socket::IP->new(
PeerHost => $host, # \ bind()
PeerPort => $port, # /
) or die "Cannot create socket - $#\n";
print $sock "Hello, world!\n";
$sock->shutdown(1); # Done writing.
print while <$sock>;
The comments indicate the underlying system call used to perform the action.

Error in perl chat server

I'm trying to create a chat server using sockets in Perl. However, when I run the Server program I get the error:
"ERROR:(9)(Bad file descriptor)(6)(+The handle is invalid) at Server.pl line 21."
and when I run the client program I get the error:
"Cannot create the socket: No connection could be made because the target machine
actively refused it."
Here is the Server program:
#!usr/bin/perl
#server.pl
use IO::Socket;
$| = 1;
print "Server Program\n";
my $lp = 12000;
my $server_socket, $new_client, $addr, $port;
$server_socket = new IO::Socket::INET (
LocalHost => '127.0.0.1',
LocalPort => $lp,
Proto => 'tcp',
Reuse => 1) or die "Cannot create the socket: $!\n";
print "Server started at port $lp \n";
while (1) {
$new_client = $server_socket->accept() or die sprintf "ERROR:(%d)(%s)(%d)(+%s)", $!,$!,$^E,$^E;
$addr = $new_client->peerhost();
$port = $new_client->peerport();
print "Connected to client at $addr at port $port ";
while(<$new_client>) {
print "Following is the text entered by client: \n";
print "$_";
}
print "Client now disconnecting..\n";
close $new_client;
}
$server_socker->close();
And here is the client:
#!usr/bin/perl
#client.pl
use IO::Socket;
$| = 1;
print "Client Program\n";
my $lp = 12000;
my $client_socket = new IO::Socket::INET (
PeerHost => '127.0.0.1',
PeerPort => $lp,
Proto => 'tcp',
Reuse => 1) or die "Cannot create the socket: $!\n";
print "Server connected at port $lp \n";
print "Enter the text to sent to the server: \n";
$user_input = <>;
chomp $user_input;
print $plient_socket;
$client_socket->send($user_input);
$client_socket->close();
I am new to this and I'm not getting where I'm going wrong. Could anybody help?
You trying to accept a connection from a socket that's not listening. Add
Listen => SOMAXCONN,
And now for off-topic comments about your code:
Always use use strict; use warnings;. It will highlight some other problems with your code.
It doesn't make any sense to relative paths on the shebang line. You're missing a /.
On the style front, it's considered bad form to declare variables ahead of where they are used. The whole point of declaring variables is to limit their scope, so declaring them at the top of the program defies the purpose.
LocalHost => '127.0.0.1' (better written as LocalHost => INADDR_LOOPBACK) makes it so you can only receive connections from 127.0.0.1. That can be useful, but I don't know if you did that intentionally. The default, INADDR_ANY, allows connections from any interface.

how to parse request URL in simple server in Perl which listen to port

here is the request URL http://localhost:9009/?comd&user=kkc&mail=kkc#kkc.com
what are the modification need to do in the server perl script.
server-Perl-script
use IO::Socket;
use Net::hostent; # for OO version of gethostbyaddr
$PORT = 9009; # pick something not in use
$server = IO::Socket::INET->new( Proto => 'tcp',
LocalPort => $PORT,
Listen => SOMAXCONN,
Reuse => 1);
die "can't setup server" unless $server;
print "[Server $0 accepting clients]\n";
while ($client = $server->accept())
{
$client->autoflush(1);
print $client "Welcome to $0; type help for command list.\n";
$hostinfo = gethostbyaddr($client->peeraddr);
printf "[Connect from %s]\n", $hostinfo ? $hostinfo->name : $client->peerhost;
print $client "Command? ";
while ( <$client>) {
next unless /\S/; # blank line
if (/comd/i ) { print $client `dir`; }
} continue {
print $client "Command? ";
}
close $client;
print "client closed";
}
I assume that your script is not for production, but for homework or testing sometime. There are multiple very efficient web server solutions in/with Perl like Apache with CGIs or mod_perl, HTTP::Server::Simple and PSGI/Plack.
You'll also typically use a framework like Dancer, Mojo or Catalyst which does most of the boring standard stuff for you:
use Dancer;
get '/' => sub {
return 'Hi there, you just visited host '.request->host.
' at port '.request->port.' asking for '.request->uri;
};
Back to your question: Your script is a interactive server while HTTP has a strict request and response structure:
Client connects to server
Client sends a request
Server sends a response
You need to remove the interactive part and just wait for the client to start the conversation:
use IO::Socket;
use Net::hostent; # for OO version of gethostbyaddr
$PORT = 9009; # pick something not in use
$server = IO::Socket::INET->new( Proto => 'tcp',
LocalPort => $PORT,
Listen => SOMAXCONN,
Reuse => 1);
die "can't setup server" unless $server;
print "[Server $0 accepting clients]\n";
while ($client = $server->accept())
{
$hostinfo = gethostbyaddr($client->peeraddr);
# Read request up to a empty line
my $request;
while ( <$client>) {
last unless /\S/;
$request .= $_;
}
# Do something with the request
# Send response
print $client "Status: 200 OK\r\nContent-type: text/plain\r\n\r\n".$request;
close $client;
print "client closed";
}
The server reads the full request from the client and returns a minimized HTTP header plus the original request.