问题
REQ FLOW :
____________ LOGIN ___________
| |------------------->>| |
| CLIENT | LOGIN ACK | SERVER |
|__________|<<------------------ |__________|
The client and the server sends across the contents of the files they open.
CODE:
SERVER
$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";
while($clientsocket = $socket->accept()){
print "Connected from : ", $clientsocket->peerhost();
print ", Port : ", $clientsocket->peerport(), "\n";
while(<$clientsocket>){
if($_ ne "\$END\$\n"){
print"Message received from Client : $_";
print $clientsocket $_;
}
else{
print"\$END\$\n";
}
} last;
}
login_ack();
sub login_ack{
# Some code removed for the purpose of posting
open (LOGINACK, "login_ack.txt") || die "Cannot open login acknowledgment file $!\n";
my @loginack=<LOGINACK>;
close LOGINACK;
open(LOG, ">>logfile.txt");
foreach $loginack(@loginack) {
if($loginack ne "\$END\$\n"){
print $clientsocket $loginack;
print LOG $loginack;
print $loginack;
}
else{
print"\$END\$\n";
}
}
CLIENT
$socket = new IO::Socket::INET ( PeerHost => '127.0.0.1', PeerPort => '0155', Proto => 'tcp', Reuse => 1) or die "$!\n";
print "Connected to the Server.\n";
send_login();
sub send_login{
# Some code removed for the purpose of posting
open (LOGIN, "Login.txt") || die "Cannot open login file $!\n";
my @login=<LOGIN>;
close LOGIN;
open(LOG, ">>logfile.txt");
foreach $login(@login) {
if($login ne "\$END\$\n"){
print $socket $login;
print LOG $login;
print $login;
}
else{
print"\$END\$\n";
}
}
}
LOGINACK : while(<$socket>){
print"Message received from Server : $_";
print $socket $_;
last LOGINACK;
}
PRESENT OUTPUT:

DESIRED OUTPUT:
CLIENT
Connected to the Server.
this is Login
SAS4
50
SAS_ACTION LOGIN
LOGIN bss
PASSWORD cleint
$END$
Message received from Server : this is Login Ack
Message received from Server : SAS4
Message received from Server : 61
Message received from Server : SAS_ACTION LOGIN_ACK
Message received from Server : ACK_STATUS 0
Message received from Server : ACK_MESSAGE Logged In
Message received from Server : $END$
SERVER
Waiting for the Client.
Connected from : 127.0.0.1, Port : 1862
Message received from Client : this is Login
Message received from Client : SAS4
Message received from Client : 50
Message received from Client : SAS_ACTION LOGIN
Message received from Client : LOGIN bss
Message received from Client : PASSWORD cleint
Message received from Client : $END$
this is Login Ack
SAS4
61
SAS_ACTION LOGIN_ACK
ACK_STATUS 0
ACK_MESSAGE Logged In
$END$
回答1:
Revised Edition of Answer
This code includes 3 scripts:
serverJ.pl
which is an iterative server, processing one request at a time, but continuing to process multiple requests;clientJ.pl
which is a simple client that sends the login request from theLogin.txt
file and echoes what it receives from the server; andclientQ.pl
which sends a QUIT message to the server.
I've left the code using old-fashioned file handles rather than upgrading to modern lexical file handles, but I changed to the 3-argument form of open
. One other change is that most messages are prefixed with $$:
, the Perl process ID. I would not have labelled the INNER:
loop except for symmetry with the OUTER:
loop, which does need a label. It is not clear that the functions send_login()
and abc()
are needed in clientJ.pl
; they are left in deference to the original code.
serverJ.pl
#!/usr/bin/env perl
use strict;
use warnings;
use IO::Socket::INET;
my $socket = new IO::Socket::INET (
LocalHost => '127.0.0.1',
LocalPort => '1055',
Proto => 'tcp',
Listen => 1,
Reuse => 1
) or die "Oops: $! \n";
print "$$: waiting for clients.\n";
server_loop();
$socket->close();
sub server_loop
{
OUTER:
while (my $clientsocket = $socket->accept())
{
print "$$: connected from : ", $clientsocket->peerhost();
print ", port : ", $clientsocket->peerport(), "\n";
INNER:
while (<$clientsocket>)
{
print"$$: Message received from Client : $_";
last INNER if ($_ eq "\$END\$\n");
last OUTER if ($_ eq "\$QUIT\$\n");
print $clientsocket $_;
}
my $login_ack = "login_ack.txt";
open LOGINACK, '<', $login_ack or die "Cannot open login acknowledgment file $login_ack ($!)\n";
my @loginack = <LOGINACK>;
close LOGINACK;
my $logfile = "logfile.txt";
open LOG, ">>", $logfile or die "$$: cannot open $logfile ($!)\n";
foreach my $loginack (@loginack)
{
last if ($loginack eq "\$END\$\n");
print $clientsocket $loginack;
print LOG "$$: $loginack";
print "$$: server to client: $loginack";
}
close LOG;
close $clientsocket;
}
}
clientJ.pl
#!/usr/bin/env perl
use strict;
use warnings;
use IO::Socket::INET;
my $socket = new IO::Socket::INET (
PeerHost => '127.0.0.1',
PeerPort => '1055',
Proto => 'tcp',
Reuse => 1
) or die "$!\n";
print "$$: connected to the server.\n";
send_login();
abc();
$socket->close();
sub send_login
{
my $login_txt = "Login.txt";
open LOGIN, '<', $login_txt or die "Cannot open $login_txt $!\n";
my @login = <LOGIN>;
close LOGIN;
my $logfile = "logfile.txt";
open LOG, '>>', $logfile or die "Cannot open $logfile ($!)\n";
foreach my $login (@login)
{
print $socket $login;
print LOG "$$: $login";
print "$$: sent to server: $login";
last if ($login eq "\$END\$\n");
}
close LOG;
}
sub abc
{
while (<$socket>)
{
print"$$: Message received from Server: $_";
}
}
clientQ.pl
#!/usr/bin/env perl
use strict;
use warnings;
use IO::Socket::INET;
my $socket = new IO::Socket::INET(
PeerHost => '127.0.0.1',
PeerPort => '1055',
Proto => 'tcp',
Reuse => 1
) or die "$!\n";
print $socket "\$QUIT\$\n";
$socket->close();
Sample log
$ perl serverJ.pl 2>&1 &
[1] 87610
$ 87610: waiting for clients.
$ perl clientJ.pl | so
87610: connected from : 127.0.0.1, port : 57143
87610: Message received from Client : SAS4
87610: Message received from Client : 50
87610: Message received from Client : SAS_ACTION LOGIN
87610: Message received from Client : LOGIN bss
87610: Message received from Client : PASSWORD cleint
87610: Message received from Client : $END$
87610: server to client: SAS4
87610: server to client: 61
87610: server to client: SAS_ACTION LOGIN_ACK
87610: server to client: ACK_STATUS 0
87610: server to client: ACK_MESSAGE Logged In
87614: connected to the server.
87614: sent to server: SAS4
87614: sent to server: 50
87614: sent to server: SAS_ACTION LOGIN
87614: sent to server: LOGIN bss
87614: sent to server: PASSWORD cleint
87614: sent to server: $END$
87614: Message received from Server: SAS4
87614: Message received from Server: 50
87614: Message received from Server: SAS_ACTION LOGIN
87614: Message received from Server: LOGIN bss
87614: Message received from Server: PASSWORD cleint
87614: Message received from Server: SAS4
87614: Message received from Server: 61
87614: Message received from Server: SAS_ACTION LOGIN_ACK
87614: Message received from Server: ACK_STATUS 0
87614: Message received from Server: ACK_MESSAGE Logged In
$ perl clientJ.pl | so
87610: connected from : 127.0.0.1, port : 57144
87610: Message received from Client : SAS4
87610: Message received from Client : 50
87610: Message received from Client : SAS_ACTION LOGIN
87610: Message received from Client : LOGIN bss
87610: Message received from Client : PASSWORD cleint
87610: Message received from Client : $END$
87610: server to client: SAS4
87610: server to client: 61
87610: server to client: SAS_ACTION LOGIN_ACK
87610: server to client: ACK_STATUS 0
87610: server to client: ACK_MESSAGE Logged In
87617: connected to the server.
87617: sent to server: SAS4
87617: sent to server: 50
87617: sent to server: SAS_ACTION LOGIN
87617: sent to server: LOGIN bss
87617: sent to server: PASSWORD cleint
87617: sent to server: $END$
87617: Message received from Server: SAS4
87617: Message received from Server: 50
87617: Message received from Server: SAS_ACTION LOGIN
87617: Message received from Server: LOGIN bss
87617: Message received from Server: PASSWORD cleint
87617: Message received from Server: SAS4
87617: Message received from Server: 61
87617: Message received from Server: SAS_ACTION LOGIN_ACK
87617: Message received from Server: ACK_STATUS 0
87617: Message received from Server: ACK_MESSAGE Logged In
$ perl clientQ.pl | so
87610: connected from : 127.0.0.1, port : 57147
87610: Message received from Client : $QUIT$
[1]+ Done perl serverJ.pl 2>&1
$
Post loop code executes
In the server script, while sending the acknowledgement, the code after the
foreach my $loginack (@loginack)
loop does not get executed. I think that is because the code cannot break out of the loop. How shall it be dealt with?
Mildly modified code in serverJ.pl
:
foreach my $loginack (@loginack)
{
last if ($loginack eq "\$END\$\n");
print $clientsocket $loginack;
print LOG "$$: $loginack";
print "$$: server to client: $loginack";
}
print "$$: End of Loop\n";
close LOG;
close $clientsocket;
print "$$: After close\n";
Example run:
$ perl serverJ.pl &
[1] 6913
$ 6913: waiting for clients.
$ perl clientJ.pl
6915: connected to the server.
6913: connected from : 127.0.0.1, port : 52454
6915: sent to server: This is the file Login.txt
6913: Message received from Client : This is the file Login.txt
6915: sent to server: It contains more than 1 line
6915: sent to server: It also contains this one
6915: sent to server: $END$
6913: Message received from Client : It contains more than 1 line
6913: Message received from Client : It also contains this one
6913: Message received from Client : $END$
6915: Message received from Server: This is the file Login.txt
6915: Message received from Server: It contains more than 1 line
6915: Message received from Server: It also contains this one
6913: server to client: This is the file login_ack.txt
6913: server to client: As with the other file, it contains multiple lines
6913: server to client: Several of them.
6913: server to client: This is one of them.
6915: Message received from Server: This is the file login_ack.txt
6913: End of Loop
6915: Message received from Server: As with the other file, it contains multiple lines
6915: Message received from Server: Several of them.
6915: Message received from Server: This is one of them.
6913: After close
$ perl clientQ.pl
6913: connected from : 127.0.0.1, port : 52455
6913: Message received from Client : $QUIT$
[1]+ Done perl serverJ.pl
$
Original Edition of Answer
This code seems to work for me (for a loose definition of 'works'). It is closely based on your code, but using socket 1055 instead of 0155 (I run on Unix; I'd have to be root to use a port number less than 1024), and with use strict;
and use warnings;
and other minor cleanups.
server.pl
#!/usr/bin/env perl
use strict;
use warnings;
use IO::Socket::INET;
my $socket = new IO::Socket::INET( LocalHost => '127.0.0.1', LocalPort => '1055', Proto => 'tcp', Listen => 1, Reuse => 1 ) or die "Oops: $! \n";
print "Waiting for the Client.\n";
my $clientsocket;
while ($clientsocket = $socket->accept())
{
print "Connected from : ", $clientsocket->peerhost();
print ", Port : ", $clientsocket->peerport(), "\n";
while (<$clientsocket>)
{
if ($_ ne "\$END\$\n")
{
print"Message received from Client : $_";
print $clientsocket $_;
}
else
{
print"\$END\$\n";
}
}
last;
}
login_ack();
sub login_ack
{
# Some code removed for the purpose of posting
open (LOGINACK, "login_ack.txt") || die "Cannot open login acknowledgment file $!\n";
my @loginack=<LOGINACK>;
close LOGINACK;
open(LOG, ">>logfile.txt");
foreach my $loginack (@loginack)
{
if ($loginack ne "\$END\$\n")
{
print $clientsocket $loginack;
print LOG $loginack;
print $loginack;
}
else
{
print"\$END\$\n";
}
}
}
client.pl
#!/usr/bin/env perl
use strict;
use warnings;
use IO::Socket::INET;
my $socket = new IO::Socket::INET ( PeerHost => '127.0.0.1', PeerPort => '1055', Proto => 'tcp', Reuse => 1) or die "$!\n";
print "Connected to the Server.\n";
send_login();
sub send_login
{
# Some code removed for the purpose of posting
open (LOGIN, "Login.txt") || die "Cannot open login file $!\n";
my @login=<LOGIN>;
close LOGIN;
open(LOG, ">>logfile.txt");
foreach my $login (@login)
{
if ($login ne "\$END\$\n")
{
print $socket $login;
print LOG $login;
print $login;
}
else
{
print"\$END\$\n";
}
}
}
LOGINACK:
while (<$socket>)
{
print"Message received from Server : $_";
print $socket $_;
last LOGINACK;
}
Login.txt
This is the content of the Login.txt file.
$END$
login_ack.txt
This is the contents of the login_ack.txt file.
It has two lines of text plus the $END$ line.
$END$
Sample output
$ perl server.pl &
[1] 74838
$ Waiting for the Client.
$ perl client.pl | so
Connected from : 127.0.0.1, Port : 51109
Message received from Client : This is the content of the Login.txt file.
Message received from Client : This is the content of the Login.txt file.
Connected to the Server.
This is the content of the Login.txt file.
$END$
Message received from Server : This is the content of the Login.txt file.
This is the contents of the login_ack.txt file.
It has two lines of text plus the $END$ line.
$END$
[1]+ Done perl server.pl
$
The server terminates after responding to a single request.
回答2:
accept
is used to accept a connection from a listen
ing (server) socket. Client sockets are connected by connect
, which is called for you by new
.
So,
while (my $serversocket = $socket->accept()) {
print "\nThe line after the while loop is printing\n\n";
while (<$serversocket>) {
print "Message received from Server : $_";
print $serversocket $_;
}
}
should be
while (<$socket>) {
print "Message received from Server : $_";
}
The output of the client is now
Connected to the Server.
SAS4
50
SAS_ACTION LOGIN
LOGIN bss
PASSWORD cleint
$END$
The line before the while loop is printing.
Message received from Server : SAS4
Message received from Server : 50
Message received from Server : SAS_ACTION LOGIN
Message received from Server : LOGIN bss
Message received from Server : PASSWORD cleint
Message received from Server : $END$
Then it waits for more input from the server. The server never calls login_ack
, since it's waiting for more input from the client. When do you want to call login_ack
?
来源:https://stackoverflow.com/questions/15891134/client-server-2-way-communication-unsuccessful-perl