Keep open socket connection Perl - perl

I created a Perl script that open a new socket on my server.
When I connect with telnet to the socket and I write (and receive) something, the connection closes.
#!/usr/bin/perl
use strict;
use warnings;
use IO::Socket;
use IO::Socket::INET;
$| = 1;
my $sock = IO::Socket::INET->new(Listen => 5,
LocalAddr => 'localhost',
LocalPort => 9000,
Reuse => 1,
Proto => 'tcp');
die "Socket not created $!\n" unless $sock;
print "Server waiting for connections\n";
while(1)
{
# waiting for a new client connection
my $client_socket = $sock->accept();
# get information about a newly connected client
my $client_address = $client_socket->peerhost();
my $client_port = $client_socket->peerport();
print "Connection from $client_address:$client_port\n";
# read up to 1024 characters from the connected client
my $data = "";
$client_socket->recv($data, 1024);
chomp($data);
print "Data: $data\n";
# write response data to the connected client
my $dataok = "OK";
$client_socket->send("$dataok\n");
$client_socket->send("$data\n");
if($data == 500){
close($sock);
exit();
}
elsif($data eq "Close\r") {
close($sock);
exit();
}
}
My telnet session:
telnet localhost 9000
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
e //(Sent)
e //(Received)
Connection closed by foreign host.
Why does my script close the connection?
Thanks in advance

I added a loop in my code and it worked!
Thanks to #simbabque and #SteffenUllrich.
# waiting for a new client connection
my $client_socket = $sock->accept();
# get information about a newly connected client
my $client_address = $client_socket->peerhost();
my $client_port = $client_socket->peerport();
print "Connection from $client_address:$client_port\n";
# read up to 1024 characters from the connected client
while(1){
my $data = "";
$client_socket->recv($data, 1024);
chomp($data);
print "Data: $data\n";
# write response data to the connected client
my $dataok = "OK";
$client_socket->send("$dataok\n");
$client_socket->send("$data\n");
if($data == 500){
close($sock);
exit();
}
elsif($data eq "Close\r") {
close($sock);
exit();
}
}

Related

Established TCP connection but socket doesn't send/recv data

