Simultaneous data transfer In Perl Chat Server? - perl

I am writing a Chat Server in Perl, I can Transfer messages between the Host(Server) and the Client but i can't send and receive data at the same time.
So how do I Implement The server so that it can send and receive data at the same time and not wait for one of them to finish to move on?
this is what I have written so far.
Server
use IO::Socket::INET;
use Socket;
# auto-flush on socket
$| = 1;
$data;
my $socket = new IO::Socket::INET (
LocalHost => 'localhost',
LocalPort => '4200',
Proto => 'tcp',
Listen => 5,
Reuse => 1
);
die "cannot create socket $!\n" unless $socket;
print "server waiting for client connection on port 4200\n";
while(true)
{
my $client_socket = $socket->accept();
my $client_address = $client_socket->peerhost();
my $client_name=gethostbyaddr($client_address, AF_INET );
my $client_port = $client_socket->peerport();
print "Connection recieved from $client_address\n";
while($client_socket != null)
{
$client_socket->recv($data, 1024);
print "$client_name: $data\n";
$msg=<>;
$client_socket->send($msg);
}
}
$socket->close();
Client
use IO::Socket::INET;
$| = 1; # auto-flush on socket
my $socket = new IO::Socket::INET (
PeerHost => '127.0.0.1',
PeerPort => '4200',
Proto => 'tcp',
); # create a connecting socket
die "cannot connect to the server $!\n" unless $socket;
print "connected to the server\n";
my $recieved;
while(true)
{
$input=<>;
$socket->send($input);
$socket->recv($msg,1024);
print ">".$msg;
}
$socket->close();

Both your program (scripts) are single-thread code. If you want to do a full-duplex ability you will need to do - at least - two threads per-program. One for receiving data, another for sending.
Usually three threads are used: View, Send and Receive
The first shows the data from receive queue, and sends to the send queue when something needs to be sent
Send connects or maintains a connection to the remote server and sends data out, expecting just confirmations on the data sent. Doesn't actively receive
Receive connects or maintains a connection to the remote server, and receives data waiting there, it doesn't send anything, just loops while there is data and receives it, and waits for "flags" from the sending server when there is data pending.

Instead of threading, you can use an event framework; for example, POE::Component::Server::IRC is an IRC server based on the POE framework.

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

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.

Working of perl sockets

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.

Perl client/server socket

--|proxy|--|mux|--|demux|--|proxy|--
--
--
--
machineA satellite link machineB
172.16.1.224 172.16.1.218
Greetings,
I have setup as above. I'm trying to create 'mux'. Basically, it reads traffic from a proxy and splits it up for transmission over 4 wires. The 'demux' reads off 4 wires and forwards traffic on to the proxy.
I've got a basic client/server setup in Perl. But I don't know how to get traffic from the proxy into 'mux'?
Here is my code:
server.pl -- runs on 172.16.1.218
use IO::Socket;
$| = 1;
$socket = new IO::Socket::INET (
LocalHost => '172.16.1.218',
LocalPort => '5000',
Proto => 'tcp',
Listen => 5,
Reuse => 1
);
die "Coudn't open socket" unless $socket;
print "\nTCPServer Waiting for client on port 5000";
while(1)
{
$client_socket = "";
$client_socket = $socket->accept();
$peer_address = $client_socket->peerhost();
$peer_port = $client_socket->peerport();
#print "\n I got a connection from ( $peer_address , $peer_port ) ";
while (1){
$send_data = <STDIN>;
$client_socket->send($send_data);
$client_socket->recv($recieved_data,10);
print $recieved_data;#."\n";
#$client_socket->autoflush();
}
}
and:
client.pl
use IO::Socket;
$socket = new IO::Socket::INET (
PeerAddr => '172.16.1.224',
PeerPort => 5000,
Proto => 'tcp',
)
or die "Couldn't connect to Server\n";
while (1) {
$socket->recv($recv_data,10);
print $recv_data."\n";
$send_data = <STDIN>;
$socket->send($send_data);
}
I'm just a bit stuck and would appreciate any comments.
Many thanks in advance,
Your server is handling just one connection. You should use an array of connections (#socket).
You have two infinite loops nested. Since the inner one is never going to finish, you are going to attend only the first connection.
This seems a typical chat server, so i recommend you to search Google for "perl chat server". Here you have some source code that can be of help:
http://sourceforge.net/projects/perlchat/

proxy with perl script

#!/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.