我正在关注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();
答案 0 :(得分:1)
对于一个简单的&#34;只需从STDIN发送,接收到STDOUT&#34;客户端,您可以使用telnet
,nc
或socat
中的任何一个。这些将非常简单,可用于测试。
$ 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 "");