I'm writing a simple TCP client and server Perl script.
As of now I verify the 3 way TCP handshake using wireshark, and the connection is established.
But when i try to send or recv data nothing happens.
Questions:
1) the major difference between the client and the server is only that the server has an added LISTEN parameter which enables it to listen for incoming connections ?
2)Are there any steps missing between recv and displaying the data?
3)Shouldn't atleast the hardcoded string "$response" be sent when the program executes the while loop the first time?
4)How do shutdown($sock,1) and sleep(1) differ in this implementation? Is it okay to let the socket sleep or should I use shutdown($sock,1) to signal to the client/server that data has been sent ?
on inspecting the status of the connection in wireshark, i've noticed that only the handshake takes place. there is no data exchanged at all. So im pretty sure the problem lies somewhere on writing to the socket and reading data from the socket (using the keyboard or hardcoded strings).
Any help would be really appreciated.
The client is as follows:
#!/usr/bin/perl
use IO::Socket;
use Getopt::Long;
#$IP_addr = $ARGV[0];
#$tgt_port = $ARG[1];
#netcat client
$port = 9040;
$sock = IO::Socket::INET->new( PeerAddr => 'localhost',
PeerPort => $port,
LocalPort => 9000,
Proto => 'tcp')
or die "\nunable to bind on localhost : $port...";
while ($sock){
#Get the clients IP and port number
$client_IP = $sock -> peerhost();
#$client_IP = 'localhost';
$client_port = $sock -> peerport();
print "\n Connected to $client_IP $client_port \n";
#Reading from socket
$data;
$sock ->recv($data, 1024);
print $data;
#writing to socket
$sock->autoflush(1);
$response = "response: OK recvd\n" ;
$sock->send($response);
shutdown($sock,1);
}
$sock -> close();
The server is as follows:
#!/usr/bin/perl
use IO::Socket;
use Getopt::Long;
#$IP_addr = $ARGV[0];
#$tgt_port = $ARG[1];
#netcat server
$port = 9040;
$sock = IO::Socket::INET->new( Listen => 1,
LocalAddr => 'localhost',
LocalPort => $port,
Proto => 'tcp')
or die "\nunable to bind on localhost : $port...";
while ($sock){
print "\nListening on port $port ...\n";
$sock = $sock -> accept();
#Get the clients IP and port number
$client_IP = $sock->peerhost();
$client_port = $sock->peerport();
print "\n Connected from $client_IP $client_port \n";
#Reading from socket
$data ->recv($sock, 1024);
print $data;
#writing to socket
$sock->autoflush(1);
$response = "oohlalala" ;
$sock -> send($response);
shutdown($sock, 1);
}
$sock -> close();
From IO::Socket:
As of VERSION 1.18 all IO::Socket objects have autoflush turned on by
default. This was not the case with earlier releases.
Perl version 2.0 was released in 1988. You are most likely using perl version 5.x.
1) the major difference between the client and the server is only that
the server has an added LISTEN parameter which enables it to listen
for incoming connections ?
According to the docs:
If Listen is defined then a listen socket is created...
A listen socket can call accept(). If a regular socket calls accept(), accept() returns undef.
accept()
In a scalar context the new socket is returned, or undef upon failure.
In a list context a two-element array is returned containing the new
socket and the peer address; the list will be empty upon failure.
https://perldoc.perl.org/IO/Socket.html
Here is a nice, short, basic description of sockets.
Your server code probably hides some of what's going on. It would be more illustrative if it was written like this:
$server_socket = IO::Socket::INET(.....);
...
...
my $client_socket = $server_socket->accept();
...
...
There are two different sockets. accept() returns a new socket for the server and the client to communicate with, so the original server socket can keep listening for client connections.
2) Are there any steps missing between recv and displaying the data?
Depending on what you're doing, you might want to get rid of the characters that mark the end of the data, which the code would have used to signal the other side that it should stop trying to read more data from the socket.
Receiving the data is the tricky part. An agreed upon protocol must be used by both the client and the server to avoid deadlock, which is when both the client and the server are waiting for the other side to send data. In the example below, I employ a "line oriented" protocol where one side stops reading from the socket when it reads a newline. In networking, by convention a newline is considered to be "\r\n", which represents the ascii characters carriage return and line feed, but to avoid any type of automatic "\n" translations on various OS's, the socket library uses the actual ascii codes: 13 and 10, which in hex notation is: "\x0D\x0A".
server.pl:
use strict;
use warnings;
use 5.020;
use autodie;
use Data::Dumper;
use IO::Socket::INET;
use Socket qw( :crlf ); # "\x0D\x0A" constants CRLF and $CRLF
my $host = 'localhost';
my $port = 15_678;
my $server_socket = IO::Socket::INET->new(
Listen => 5,
LocalPort => $port,
LocalAddr => $host,
Proto => 'tcp',
ReuseAddr => 1,
ReusePort => 1
);
say "Server listening on port: $port\n";
while (my $client_socket = $server_socket->accept() ) {
my $client_ip = $client_socket->peerhost();
my $client_port = $client_socket->peerport();
say "Connection from $client_ip:$client_port";
{
local $/ = CRLF; # $/ is the input record separator, which is "\n"
#by default. Both <$INFILE> and getline() read up to
#and including the input record separator.
while(my $line = $client_socket->getline) { #Blocks until CRLF is read
#from the socket or the other
#side closes the socket.
chomp $line; #chomp() removes input record separator from end of line.
say "Server received: $line";
my $response = reverse $line;
$client_socket->send("$response$CRLF");
say "Server sent: $response";
}
} #Here $/ is restored to whatever it was before this parenthesized block.
#That is what declaring a variable as local does.
say "-" x 30;
#Execution arrives here after the client closes the socket:
$client_socket->shutdown(2); #Send signals to other side of socket.
#Not necessary in this example because other threads
#aren't also reading from the socket.
$client_socket->close(); #Close the filehandle associated with the socket.
}
Note that just like when reading a file, getline will return everything it has read so far when it receives an eof signal, and for the next iteration of the while loop getline will return undef causing the while loop to terminate.
client.pl:
use strict;
use warnings;
use 5.020;
use autodie;
use Data::Dumper;
use IO::Socket::INET;
use Socket qw( :crlf ); #\x0D\x0A constants CRLF and $CRLF
my $port = 15_678;
my #lines = (
"hello world",
"goodbye mars",
);
my $sock = IO::Socket::INET->new("localhost:$port");
for my $line(#lines){
my $server_ip = $sock->peerhost();
my $server_port = $sock->peerport();
say "Connected to $server_ip:$server_port";
$sock->send("$line$CRLF");
say "Client sent: $line";
my $response;
{
local $/ = CRLF;
$response = $sock->getline();
chomp $response;
}
say "Client received: $response";
say '-' x 30;
}
#Tell the server that no more data is coming from this client:
$sock->shutdown(2); #Send signals to other side of socket.
$sock->close(); #Close the filehandle associated with the socket.
After running the client program twice...
Server output:
Server listening on port: 15678
Connection from 127.0.0.1:56085
Server received: hello world
Server sent: dlrow olleh
Server received: goodbye mars
Server sent: sram eybdoog
------------------------------
Connection from 127.0.0.1:56096
Server received: hello world
Server sent: dlrow olleh
Server received: goodbye mars
Server sent: sram eybdoog
------------------------------
Client output:
$ perl client.pl
Connected to 127.0.0.1:15678
Client sent: hello world
Client received: dlrow olleh
------------------------------
Connected to 127.0.0.1:15678
Client sent: goodbye mars
Client received: sram eybdoog
------------------------------
$ perl client.pl
Connected to 127.0.0.1:15678
Client sent: hello world
Client received: dlrow olleh
------------------------------
Connected to 127.0.0.1:15678
Client sent: goodbye mars
Client received: sram eybdoog
------------------------------
$
3) Shouldn't atleast the hardcoded string "$response" be sent when the
program executes the while loop the first time?
Yes, all statements in a while loop will have executed after the first loop has finished executing--but when a statement higher up in the loop is blocking, then the send will never execute.
4) How do shutdown($sock,1) and sleep(1) differ in this implementation? Is it okay to let the socket sleep or should I use
shutdown($sock,1) to signal to the client/server that data has been
sent ?
I'm not sure how shutdown() and sleep() are related in any way. sleep() stops your code from executing for the specified time, while shutdown() sends something to the other side of a socket.
"Closing the socket", i.e. calling shutdown(), to mark the end of the data is another protocol that you can adopt. It makes things pretty easy: one side just continues to read from the socket in some sort of read statement, and when the other side closes the socket, the read will return. Here's an example:
server.pl:
use strict;
use warnings;
use 5.020;
use autodie;
use Data::Dumper;
use IO::Socket::INET;
my $host = 'localhost';
my $port = 15_678;
my $server_socket = IO::Socket::INET->new(
Listen => 5,
LocalPort => $port,
LocalAddr => $host,
Proto => 'tcp',
ReuseAddr => 1,
ReusePort => 1
);
say "Server listening on port: $port\n";
while (my $client_socket = $server_socket->accept() ) {
my $client_ip = $client_socket->peerhost();
my $client_port = $client_socket->peerport();
say "Connection from $client_ip:$client_port";
my $data;
{
local $/ = undef; #This input record separtor will never be found...
$data = <$client_socket>; #...so this reads everything--including newlines--until it gets an eof signal.
}
say "Server received: $data";
my $response = reverse $data;
$client_socket->send($response);
$client_socket->shutdown(2); #Doesn't close filehandle -- merely sends signals.
$client_socket->close(); ##Close the filehandle associated with the socket.
say "Server sent: $response";
say "-" x 30;
}
client.pl:
use strict;
use warnings;
use 5.020;
use autodie;
use Data::Dumper;
use IO::Socket::INET;
my $port = 15_678;
my #data = (
"hello \n world", #Now newlines are in the data
"goodbye \n mars",
);
for my $data (#data){
my $sock = IO::Socket::INET->new("localhost:$port");
my $server_ip = $sock->peerhost();
my $server_port = $sock->peerport();
say "Connected to $server_ip:$server_port";
$sock->send($data);
say "Client sent: $data";
$sock->shutdown(1);
my $response;
{
local $/ = undef; #This input record separtor will never be found...
$response = <$sock>; ##...so this reads everything--including newlines--until it gets an eof signal.
}
$sock->shutdown(0);
$sock->close();
say "Client received: $response";
say '-' x 30;
}
Server output:
Server listening on port: 15678
Connection from 127.0.0.1:53139
Server received: hello
world
Server sent: dlrow
olleh
------------------------------
Connection from 127.0.0.1:53140
Server received: goodbye
mars
Server sent: sram
eybdoog
------------------------------
Client output:
Connected to 127.0.0.1:15678
Client sent: hello
world
Client received: dlrow
olleh
------------------------------
Connected to 127.0.0.1:15678
Client sent: goodbye
mars
Client received: sram
eybdoog
------------------------------
Code for the server (tested with telnet localhost 9040):
use strict;
use warnings;
use IO::Socket::INET;
my $port = 9040;
my $listen = IO::Socket::INET->new(Listen => 1,
LocalPort => $port,
Proto => 'tcp',
ReuseAddr => 1,
ReusePort => 1);
while ($listen) {
print "\nListening on port $port ...\n";
my $sock = $listen->accept();
my $client_IP = $sock->peerhost();
my $client_port = $sock->peerport();
print "\n Connected from $client_IP $client_port \n";
my $data;
$sock->recv($data, 1024);
print $data;
#writing to socket
$sock->autoflush(1);
my $response = "oohlalala\n" ;
$sock->send($response);
shutdown($sock, 1);
}
Client code (tested against above server):
use strict;
use warnings;
use IO::Socket::INET;
my $port = 9040;
my $sock = IO::Socket::INET->new(PeerAddr => 'localhost',
PeerPort => $port,
Proto => 'tcp');
if ($sock) {
my $server_IP = $sock->peerhost();
my $server_port = $sock->peerport();
print "\n Connected to $server_IP $server_port \n";
# initiate protocol
$sock->autoflush(1);
print $sock "OK\n";
my $data;
$sock->recv($data, 1024);
print $data;
shutdown($sock, 1);
}
Output from server:
Listening on port 9040 ...
Connected from 127.0.0.1 36106
OK
Listening on port 9040 ...
Output from client:
Connected to 127.0.0.1 9040
oohlalala

