抱歉英语不好,不是我的母语。
我是perl编程的新手,我现在面临一个繁琐的问题。
我使用IO :: Socket :: INET编写了一个简单的客户端服务器。它在Windows上运行完美,但在Linux上却被破坏了。
在Linux上,第一个recv获得服务器的两个通信,因此,第二个正在无休止地等待通信。
运行命令" perl -version"在Windows上给我这个结果:
这是perl 5,版本20,颠覆2(v5.20.2) MSWin32-x64-multi-t hread(有1个注册补丁,请参阅perl -V for 更多细节)
在Linux上:
这是perl 5,版本20,颠覆2(v5.20.2) x86_64-linux-gnu-thread-multi(有42个已注册的补丁,请参阅perl -V 更多细节)
这是服务器的例子:
use IO::Socket;
my $socket= IO::Socket::INET->new( Proto => "tcp",
LocalPort => 2559,
Listen => SOMAXCONN,
Reuse => 1);
while(1)
{
print "Waiting for a client\n";
my $client = $socket->accept();
$client->send("Hello, please connect yourself");
$client->send("Username:");
$client->recv(my $username, 1024);
$client->send("Password:");
$client->recv(my $cipheredpassword, 1024);
$client->send("Thank you, Goodbye.");
$client->close();
print "Connection closed\n";
}
以下是客户的例子:
use IO::Socket;
use Digest::MD5 qw(md5_hex);
my $username = "";
my $password = "";
my $server = IO::Socket::INET->new( Proto => "tcp",
PeerAddr => "localhost",
PeerPort => 2559);
# Pick up both $firstServerMessage and
# $serverAskUsernameMessage on Linux
$server->recv(my $firstServerMessage, 1024);
print "$firstServerMessage\n";
# Hangs on Linux
$server->recv(my $serverAskUsernameMessage, 1024);
while($username eq "")
{
print "$serverAskUsernameMessage\n";
chomp($username = <STDIN>);
}
$server->send($username);
$server->recv(my $serverAskPasswordMessage, 1024);
while($password eq "")
{
print "$serverAskPasswordMessage\n";
chomp($password = <STDIN>);
}
my $hashedPassword = md5_hex($password);
$server->send($hashedPassword);
$server->recv(my $lastServerMessage, 1024);
print $lastServerMessage;
我知道解决这个问题的简单方法是避免连续多次使用&gt; recv,但我也很想知道为什么它不适用于Linux。
我尝试使用 - &gt; flush和 - &gt; autoflush(1),但没有成功。
您的帮助和知识将不胜感激, L.C。
答案 0 :(得分:1)
此问题与操作系统或语言的选择无关。问题与您使用TCP的方式有关。
TCP流就是 - 一个字节流。 TCP写入这些字节的方式无关紧要 - 你可以用50个1字节的块中的send
,或者50个字节,或者介于两者之间的任何东西。 TCP流仅表示字节,没有消息边界。它与文件IO非常相似 - 磁盘上的文件不记得write
调用之间的区别,只记录了传输的字节总数。
所以在您的服务器中
$client->send("Hello, please connect yourself");
$client->send("Username:");
它可以全部通过电线合并到一个段中,并且将在另一端一次到达。这就是为什么任何基于TCP的协议提供某种形式的框架 - 无论是换行,还是声明正文大小的消息头,或者其他什么。某种方式接收器可以再次将流拉开。
例如,您可能决定使用"\n"
作为消息边界。然后,您可以使用
$client->send("Hello, please connect yourself\n");
$client->send("Username:\n");
接收者可以使用常规readline
再次读回这些行。