Perl中的基本网络聊天应用程序

Perl中的基本网络聊天应用程序,perl,network-programming,Perl,Network Programming,为了便于学习,我正在尝试用Perl编写一个基本的网络聊天应用程序。我目前有一个服务器和客户机程序,几乎可以按照我的要求运行。多个客户端可以连接到服务器并向服务器发送消息。然而,我真的不知道如何从一个客户机向另一个客户机发送消息,如果能在这里向正确的方向推进,我将不胜感激。这是我到目前为止的代码,想法 注意:这是我第一次尝试在一个合适的项目中使用网络或Perl,因此对于如何编写它的任何其他指导也将不胜感激 chat_server.pl #!/usr/bin/perl -w # chat_serve

为了便于学习,我正在尝试用Perl编写一个基本的网络聊天应用程序。我目前有一个服务器和客户机程序,几乎可以按照我的要求运行。多个客户端可以连接到服务器并向服务器发送消息。然而,我真的不知道如何从一个客户机向另一个客户机发送消息,如果能在这里向正确的方向推进,我将不胜感激。这是我到目前为止的代码,想法

注意:这是我第一次尝试在一个合适的项目中使用网络或Perl,因此对于如何编写它的任何其他指导也将不胜感激

chat_server.pl

#!/usr/bin/perl -w
# chat_server.pl
use strict;
use IO::Socket::INET;

my $port = shift or die "Port required!\n";
my $socket = IO::Socket::INET->new(
        LocalPort   => $port,
        Proto       => 'tcp',
        Listen      => SOMAXCONN
    ) or die "Can't create socket: $!!\n";
my $child;

print "Listening for clients on $port...\n";
REQUEST:
while(my $client = $socket->accept) {
    my $addr = gethostbyaddr($client->peeraddr, AF_INET);
    my $port = $client->peerport;

    if($child = fork) {
        print "New connection from $addr:$port\n";
        close $client;
        next REQUEST;
    } die "fork failed!\n" unless defined $child;

    while (<$client>) {
        print "[$addr:$port] says: $_";
        print $client "[$addr:$port] says: $_";
    }   
}
close $socket;
#!/usr/bin/perl -w
# chat_client.pl
use strict;
use IO::Socket::INET;

my $port            = shift or die "No port\n";
my $server          = shift or die "No server\n";
my $client_socket   = IO::Socket::INET->new(
        PeerPort    =>  $port,
        PeerAddr    =>  $server,
        Proto       =>  'tcp'
    ) or die "Can't create send socket: $!!\n";

my $child;

if($child = fork) {
    while(1) {
        sleep(1);
        print scalar <$client_socket>;
    }
}

die "fork failed!\n" unless defined $child;
print "Connected to $server:$port!\n";

do {
    print "> ";
    print $client_socket $_ if defined $_;
} while(<STDIN>);

print "Closing connection";
close $client_socket;
#/usr/bin/perl-w
#chat_server.pl
严格使用;
使用IO::Socket::INET;
my$port=shift或die“需要端口!\n”;
my$socket=IO::socket::INET->new(
LocalPort=>$port,
Proto=>“tcp”,
Listen=>SOMAXCONN
)或死亡“无法创建套接字:$!!\n”;
我的孩子;
打印“侦听$port上的客户端…\n”;
请求:
while(我的$client=$socket->accept){
my$addr=gethostbyaddr($client->peeraddr,AF_INET);
我的$port=$client->peerport;
如果($child=fork){
打印“来自$addr:$port的新连接\n”;
关闭$client;
下一个请求;
}除非定义了$child,否则die“fork failed!\n”;
而(){
打印“[$addr:$port]显示:$\ux”;
打印$client“[$addr:$port]上写着:$\”;
}   
}
关闭$socket;
chat_client.pl

#!/usr/bin/perl -w
# chat_server.pl
use strict;
use IO::Socket::INET;

my $port = shift or die "Port required!\n";
my $socket = IO::Socket::INET->new(
        LocalPort   => $port,
        Proto       => 'tcp',
        Listen      => SOMAXCONN
    ) or die "Can't create socket: $!!\n";
my $child;

print "Listening for clients on $port...\n";
REQUEST:
while(my $client = $socket->accept) {
    my $addr = gethostbyaddr($client->peeraddr, AF_INET);
    my $port = $client->peerport;

    if($child = fork) {
        print "New connection from $addr:$port\n";
        close $client;
        next REQUEST;
    } die "fork failed!\n" unless defined $child;

    while (<$client>) {
        print "[$addr:$port] says: $_";
        print $client "[$addr:$port] says: $_";
    }   
}
close $socket;
#!/usr/bin/perl -w
# chat_client.pl
use strict;
use IO::Socket::INET;