no data received on server side when data is written to socket on client side

I send "smile from server" to the client and expect "good morning" from the client. Basically I don't understand whether the flaw is on server side or the client side.
here is my code :
Server side
#!/usr/bin/perl -w
# Filename : server.pl
use strict;
use Socket;
# use port 7890 as default
my $port = shift || 7890;
my $proto = getprotobyname('tcp');
my $server = "localhost"; # Host IP running the server
# create a socket, make it reusable
socket(SOCKET, PF_INET, SOCK_STREAM, $proto)
or die "Can't open socket $!\n";
# bind to a port, then listen
bind( SOCKET, pack_sockaddr_in($port, inet_aton($server)))
or die "Can't bind to port $port! \n";
listen(SOCKET, 5) or die "listen: $!";
print "SERVER started on port $port\n";
# accepting a connection
my $client_addr;
while ($client_addr = accept(NEW_SOCKET, SOCKET)) {
# send them a message, close connection
my $name = gethostbyaddr($client_addr, AF_INET );
print NEW_SOCKET "Smile from the server";
sleep(5);
print <NEW_SOCKET>;
print "Connection recieved from $name\n";
close NEW_SOCKET;
}
and this is the client side:
#!/usr/bin/perl -w
use strict;
use Socket;
# initialize host and port
my $host = 'localhost';
my $port = 7890;
my $server = "localhost"; # Host IP running the server
# create the socket, connect to the port
socket(SOCKET,PF_INET,SOCK_STREAM,getprotobyname('tcp'))
or die "Can't create a socket $!\n";
connect( SOCKET, pack_sockaddr_in($port, inet_aton($server)))
or die "Can't connect to port $port! \n";
my $line;
while ($line = <SOCKET>) {
print "$line\n";
print SOCKET "good morning";
sleep(10);
}
close SOCKET or die "close: $!";
Buffering.
It's hard to show an example of how to turn the buffering off, when you're using global filehandles and lowlevel core socket functions, instead of using a higher-level IO::Handle-derived socket wrapper.
If instead you'd use that, then this would be simple. The server would then be:
use strict;
use IO::Socket::IP;
# use port 7890 as default
my $port = shift || 7890;
my $listensock = IO::Socket::IP->new(
LocalPort => $port,
Listen => 5,
) or die "Cannot listen - $#";
# accepting a connection
while (my ($client, $client_addr) = $listensock->accept) {
$client->autoflush(1); ### THIS IS THE KEY LINE
# send them a message, close connection
$client->print("Smile from the server");
sleep(5);
print <$client>;
}
The key point being the call to autoflush here, which disables the output buffering and makes sure to send all bytes immediately.
$client->print("Smile from the server\n");
'\n' is the end ch for getline

