1

I am making socket programming for simple communication now.

I have noticed that the server is not the one I created and it works fine (given the experimental client)

In my code, recv works fine, but send does not work. Is there anything wrong with my code?

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"}
        }
    }
}

The server works fine. I checked with the example source (python code) given with the server. What am I missing?

4
  • 1
    Please do add use strict; and use warnings; do your code. Then fix the errors reported and update your question. Commented Feb 7, 2019 at 7:07
  • Several problems with your code: (a) you do not check how many bytes recv() does return. It may be less then you requested, (b) JSON decode returns refs, i.e. it should be my $json = json_decode($response); and switch($json->{type}) { Commented Feb 7, 2019 at 7:10
  • You also use recv() on a SOCK_STREAM socket. Commented Feb 7, 2019 at 7:20
  • Shouldn't the messages you send be length-prefixed like the ones you received? Commented Feb 7, 2019 at 7:55

1 Answer 1

2
  • You can't assume the recv (or read) will return the entire response. You need to call it repeatedly.
  • You can't assume the recv (or read) will just the response. You need to limit the size of the read of buffer the excess.
  • decode_json returns a reference (not a list of key-value pairs you can assign to a hash).
  • You might also have to handle encoding of the JSON string. The example below assumes UTF-8 encoding.
  • JSON response to the server (case 2 in the original code) needs to include length too.

The following code should be used instead:

#!/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);
    }
}

As I don't have access to your server I used sshd on my local machine, which of course does not send me a JSON. But it shows that reading works :-)

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

Output for an example response to the server would be:

JSON:   {"type":0,"point":[5,4]}
PACKET: 000000187b2274797065223a302c22706f696e74223a5b352c345d7d
Sign up to request clarification or add additional context in comments.

2 Comments

Sorry, missed the print $socket hidden in the code. Updated my answer.
Tip: pack('Na*', length($resp_json), $resp_json) can be shortened to pack('N/a*', $resp_json);

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.