首先让我重申我上面的评论。通过阅读IO::Socket::Async 的文档,我没有看到明显的方法来做到这一点。您可以设置 UDP 发送方或 UDP 接收方,但不能同时设置。
UDP 连接由 4 个东西定义,(发送方地址、发送方端口、接收方地址、接收方端口)。
服务器可以监听给定的地址/端口。收到数据包后,通常有一些方法可以查询发送者的地址/端口。这就是我在 Perl 6 中看不到的。
客户端可以将数据包定向到特定的服务器地址/端口。客户端通常会选择一个随机的“发送端口”,给出“连接”所需的第四个元素(在此无连接协议中)。
因此,就像您在其他语言的示例中一样,客户端发送数据包,服务器查找发送者的地址/端口,然后将数据包返回到相同的地址/端口。客户端在发送数据包后,再次侦听它发送数据包的同一随机端口,以接收来自服务器的响应。我在 Perl 6 中看不到一个明显的方式来跟进 print-to 和 recv 在刚刚发送到的同一端口上。
话虽如此,Perl 6 有一个很棒的NativeCall 工具,可以用来直接调用动态库,所以如果你愿意的话,你可以用实际的系统调用来做你需要的一切。
这绝不是“官方”的 Perl 6 方式,一旦 IO::Socket::Async 可以做你想做的事,就从你的大脑中清除所有这些,但这里是使用 NativeCall 的方法:
server-udp.pl
use NativeCall;
constant \AF_INET := 2;
constant \SOCK_DGRAM := 2;
class sockaddr_in is repr('CStruct')
{
has int16 $.sin_family;
has uint16 $.sin_port;
has int32 $.sin_addr;
has int64 $.pad;
}
sub socket(int32, int32, int32 --> int32) is native() {}
sub bind(int32, sockaddr_in, uint32 --> int32) is native() {}
sub htons(uint16 --> uint16) is native() {}
sub ntohs(uint16 --> uint16) is native() {}
sub inet_ntoa(int32 --> Str) is native() {}
sub perror(Str) is native() {}
sub recvfrom(int32, Blob, size_t, int32, sockaddr_in, int32 is rw --> ssize_t) is native() {}
sub sendto(int32, Blob, size_t, int32, sockaddr_in, int32 --> ssize_t) is native() {}
my int32 $sock = socket(AF_INET, SOCK_DGRAM, 0);
perror('socket') // die if $sock < 0;
my $addr = sockaddr_in.new(sin_family => AF_INET,
sin_port => htons(3333),
sin_addr => 0);
my $ret = bind($sock, $addr, nativesizeof(sockaddr_in));
perror('bind') // die if $ret < 0;
my $buf = buf8.allocate(1024);
my $fromaddr = sockaddr_in.new;
my int32 $addrsize = nativesizeof(sockaddr_in);
loop
{
$ret = recvfrom($sock, $buf, $buf.bytes, 0, $fromaddr, $addrsize);
perror('recvfrom') // die if $ret < 0;
my $msg = $buf.decode;
$msg.print;
my $return-msg = "Thank you for saying $msg";
my $return-buf = $return-msg.encode;
$ret = sendto($sock, $return-buf, $return-buf.bytes, 0, $fromaddr, $addrsize);
perror('sendto') // die if $ret < 0;
}
client-udp.pl
use NativeCall;
constant \AF_INET := 2;
constant \SOCK_DGRAM := 2;
class sockaddr_in is repr('CStruct')
{
has int16 $.sin_family;
has uint16 $.sin_port;
has int32 $.sin_addr;
has int64 $.pad;
}
sub socket(int32, int32, int32 --> int32) is native() {}
sub htons(uint16 --> uint16) is native() {}
sub inet_ntoa(int32 --> Str) is native() {}
sub inet_aton(Str, int32 is rw --> int32) is native() {}
sub perror(Str) is native() {}
sub recvfrom(int32, Blob, size_t, int32, sockaddr_in, int32 is rw --> ssize_t) is native() {}
sub recv(int32, Blob, size_t, int32 --> ssize_t) is native() {}
sub sendto(int32, Blob, size_t, int32, sockaddr_in, int32 --> ssize_t) is native() {}
my int32 $sock = socket(AF_INET, SOCK_DGRAM, 0);
perror('socket') // die if $sock < 0;
my int32 $addr-ip;
inet_aton('127.0.0.1', $addr-ip) or die "Bad address";
my $addr = sockaddr_in.new(sin_family => AF_INET,
sin_port => htons(3333),
sin_addr => $addr-ip);
my $msg = "Hello, Perl 6!\n".encode;
my $ret = sendto($sock, $msg, $msg.bytes, 0, $addr, nativesizeof(sockaddr_in));
perror('sendto') // die if $ret < 0;
my $buf = buf8.allocate(1024);
$ret = recv($sock, $buf, $buf.bytes, 0);
say "Return Msg: ", $buf.decode;