How to set in PERL recv timeout in my code?

I want to set timeout in my recv function in this specific code below, because sometimes my script stuck forever. I am new in socket programming so i would really appreciate any help. Thanks in advance.
use IO::Socket::INET;
use IO::Select;
use LWP::UserAgent;
use JSON::XS 'decode_json';
use Data::Dumper;
use DBI();
sub dbconn {
my $db_conf = shift;
my $dbh = DBI->connect("DBI:Pg:dbname=somedatabase;host=somehost", "postgres", "",
{pg_server_prepare =>
0,AutoCommit => 1,RaiseError=>1});
$dbh->do("SET CLIENT_ENCODING TO 'UTF-8';");
return $dbh;
}
# auto-flush on socket
$| = 1;
# creating a listening socket
my $socket = new IO::Socket::INET (
LocalHost => '0.0.0.0',
LocalPort => '5000',
Proto => 'tcp',
Listen => 5,
Reuse => 1
);
die "cannot create socket $!\n" unless $socket;
$sel = IO::Select->new( $socket );
print "Server waiting for client connection on port 5000...\n";
my $command = 1;
my $watchTracker = "*HQ,";
my $tl206 = ",LAT:";
my $watchConnectedCheck = ",A,";
my $gpsType;
my $circleString = ",LINK,";
my $dataToSend;
my $new;
my $dbh = dbconn();
while(#ready = $sel->can_read) {
foreach $fh (#ready) {
if($fh == $socket) {
# Create a new socket
$new = $socket->accept;
$new->recv($dataReceived, 1024);
$new->recv($dataReceived, 1024);
# get information about a newly connected client
my $client_address = $new->peerhost();
my $client_port = $new->peerport();
print "===============================================\n";
print "===============================================\n\n";
print "Connection from $client_address:$client_port\n";
print "General data received: $dataReceived\n\n";
#MORE LINES...
}
else {
# Process socket
# Maybe we have finished with the socket
$sel->remove($fh);
$fh->close;
}
}
}
$dbh->disconnect();
Perhaps I am misunderstanding the question, but have you tried setting a timeout in the socket with "Timeout"?
See IO::Socket::INET.
EDIT: I did not catch the 'recv' bit. You have to use setsockopt, which is not wholly portable, so the final answer is somewhat dependent on your platform. Here are some posts that may help:
How do I set `SO_RCVTIMEO` on a socket in Perl?
http://www.perlmonks.org/?node_id=761935
E.g.,
$socket->setsockopt(SOL_SOCKET, SO_RCVTIMEO, pack('l!l!', 30, 0))
or die "setsockopt: $!";

