Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic
 
PerlMonks  

communication between server/client

by hari9 (Sexton)
on Aug 03, 2010 at 15:53 UTC ( [id://852690]=perlquestion: print w/replies, xml ) Need Help??

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

Hi All.
In the program below, I want client to send server a message. This message is interpreted by the server and a corresponding reply is given to client.

I'm not sure why client is not getting the reply from the server.

server code

#!/usr/bin/perl #tcpserver.pl use Switch; use IO::Socket::INET; $o=0; $| = 1; $i=0; my ($socket,$client_socket); my ($peer_address,$peer_port); $socket = new IO::Socket::INET ( #LocalHost => '127.0.0.1', LocalPort => '5000', Proto => 'tcp', Listen => 5, Reuse => 1) or die "ERROR in Socket +Creation : $!\n"; $timeData = scalar(localtime); print $timeData."\n"; print "SERVER Waiting for client connection on port 5000"; $n=0; $times_connected=0; # number of client connection $t=0; @connects=(""); while(1) { # waiting for new client connection. $client_socket = $socket->accept(); my $gotdata=""; # get the host and port number of newly connected clients. $peer_address = $client_socket->peerhost(); $peer_port = $client_socket->peerport(); $_=received($peer_address,$peer_port); if($_) { print"\n\nCLIENT ADDRESS\t CLIENT PORT\n"; foreach $_(0..$#client) { print $client[$_]{addr}."\t".$client[$_]{port}."\n +"; #Prints the list of connected clients (dumped in t +he array so far). } } else { sleep(20); } $times_connected++; print "\nAccepted New Client Connection[$times_connected] +From : $peer_address, $peer_port\n at".scalar(localtime)."\n"; while(defined(my $data=<$client_socket>)) { chomp($data); $gotdata.=$data; } process($times_connected,$gotdata,$peerport); # processes +each client details and suitably directs them. print "\n Data Received from Client : $gotdata\n"; ###print $client_socket $status; } $socket->close(); # Process : Interprets the packet from client and instructs it do +the next step sub process { my $client_no=shift; my $data=shift; my $port=shift; my @client_details=(id=>$client_no,info=>$data,port=>$port); my @dataElements = split(//, $data); if($dataElements[0] eq 0) { if($client_no eq 1) #if Its the + very first client pinging { $status="write and get your own Md5"; print "Get your own MD5"; } else { $status="take this Md5 and verify with others"; print "verify this MD5 with already existing other +s"; } } if($dataElements[0] eq 1) { $status="write and Get your own MD5 "; print "write and Get your own MD5 "; #verify(@verified); } if($dataElements[0] eq 2) { $status="Thanks for verifying"; print "Thanks for verifying"; } } # Checks for redundant client connections. sub received { $addr=shift; $port=shift; if($o eq 0) { push @client,{addr=>$addr,port=>$port}; } else { if(grep $client[$_]{port} eq $port,@client) { print "Value already exists"; $ret=0; } else { $ret=1; } $o++; return $ret; } }

Client

#!/usr/bin/perl #tcpclient.pl use IO::Socket::INET; my($status,$md_self,@md_others); $status=0; $md=0; @md_others=("0"); $md_others=join(' ',@md_others); $| = 1; my ($socket,$client_socket); print "TCP Connection Success.\n"; # creating object interface of IO::Socket::INET modules which inte +rnally creates # socket, binds and connects to the TCP server running on the spec +ific port. $socket = new IO::Socket::INET (PeerHost => '127.0.0.1', PeerPort => '5000', Proto => 'tcp', ) or die "ERROR in Socket Creation + : $!\n"; # write on the socket to server. $_=join(' ',$status,$md,$md_others); @data=split(" ",$_); foreach $_(0..$#data) { print $socket $data[$_]; } ###$data=<$socket>; ###print $data; $socket->close();

Programs works fine (client writes on server)if you remove "###" lines from both the codes.

I tried using "print scalar <$socket>" at clients side to display server's reply, not working.

How would I do this otherwise.

Thanks in advance.

Replies are listed 'Best First'.
Re: communication between server/client
by BrowserUk (Patriarch) on Aug 03, 2010 at 16:11 UTC

    When you attempt to read data in your server, you are attempting to read a 'line':

    while(defined(my $data=<$client_socket>))

    But when your client writes the data, it doesn't add any delimiter:

    print $socket $data[$_];

    You need to read the docs and understand how Perl's basic IO functions work.

    And whilst we're at it, what on earth is your reasoning for first joining a bunch of variables together with spaces, and then spliting them apart again?

    # write on the socket to server. $_=join(' ',$status,$md,$md_others); @data=split(" ",$_);

    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      no reasoning, plain gross mistake. having corrected them and adding autoflush after the second socket statement in server, the client still doesnt recieve the msg sent by server.

        Did you add newlines on output from your client?

Re: communication between server/client
by almut (Canon) on Aug 03, 2010 at 16:12 UTC

    Two common problems with client-server programming are

    • using readline (<$socket>) to read data, but not writing newlines on the other end
    • not having made sure data is actually being sent (without buffering), by either calling IO::Handle's ->autoflush() (once) or ->flush() (after every write operation) on the respective handle

    A cursory scan of your code seems to suggest that at least one of those problems is involved.

Re: communication between server/client
by zentara (Archbishop) on Aug 03, 2010 at 19:08 UTC
    I just quickly went thru your code, and didn't see any protocol for telling the server and client to be in recv or send mode. You appear to be having a deadlock problem, where the server expects to be in recv mode, and the client in send mode. When you try and use the socket filehandle to receive, both ends sit and wait. You need to either use IO::Select on the sockets, to detect when you can_read or use the recv and send methods of IO::Socket.

    Think of it like in the old walkie-takie days.... when one end was done sending, they would say "over", and that would signal the other end to start sending instead of listening to the socket filehandle.

    My first guess is to put the client into recv mode just before closing the socket, like:

    # write on the socket to server. $_=join(' ',$status,$md,$md_others); @data=split(" ",$_); foreach $_(0..$#data) { print $socket $data[$_]; } #untested pseudo code my $data; $socket->recv(data,1024); # from perldoc IO::Socket print $data; $socket->close();
    But the best way to avoid this send-recv business is to use IO::Select, and use
    while( $select->can_read){}
    code blocks. Search google for "perl IO::Select socket" and get tons of code.

    Here are some old examples: Look at the perl code at UNO socket code tutorials and Problems reading back from socket

    Also,. you may want to try a forked client which acts more like a bidirectional Telnet connection. The following client avoids the socket send-recv lockup problem, by forking, and have 1 fork for send and 1 fork for recv.

    #!/usr/bin/perl -w use strict; use IO::Socket; my ( $host, $port, $kidpid, $handle, $line ); ( $host, $port ) = ('localhost',15005); my $name = shift || ''; if($name eq ''){print "What's your name?\n"} chomp ($name = <>); # create a tcp connection to the specified host and port $handle = IO::Socket::INET->new( Proto => "tcp", PeerAddr => $host, PeerPort => $port ) or die "can't connect to port $port on $host: $!"; $handle->autoflush(1); # so output gets there right away print STDERR "[Connected to $host:$port]\n"; # split the program into two processes, identical twins die "can't fork: $!" unless defined( $kidpid = fork() ); # the if{} block runs only in the parent process if ($kidpid) { # copy the socket to standard output while ( defined( $line = <$handle> ) ) { print STDOUT $line; } kill( "TERM", $kidpid ); # send SIGTERM to child } # the else{} block runs only in the child process else { # copy standard input to the socket while ( defined( $line = <STDIN> ) ) { print $handle "$name->$line"; } }

    I'm not really a human, but I play one on earth.
    Old Perl Programmer Haiku

      Thanks guys, I finally figured it out. I had to put
      $client_socket->shutdown(0); #at the server end.
      and $socket->shutdown(1); #at the client end.

      Salute!

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://852690]
Approved by BrowserUk
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others chilling in the Monastery: (3)
As of 2024-04-24 05:43 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found