Perl中的基本网络聊天应用程序
为了便于学习,我正在尝试用Perl编写一个基本的网络聊天应用程序。我目前有一个服务器和客户机程序,几乎可以按照我的要求运行。多个客户端可以连接到服务器并向服务器发送消息。然而,我真的不知道如何从一个客户机向另一个客户机发送消息,如果能在这里向正确的方向推进,我将不胜感激。这是我到目前为止的代码,想法 注意:这是我第一次尝试在一个合适的项目中使用网络或Perl,因此对于如何编写它的任何其他指导也将不胜感激 chat_server.plPerl中的基本网络聊天应用程序,perl,network-programming,Perl,Network Programming,为了便于学习,我正在尝试用Perl编写一个基本的网络聊天应用程序。我目前有一个服务器和客户机程序,几乎可以按照我的要求运行。多个客户端可以连接到服务器并向服务器发送消息。然而,我真的不知道如何从一个客户机向另一个客户机发送消息,如果能在这里向正确的方向推进,我将不胜感激。这是我到目前为止的代码,想法 注意:这是我第一次尝试在一个合适的项目中使用网络或Perl,因此对于如何编写它的任何其他指导也将不胜感激 chat_server.pl #!/usr/bin/perl -w # chat_serve
#!/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让你共享数据结构。不容易-但我可以举个例子:滚动到底部,您可以看到一个基于套接字的场景。