Persistent connection with simple TCP server

Using this simple TCP server/client example in perl, how can I keep sending and receiving without having to reopen the connection (continuously receive data, and process it as it arrives)?
Server:
use IO::Socket::INET;
# auto-flush on socket
$| = 1;
# creating a listening socket
my $socket = new IO::Socket::INET (
LocalHost => '0.0.0.0',
LocalPort => '7777',
Proto => 'tcp',
Listen => 5,
Reuse => 1
);
die "cannot create socket $!\n" unless $socket;
print "server waiting for client connection on port 7777\n";
while(1)
{
# waiting for a new client connection
my $client_socket = $socket->accept();
# get information about a newly connected client
my $client_address = $client_socket->peerhost();
my $client_port = $client_socket->peerport();
print "connection from $client_address:$client_port\n";
# read up to 1024 characters from the connected client
my $data = "";
$client_socket->recv($data, 1024);
print "received data: $data\n";
# write response data to the connected client
$data = "ok";
$client_socket->send($data);
# notify client that response has been sent
shutdown($client_socket, 1);
}
$socket->close();
Client:
use IO::Socket::INET;
# auto-flush on socket
$| = 1;
# create a connecting socket
my $socket = new IO::Socket::INET (
PeerHost => '192.168.1.10',
PeerPort => '7777',
Proto => 'tcp',
);
die "cannot connect to the server $!\n" unless $socket;
print "connected to the server\n";
# data to send to a server
my $req = 'hello world';
my $size = $socket->send($req);
print "sent data of length $size\n";
# notify server that request has been sent
shutdown($socket, 1);
# receive a response of up to 1024 characters from server
my $response = "";
$socket->recv($response, 1024);
print "received response: $response\n";
$socket->close();
I think what you probably want is to prefix all of your messages with some sort of header that contains the length of the message. For example, if you're sending the string hello on the wire, you might prefix with the number 5 to let the other end know how many bytes to read.
how can I keep sending and receiving without having to reopen the connection
You are closing the connection immediately after the first receive-send cycle. I hope it kind of makes sense to you that this causes the connection ... to be closed.
Don't do that. Don't close the connection. Read in a loop until you detect that the other side has shut down. You detect that by comparing the return value of read with zero.

