I am a beginner to Perl socket programming. As of now, the server sends a string and the client responds with another string in my program. Later, if the server sends another string, the client is not able to receive it. To transfer data between the server and client for multiple times, should I include any functions?
SERVER:
#!/usr/bin/perl
use strict;
use warnings;
use IO::Socket::INET;
my $socket;
my $clientsocket;
my $serverdata;
my $clientdata;
$socket = new IO::Socket::INET (
LocalHost => '127.0.0.1',
LocalPort => 2500,
Proto => 'tcp',
Listen => 1,
Reuse => 1
) or die "Oops: $! \n";
print "Waiting for the Client.\n";
$clientsocket = $socket->accept();
print "Connected from : ", $clientsocket->peerhost();
print ", Port : ", $clientsocket->peerport(), "\n";
# Write some data to the client
$serverdata = "This is the Server speaking \n";
print $clientsocket "$serverdata \n";
# read the data from the client
$clientdata = <$clientsocket>;
print "$clientdata";
$serverdata = "Server Again writing \n";
print $clientsocket "$serverdata";
$socket->close();
CLIENT:
#!/usr/bin/perl
use strict;
use warnings;
use IO::Socket::INET;
use Tk;
my $socket;
my $serverdata;
$socket = new IO::Socket::INET (
PeerHost => '127.0.0.1',
PeerPort => '2500',
Proto => 'tcp',
) or die "$!\n";
print "Connected to the Server.\n";
# read the message sent by server.
$serverdata = <$socket>;
print "Message from Server : $serverdata \n";
# Send some message to server.
my $name = "Client here!";
print $socket "$name";
# Read message sent by server.
$serverdata = <$socket>;
print "$serverdata";
$socket->close();
Printing of $serverdata second time in the Client side is not happening.
If you use to read message from another end, the sender must end the message with "\n".
Alternatively, you can use recv(...) so the message won't be buffered till newline character.
Just make sure your client sends a whole line. SInce you are reading with
<$clientsocket>
your server waits for a "\n" from the client.
Your server starts listening on some port. It waits until a client connects, the accepts that connection. It reads and writes a bit of data over the client connection. And then? Then it just closes the socket and exits the program.
That is not what you intended: You want the server to start waiting for the next connection. That means some kind of loop: Each time a client connects, we'll do our communication:
while (my $client = $socket->accept) {
# do something with the $client
}
I recommend you read through the relevant sections of perldoc perlipc, but keep in mind it uses outdated best practices, so don't directly copy anything.
Related
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
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.
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);
REQUIREMENTS:
The s.erver waits for connection.
Once the client runs, the connection through the socket is developed successfully.
The Server reads a text file and sends the message to the Client.
The Client listens to it and prints it.
The Client reads a text file sends the message (acknowledgement) to the Server.
The Server listens to it and prints it.
Here is the solution to the above mentioned problem:
SERVER SCRIPT:
#!/usr/bin/perl
use strict;
use warnings;
use IO::Socket::INET;
my $socket;
my $clientsocket;
my $serverdata;
my $clientdata;
$socket = new IO::Socket::INET (
LocalHost => '127.0.0.1',
LocalPort => '0155',
Proto => 'tcp',
Listen => 1,
Reuse => 1
) or die "Oops: $! \n";
print "Waiting for the Client.\n";
$clientsocket = $socket->accept();
print "Connected from : ", $clientsocket->peerhost(); # Display messages
print ", Port : ", $clientsocket->peerport(), "\n";
# Write some data to the client
$serverdata = "This is the Server speaking :)\n";
print $clientsocket "$serverdata \n";
# read the data from the client
$clientdata = <$clientsocket>;
print "Message received from Client : $clientdata\n";
$socket->close();
CLIENT SCRIPT:
#!/usr/bin/perl
use strict;
use warnings;
use IO::Socket::INET;
my $socket;
my $serverdata;
my $clientdata;
$socket = new IO::Socket::INET (
PeerHost => '127.0.0.1',
PeerPort => '0155',
Proto => 'tcp',
) or die "$!\n";
print "Connected to the Server.\n";
# read the message sent by server.
$serverdata = <$socket>;
print "Message from Server : $serverdata \n";
# Send some message to server.
$clientdata = "This is the Client speaking :)";
print $socket "$clientdata \n";
$socket->close();
#!/usr/bin/perl -w
use IO::Socket;
my $sock = new IO::Socket::INET (
PeerAddr => 'remotehost',
PeerPort => '1230',
Proto => 'tcp',
) or die "ERROR in Socket Creation : $!\n";
print "TCP Connection Success.\n";
# write on the socket to server.
$data = "this is the data to send";
$socket->send($data);
# read the socket data sent by server.
$data = <$socket>;
print "Received from Server : $data\n";
sleep(10);
close($sock);
I am unable to send and receive response from the remotehost using the above code...any ideas?
Thanks
Ashish
You declared my $sock when you created the socket. Then later you use
$socket->send($data)
This should be
$sock->send($data)
and later
$data = <$sock>
When working with network data, it is useful to do this after declaring your socket:
$sock->autoflush(1);
By default your IO is buffered and most likely the $data variable is less than buffer size. In such a case OS is waiting for more data before sending full buffer to the remote host. Setting autoflush disables buffering.