Kelicula has asked for the wisdom of the Perl Monks concerning the following question:

I recently ran into a situation where I need to have many many raspberry pi's running all over the country and I need to "talk" to them from a central computer to tell them when to run a particular program I have pre-loaded on them. However the people that will be "hosting" them if you will are very very NON-computer savvy people, so I really can't have them configure their routers to set up VNC or the like connections, so I thought, I can solve this with "Sockets" right? :-) So what I want to do is have the pi's talk to my computer and say "I'm on and running, what do you want me to do?" and then I can send back to them what to do. Problem is I can't get the dang things to connect. :-( I have my router set to forward port 7777 to my computer and I have a no-ip service that hosts a name for my router.

But every time the connection times out and won't connect . What am I doing wrong? Here is my code:

Server Code

use IO::Socket::INET; # auto-flush on socket $| = 1; # creating a listening socket my $socket = new IO::Socket::INET ( LocalHost => '127.0.0.1', LocalPort => '7777', Proto => 'tcp', Listen => 5, Reuse => 1 ); die "cannot create socket $!\n" unless $socket; print "server waiting for client connection on port 7777\n"; while(1) { # waiting for a new client connection my $client_socket = $socket->accept(); # get information about a newly connected client my $client_address = $client_socket->peerhost(); my $client_port = $client_socket->peerport(); print "connection from $client_address:$client_port\n"; # read up to 1024 characters from the connected client my $data = ""; $client_socket->recv($data, 1024); print "received data: $data\n"; # write response data to the connected client $data = "ok"; $client_socket->send($data); # notify client that response has been sent shutdown($client_socket, 1); } $socket->close();

Client Code

#!/usr/bin/perl use IO::Socket::INET; $| = 1; my $socket = new IO::Socket::INET ( PeerHost => 'theaddressofmycomputer.com', PeerPort => '7777', Proto => 'tcp', ); die "Cannot connect to the server $!\n" unless $socket; print "Connected to the server!\n"; my $req = "Hello World\n"; my $size = $socket->send($req); print "Sent data of length $size\n"; shutdown($socket, 1); my $response = ""; $socket->recv($response, 1024); print "Recieved response: $response\n"; $socket->close();
~~~~~~~~~ I'm unique, just like everybody else! ~~~~~~~~~
UPDATE!!!

OK, I got it working, thank you to everyone for all your help, it was the windows firewall. I simply had to create an inbound and outbound rule allowing communication on the port I want and it worked like a charm!

Replies are listed 'Best First'.
Re: Socket programming Help (updated)
by haukex (Archbishop) on Apr 19, 2016 at 19:52 UTC

    Hi Kelicula,

    Your code works for me, and I suspect it's working for you when you test it locally? But on the server, the line LocalHost => '127.0.0.1', causes the server socket to bind to that address (localhost) and listen for local connections only. Try simply removing that line, and the server will listen for connections on any interface (usually represented by 0.0.0.0).

    You can check what port and address the server is listening on via the command netstat -nap46 (possibly with a sudo in front). Also, I'd suggest you get to know Wireshark for monitoring what's actually happening on the network and whether the connection attempts from the Internet are reaching your machine.

    And by the way, Use strict and warnings!

    Update: Another potential problem that you might encounter during testing is the "hairpin NAT" problem, in which your router may not be able to handle the situation where you are trying access its public Internet IP / dynamic DNS hostname from inside the network. In that case one possible solution is that when your clients are inside your network, they need to use the server's internal address (typically 192.168.X.X), and the public Internet IP when outside your network.

    One more potential situation is that your ISP may be blocking certain incoming connections, in that case the aforementioned Wireshark should be able to help you - you wouldn't see any incoming connections even if your router is configured correctly.

    Hope this helps,
    -- Hauke D

      Thank you for your help Hauke, I originally had the address 0.0.0.0 in there, but that didn't work either. The "server" computer is running Windows, but the raspberry's are running Raspbian, and they are NEVER on the same network. I have it set up for testing even that they are on an external network, so I have NEVER seen it work. :-(

      The program running on Windows with ActiveState 64 bit Perl, is running fine ( no warnings or errors, even with strict and warnings on ) but the script on the raspberry's just time's out every time... It never prints "Connected to socket".

      I will try the Wireshark you mentioned see if that gives any insight. Maybe it's just that sockets aren't what we need, Ideally we would want something like Teamviewer or RDP but they don't run on ARM Raspbian without extensive tweaking...

        Hi Kelicula,

        Ok, well two more ideas:

        Do the scripts work when both are run locally on the same Windows machine? (maybe also try running both server+client together on the RPi for good measure)

        Is the Windows firewall configured to allow incoming connections on that port?

        Regards,
        -- Hauke D

        From the Pi: telnet your_servers_external_ip_addr 7777. If that fails to connect, you've got a firewall or NAT issue.

Re: Socket programming Help
by mlawren (Sexton) on Apr 19, 2016 at 20:59 UTC

    haukex has made some excellent points. The only thing I would add is to think about security, and specifically think about re-using established encryption and/or authentication protocols. I know there is lots of satisfaction in building something new, but please do not deliver something that communicates over the internet in the clear.

    The letsencrypt.org organisation is handing out web certificates for free and http(s) is well understood and supported. Perhaps you could make use of HTTP::Tiny and HTTP::Server::Simple or similar?

Re: Socket programming Help
by morgon (Priest) on Apr 19, 2016 at 22:23 UTC
    Binding the server-socket to 127.0.0.1 cannot work, but this has already been mentioned.

    One possible problem could be that your ISP (the IPS of your sever that is) does not allow incoming connections.

    So try to verify that your server is actually visible on the internet (e.g. telnet from a pi to your server) as just opening a server socket might not be enough...