【问题标题】:Perl socket programing send methodPerl socket编程发送方法
【发布时间】:2019-07-01 05:26:51
【问题描述】:

我现在正在为简单的通信进行套接字编程。

我注意到服务器不是我创建的,它工作正常(给定实验客户端)

在我的代码中,recv 工作正常,但 send 不工作。我的代码有什么问题吗?

my $socket = new IO::Socket::INET (
    #PeerHost => '127.0.0.1',
    PeerHost => '192.168.0.100',
    PeerPort => '8472',
    Proto => 'tcp',
);
die "cannot connect to the server $!\n" unless $socket;
print "connected to the server\n";

while (1) {
    my $response = "";
    $socket->recv($response, 1024);
    if ($response) {
        my @test = split(//,$response);
        my ($length,$data) = unpack("N A*",$response);
        %json = json_decode($data,$length);

        switch ($json{'type'}) {
            case 1 { print "Game Start\n";}
            #case 2 { my $tmp = &my_turn(%json);} #my_turn func is return  "{'type': 0, 'point': [5, 4]}", but fail!
            #case 2 { $socket->send("{'type': 0, 'point': [5, 4]}");} # fail!
            case 2 { print $socket "{'type': 0, 'point': [5, 4]}"; print "ok\n";} # print is executed. However, the server does not receive packets
            #case 2 { $socket->send("{'type': 0, 'point': [5, 4]}");} #fail...
            case 3 { print "ACCEPT\n";}
            case 5 { print "NOPOINT\n";}
            case 6 { print "GAMEOVER\n";}
            case 7 { print "ERROR\n";}
            else {print "ERROR type : $json{'type'}\n"}
        }
    }
}

服务器工作正常。我检查了服务器提供的示例源代码(python 代码)。我错过了什么?

【问题讨论】:

  • 请添加use strict;use warnings; 做你的代码。然后修复报告的错误并更新您的问题。
  • 您的代码存在几个问题:(a) 您没有检查recv() 确实返回了多少字节。它可能比您要求的要少,(b) JSON 解码返回 refs,即它应该是 my $json = json_decode($response);switch($json->{type}) {
  • 您还可以在SOCK_STREAM 套接字上使用recv()
  • 您发送的消息不应该像您收到的消息一样使用长度前缀吗?

标签: perl sockets


【解决方案1】:
  • 您不能假设recv(或read)会返回整个响应。您需要反复调用它。
  • 您不能假设recv(或read)只会响应。您需要限制读取缓冲区的大小。
  • decode_json 返回一个引用(不是您可以分配给哈希的键值对列表)。
  • 您可能还必须处理 JSON 字符串的编码。下面的示例假定使用 UTF-8 编码。
  • 对服务器的 JSON 响应(原始代码中的case 2)也需要包含长度。

应使用以下代码:

#!/usr/bin/perl
use strict;
use warnings;

use JSON;
use IO::Socket;

my $socket = IO::Socket::INET->new(
    PeerHost => '127.0.0.1',
    PeerPort => '22',
    Proto    => 'tcp',
) or
    die "cannot connect to the server $!\n";

print "connected to the server\n";

sub read_bytes($$) {
    my($socket, $length) = @_;
    my $result = '';
    print "ATTEMPT TO READ ${length}\n";
    while ($length > 0) {
        my $received = $socket->read($result, $length, length($result));
        die "socket error: $!\n" unless defined($received);
        die "unexpected EOF\n"   unless $received;
        $length -= $received;
    }

    print "READ '${result}'\n";
    return($result);
}

while (1) {
    my $length = unpack("N", read_bytes($socket, 4));
    my $json   = read_bytes($socket, $length);
    my $data   = JSON->new->utf8->decode($json);

    print $data->{type}, "\n";

    if ($data->{type} == 2) {
        my $response = {
            type  => 0,
            point => [5, 4],
        };
        my $resp_json = JSON->new->utf8->encode($response);
        print "JSON:   ${resp_json}\n";

        my $packet = pack('NA*', length($resp_json), $resp_json);
        print "PACKET: ", unpack('H*', $packet), "\n";

        $socket->write($packet);
    }
}

由于我无法访问您的服务器,因此我在本地计算机上使用了sshd,这当然不会向我发送 JSON。但它表明阅读有效:-)

$ perl dummy.pl
connected to the server
ATTEMPT TO READ 4
READ 'SSH-'
ATTEMPT TO READ 1397966893
^C

对服务器的示例响应的输出将是:

JSON:   {"type":0,"point":[5,4]}
PACKET: 000000187b2274797065223a302c22706f696e74223a5b352c345d7d

【讨论】:

  • 抱歉,错过了隐藏在代码中的print $socket。更新了我的答案。
  • 提示:pack('Na*', length($resp_json), $resp_json)可以简写为pack('N/a*', $resp_json);
猜你喜欢
  • 2012-02-18
  • 2016-05-02
  • 2016-10-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多