my $port            = shift or die "No port\n";
my $server          = shift or die "No server\n";
my $client_socket   = IO::Socket::INET->new(
        PeerPort    =>  $port,
        PeerAddr    =>  $server,
        Proto       =>  'tcp'
    ) or die "Can't create send socket: $!!\n";

my $child;

if($child = fork) {
    while(1) {
        sleep(1);
        print scalar <$client_socket>;
    }
}

die "fork failed!\n" unless defined $child;
print "Connected to $server:$port!\n";

do {
    print "> ";
    print $client_socket $_ if defined $_;
} while(<STDIN>);

print "Closing connection";
close $client_socket;
#/usr/bin/perl-w
#chat_client.pl
严格使用;
使用IO::Socket::INET;
my$port=shift或die“无端口\n”;
my$server=shift或die“无服务器\n”;
我的$client\u socket=IO::socket::INET->new(
PeerPort=>$port,
PeerAddr=>$server,
Proto=>“tcp”
)或死亡“无法创建发送套接字:$!!\n”;
我的孩子;
如果($child=fork){
而(1){
睡眠(1);
打印标量;
}
}
除非定义了$child,否则die“fork failed!\n”;
打印“已连接到$server:$port!\n”;
做{
打印“>”;
打印$client\u socket$(如果定义了$);
}while();
打印“关闭连接”;
关闭$client_套接字;

从一台客户机到一台服务器并不太难——您在那里使用的代码实际上是——创建一种1对1的关系。您的
fork
ed服务器正在专门与您的客户交谈

要在多个客户机之间传播(通过服务器)信息,您需要变得更复杂一些-因为您有单独的进程,这些进程现在需要相互通信。这是一个很大的问题,perl文档中有一整段关于它的内容:

这实际上会大大增加代码的复杂度,因为在通信中,您将转向一对多的关系,并且它们都将异步发生

基于套接字的通信是进程间通信(IPC)的一种形式,您已经在这样做了。但你的“明白”是,你正在从1到1个通信移动到1到多个通信。你需要能够进行广播,而这种通信方式并不能很好地支持这一点

我的建议是看一下-我这里有一些示例代码:

然后使用和
can\u read
异步确定管道上是否有任何数据。您可能需要一个管道阵列-每个客户端一个-否则您可能会得到并发内容重叠

例如:

(从
IO::Pipe
doc页:

 my $pipe = IO::Pipe->new();
if($pid = fork()) { # Parent
        $pipe->reader();
        while(<$pipe>) {
        ...
        }
    }
    elsif(defined $pid) { # Child
        $pipe->writer();
        print $pipe ...
    }
my$pipe=IO::pipe->new();
如果($pid=fork()){#父
$pipe->reader();
while(){
...
}
}
elsif(定义为$pid){Child
$pipe->writer();
打印$pipe。。。
}
不幸的是,这里有一个小问题-您的管道将通过分叉过程创建,但这反过来意味着您需要弄清楚如何处理管道数组,并检查它们是否可读


这意味着您不能再坐在
中,而
循环接受套接字-这会阻塞,因此您会让消息排队,直到另一个客户端连接(这真的不是您想要的)。因此,您还需要再次使用
选择
,检查是否有东西可以
首先接受

这实际上对您的经验水平很有好处。我要马上说的唯一一件事是,您应该确保您的学习材料是最新的。
-w
在命令行或shebang行h上只要被上级所取代,请使用警告。您还应该在
中的服务器代码中声明
$child
,而
则在
之前,如果
感谢您的回答,老实说,我仍然对如何实现这一点感到非常困惑。我仍然可以在每个连接只有一个进程的情况下执行此操作吗ion还是我需要再次分叉?我如何才能将从一个连接接收到的数据包传递给所有打开的连接?我有一个想法;假设我让每个分叉的进程监听数据,一旦一个进程接收到一些数据,我就可以使用一个包含所有活动连接的所有进程之间共享的列表(尽管我不确定如何做到这一点,或者这是否可能),然后循环所有的连接并像那样发送。想法?比听起来更难,因为通过fork共享列表很难。线程可以。我得出的相同结论是,你能详细说明一下我如何在这里使用线程吗?太多了,无法放入注释中。但是Threads::shared让你共享数据结构。不容易-但我可以举个例子:滚动到底部,您可以看到一个基于套接字的场景。