在perl中编写聊天室,我遇到了客户端问题?

时间:2014-04-30 18:30:39

标签: perl sockets

我正在关注this guide解释如何使用IO :: Async来执行服务器,但我的客户端代码出现问题。我有它先发送然后收到的地方。这使我在接收任何数据之前按下每个客户端上的输入。我想我必须听,直到我想打字,但我不确定如何。以下是我当前的客户代码。

use IO::Socket::INET;

# auto-flush on socket
$| = 1;

# create a connecting socket
my $socket = new IO::Socket::INET (
    PeerHost => 'localhost',
    PeerPort => '12345',
    Proto => 'tcp',
);
die "cannot connect to the server $!\n" unless $socket;
print "My chat room client.  Version One.\n";

while (1) {
    my $data = <STDIN>;
    $socket->send($data);
    my $response = "";
    $socket->recv($response, 1024);
    print ">$response";
    last if (index($data, "logout") == 0);
}

$socket->close();

3 个答案:

答案 0 :(得分:1)

对于一个简单的&#34;只需从STDIN发送,接收到STDOUT&#34;客户端,您可以使用telnetncsocat中的任何一个。这些将非常简单,可用于测试。

$ telnet localhost 12345

$ nc localhost 12345

$ socat stdio tcp:localhost:12345

如果您真的想在Perl中编写内容,因为您希望将其用作启动更好客户端的初始基础,您可能希望将其基于IO::Async。然后,您可以使用类似netcat的示例here。这将为您提供一个看起来和感觉很像简单的netcat的客户端。

答案 1 :(得分:1)

几周前,当我尝试让客户端/服务器聊天以获得乐趣时,我实际上遇到了这个问题。

直到现在才推迟。

您必须按Enter键接收数据的问题的答案是您需要使用线程。但即使您使用线程,如果执行$socket->recv(my $data, 1024),您将无法在命令行上编写任何内容。

这不是使用你的代码,但这是我的解决方案,在过去的24小时后我的头撞墙。我想添加这个作为答案,因为虽然问题出在stackoverflow上,但没有一个答案似乎显示如何使用IO::Select

这是server.pl脚本,它不使用线程:

#!/usr/bin/perl

use strict;
use warnings;
use IO::Socket::INET;
use IO::Select;

$| = 1;
my $serv = IO::Socket::INET->new(
    LocalAddr => '0.0.0.0',
    LocalPort => '5000',
    Reuse => 1,
    Listen => 1,
);

$serv or die "$!";

print 'server up...';
my $sel = IO::Select->new($serv); #initializing IO::Select with an IO::Handle / Socket

print "\nAwaiting Connections\n";

#can_read ( [ TIMEOUT ] )
#can_write ( [ TIMEOUT ] )
#add ( HANDLES )
#http://perldoc.perl.org/IO/Select.html

while(1){
    if(my @ready = $sel->can_read(0)){ #polls the IO::Select object for IO::Handles / Sockets that can be read from
        while(my $sock = shift(@ready)){
            if($sock == $serv){
                my $client = $sock->accept();
                my $paddr = $client->peeraddr();
                my $pport = $client->peerport();

                print "New connection from $paddr on $pport";

                $sel->add($client); #Adds new IO::Handle /Socket to IO::Select, so that it can be polled 
                            #for read/writability with can_read and can_write
            }
            else{
                $sock->recv(my $data, 1024) or die "$!";
                if($data){                  
                    for my $clients ($sel->can_write(0)){
                        if($clients == $serv){next}
                        print $clients $data;
                    }

                }
            }
        }
    }
}

使用线程的client.pl

#!/usr/bin/perl

use strict;
use warnings;
use IO::Socket::INET;
use threads;
use IO::Select;
$| = 1;

my $sock = IO::Socket::INET->new("localhost:5000");
$sock or die "$!";
my $sel = IO::Select->new($sock);


print "Connected to Socket ". $sock->peeraddr().":" . $sock->peerport() . "\n";

#This creates a thread that will be used to take info from STDIN and send it out
#through the socket.

threads->create(
    sub {
        while(1){
            my $line = <>;
            chomp($line);
            for my $out (my @ready = $sel->can_write(0)){
                print $out $line;
            }
        }   
    }
);

while(1){
    if(my @ready = $sel->can_read(0)){
        for my $sock(@ready){
            $sock->recv(my $data, 1024) or die $!;
            print "$data\n" if $data;
        }
    }

}

还有另一个问题,当客户端收到数据并将其打印到控制台时,光标会转到新行,留下您输入的任何字符。

希望这有助于解答您的问题。

答案 2 :(得分:0)

我猜你需要在你的recv调用上设置MSG_DONTWAIT标志,并且仅当它是非空的时才打印响应。

$socket->recv($response, 1024, MSG_DONTWAIT);
print ">$response" if ($response ne "");