Perl HTTP server not reading requests from clients

I have created an HTTP server in Perl to accept requests from clients.
At the moment only one client is sending the request.
This is how my set-up is:
Client --> Server (this is proxy server as well connecting to the internet), Apache 2 running on Ubuntu.
This is the Perl code for my server:
#!/usr/bin/perl
use IO::Socket::INET;
use strict;
use warnings;
use LWP::Simple;
# auto-flush on socket
$| = 1;
my $port = 7890;
# Create a listening port
my $socket = new IO::Socket::INET(
LocalHost => '127.0.0.1',
LocalPort => shift || $port,
Proto => 'tcp',
Listen => SOMAXCONN,
Reuse => 1
) or die "cannot create socket $!\n";
# open a file and write client requests to the file
$| = 1;
open(FH, '>>', '/home/suresh/clientrequest.txt')
or die "could not open the /home/suresh/clientrequest : $!\n";
print FH "server waiting for client on port\n"
or die "could not write to file : $!\n";
while (my $client_socket = $socket->accept()) {
$client_socket->autoflush(1);
#print FH "Welcome to $0 \n";
my $client_address = $socket->peerhost();
my $client_port = $client_socket->peerport();
print FH "connection from $client_address:$client_port\n";
# read from connected client
my $data = "";
$client_socket->recv($data, 1024);
print FH "Data received from $client_address:$client_port: $data\n";
# write response data to the client
$data = "Sucessfully processed your request";
$client_socket->send($data);
shutdown($client_socket, 1);
}
close(FH);
$socket->close();
When I bring this server up and try sending a request from a client, the request is written to the file, so it looks like the requests are captured by the server.
Can anyone please let me know what other configurations I need to do at server side and at client?
If you write
$| = 1;
then flushing is only activated for the default output filehandle. This is STDOUT unless changed with the select() builtin. So FH is not flushed here — I guess this was your intention. Instead, you have to write
FH->autoflush(1);