在Linux上使用perl合并Socket-> recv

时间:2015-11-21 20:49:50

标签: linux perl sockets

抱歉英语不好,不是我的母语。

我是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。

1 个答案:

答案 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再次读回这些行。