Is it possible to create a socket connection to an open port on an end device.
If the connection drops print something?
I have seen a few examples but they require a server type script and a client, just looking for a client.
Thanks
Perl has sockets built right into it. You just need to load the standard Socket.pm module to get the constants you need.
The perlipc manpage tells you all about this. There are many higher-level modules that get at this more easily than the builtins, however. Some are even standard.
Here’s a CLI example:
% perl -MIO::Socket::INET -E '$him = new IO::Socket::INET "localhost:daytime" // die; print while <$him>'
Tue Jun 28 08:17:13 2011
Consider using the module IO::Socket::INET, http://www.thegeekstuff.com/2010/07/perl-tcp-udp-socket-programming/
A variation of this might fit your need:
use strict;
use warnings;
use constant
{ SOCKET_ERROR_MESSAGE => 'Some socket error message right here!'
, YOU_WANT_TO => 1
};
use IO::Select;
use IO::Socket::INET;
#ARGV = qw<server.domain.tld 8080> unless #ARGV;
sub handle_server_message {
...
}
my $sel
= IO::Select->new(
IO::Socket::INET->new(
PeerAddr => shift
, PeerPort => shift
));
# block until the server sends something that can be read.
while ( my ( $sock ) = $sel->can_read ) {
# you could just do this with $sock->eof...
if ( $sock->error and $sock->eof ) {
die MY_ERROR_MESSAGE if YOU_WANT_TO;
print MY_ERROR_MESSAGE;
}
else {
handle_server_message( $sock );
}
}
Related
I am learning Perl at basic level, I write a program that use Socket client to do a simple task:
when it receive any message from Server, print it to screen and send an "OK" message to server.
But on screen, seem my code does not print any. Here is the code, i tested on Windows and also on Ubuntu but it seem not able to print.
I found a link Print: producing no output and
this one but it does not help.
I using
perl -v
This is perl 5, version 30, subversion 0 (v5.30.0) built for x86_64-linux-gnu-thread-multi
(with 50 registered patches, see perl -V for more detail)
Code:
use strict;
use warnings;
use IO::Socket;
my $socket = new IO::Socket::INET (
PeerAddr => '127.0.0.1',
PeerPort => '8112',
Proto => 'tcp',
);
die "cannot connect to sever $!n" unless $socket;
print "connected to server";
$socket->autoflush();
$socket->send("OK");
while (1) {
# receive a response of up to 1024 characters from server
my $response = "";
$socket->recv($response, 1024);
chomp $response;
print STDOUT $response;
$socket->send( "OK");
}
As comment from #ikegami I appended LF (\n) character to string and it print out normally. So just change to.
print "connected to server\n";
I'm following this guide explaining how to do a server using IO::Async but I'm having issues with my client code. I have it where I send first then receive. This makes me press enter on each client before receiving any data. I figured I'd have to listen till I wanted to type something but I'm not really sure how. Below is my current client code.
use IO::Socket::INET;
# auto-flush on socket
$| = 1;
# create a connecting socket
my $socket = new IO::Socket::INET (
PeerHost => 'localhost',
PeerPort => '12345',
Proto => 'tcp',
);
die "cannot connect to the server $!\n" unless $socket;
print "My chat room client. Version One.\n";
while (1) {
my $data = <STDIN>;
$socket->send($data);
my $response = "";
$socket->recv($response, 1024);
print ">$response";
last if (index($data, "logout") == 0);
}
$socket->close();
I actually had this problem myself a few weeks ago when trying to make a client/server chat for fun.
Put it off until now.
The answer to your problem of having to hit enter to receive data, is that you need to use threads. But even if you use threads, if you do $socket->recv(my $data, 1024) you won't be able to write anything on the command line.
This isn't using your code, but here is my solution after banging my head against a wall for the last 24hrs. I wanted to add this as an answer, because though the question is out there on stackoverflow, none of the answers seemed to show how to use IO::Select.
Here is the server.pl script, it does not use threading:
#!/usr/bin/perl
use strict;
use warnings;
use IO::Socket::INET;
use IO::Select;
$| = 1;
my $serv = IO::Socket::INET->new(
LocalAddr => '0.0.0.0',
LocalPort => '5000',
Reuse => 1,
Listen => 1,
);
$serv or die "$!";
print 'server up...';
my $sel = IO::Select->new($serv); #initializing IO::Select with an IO::Handle / Socket
print "\nAwaiting Connections\n";
#can_read ( [ TIMEOUT ] )
#can_write ( [ TIMEOUT ] )
#add ( HANDLES )
#http://perldoc.perl.org/IO/Select.html
while(1){
if(my #ready = $sel->can_read(0)){ #polls the IO::Select object for IO::Handles / Sockets that can be read from
while(my $sock = shift(#ready)){
if($sock == $serv){
my $client = $sock->accept();
my $paddr = $client->peeraddr();
my $pport = $client->peerport();
print "New connection from $paddr on $pport";
$sel->add($client); #Adds new IO::Handle /Socket to IO::Select, so that it can be polled
#for read/writability with can_read and can_write
}
else{
$sock->recv(my $data, 1024) or die "$!";
if($data){
for my $clients ($sel->can_write(0)){
if($clients == $serv){next}
print $clients $data;
}
}
}
}
}
}
And the client.pl, which uses threads:
#!/usr/bin/perl
use strict;
use warnings;
use IO::Socket::INET;
use threads;
use IO::Select;
$| = 1;
my $sock = IO::Socket::INET->new("localhost:5000");
$sock or die "$!";
my $sel = IO::Select->new($sock);
print "Connected to Socket ". $sock->peeraddr().":" . $sock->peerport() . "\n";
#This creates a thread that will be used to take info from STDIN and send it out
#through the socket.
threads->create(
sub {
while(1){
my $line = <>;
chomp($line);
for my $out (my #ready = $sel->can_write(0)){
print $out $line;
}
}
}
);
while(1){
if(my #ready = $sel->can_read(0)){
for my $sock(#ready){
$sock->recv(my $data, 1024) or die $!;
print "$data\n" if $data;
}
}
}
There is one other problem that arises though, when the client receives data and prints it to the console, your cursor goes to a new line, leaving behind any characters you had typed.
Hope this helps and answers your question.
For a simple "just send from STDIN, receive to STDOUT" client, you could use any of telnet, nc or socat. These will be simple enough to use for testing.
$ telnet localhost 12345
$ nc localhost 12345
$ socat stdio tcp:localhost:12345
If you actually want to write something in Perl, because you want to use it as an initial base to start a better client from, you probably want to base that on IO::Async. You could then use the netcat-like example here. That will give you a client that looks-and-feels a lot like a simple netcat.
I am guessing you need to set the MSG_DONTWAIT flag on your recv call, and print the response only if it is non-null.
$socket->recv($response, 1024, MSG_DONTWAIT);
print ">$response" if ($response ne "");
I have an application that calls FCGI responder to process some tasks and I need to find whether the FCGI responder receives and returns same reqeust IDs.
The FCGI responder is written in Perl and uses FCGI module.
According to FastCGI specification, I can find the information by looking up FastCGI records.
I found Net::FastCGI library may be suitable for solving this issue, but I'm not sure how to utilize the library.
If my fcgi script looks like below, how can I use Net::FastCGI to dump contents of FastCGI record?
use FCGI;
my $count = 0;
my $request = FCGI::Request();
while($request->Accept() >= 0) {
print("Content-type: text/html\r\n\r\n", ++$count);
}
You can use Net::FastCGI if you want to dump FastCGI records. Net::FastCGI is very low level and requires understanding of the FastCGI protocol.
Following code shows a simple client that connects to a FastCGI application given as the first argument and outputs string representations of records sent by the application.
#!/usr/bin/perl
use strict;
use warnings;
use IO::Socket qw[];
use Net::FastCGI::Constant qw[:type :role];
use Net::FastCGI::IO qw[read_record write_record write_stream];
use Net::FastCGI::Protocol qw[build_params dump_record build_begin_request_body];
use warnings FATAL => 'Net::FastCGI::IO';
use constant TRUE => !!1;
my $command = shift #ARGV;
my $socket = IO::Socket::INET->new(Proto => 'tcp', Listen => 5)
or die qq/Could not create a listener socket: '$!'/;
my $host = $socket->sockhost;
my $port = $socket->sockport;
defined(my $pid = fork())
or die qq/Could not fork(): '$!'/;
if (!$pid) {
close STDIN;
open(STDIN, '+>&', $socket)
or die qq/Could not dup socket to STDIN: '$!'/;
exec { $command } $command
or die qq/Could not exec '$command': '$!'/;
}
close $socket;
$socket = IO::Socket::INET->new(Proto => 'tcp', PeerHost => $host, PeerPort => $port)
or die qq/Could not connect to '$host:$port': '$#'/;
write_record($socket, FCGI_BEGIN_REQUEST, 1, build_begin_request_body(FCGI_RESPONDER, 0));
write_stream($socket, FCGI_PARAMS, 1, build_params({}), TRUE);
write_stream($socket, FCGI_STDIN, 1, '', TRUE);
while () {
my ($type, $request_id, $content) = read_record($socket)
or exit;
warn dump_record($type, $request_id, $content), "\n";
last if $type == FCGI_END_REQUEST;
}
Example output:
fcgi-echo.pl is the example app you gave in your question and fcgi-dump.pl is the above code.
$ perl fcgi-dump.pl ./fcgi-echo.pl
{FCGI_STDOUT, 1, "Content-type: text/html\r\n\r\n1"}
{FCGI_STDOUT, 1, ""}
{FCGI_END_REQUEST, 1, {0, FCGI_REQUEST_COMPLETE}}
You wouldn't. There's no sense in using Net::FastCGI when you're already using FCGI. The request ID, if you need it, is available in $request->{id} after calling $request->Accept. It's not clear what you mean by "receives and returns same request IDs" though.
I'm trying to use an API for a Palo Alto Networks software. The code is supposed to submit username and ipaddress of user network logins to a web interface.
When I try using PANs' API with their sample code for a windows machine the following exception is thrown:
Can't use an undefined value as a symbol reference at
C:/Perl/lib/PAN/API.pm line 179 (#1)
PAN::API::UID::login('PAN::API::UID=HASH(0x7fd113828598)', 'SCU-DSM22/pmmertens', 172.16.6.117) called at API_events.pl line 12
This is the code-example that comes with the API documentation:
#!/usr/bin/perl -w
use strict;
use PAN::API;
my $useridagent = '10.0.0.99'; #I changed this to our PAN server address
my $useridapi = PAN::API::UID->new($useridagent);
my $user = $ENV{USERDOMAIN}.'/'.$ENV{USERNAME};
my $ipaddress = unpack('W4',gethostbyname($ENV{COMPUTERNAME}));
$useridapi->login($user,$ipaddress);
I've ensure that all variables are retrieved correctly. Substituting literal values did not help either. Googling this error turned up references about hard and soft references but I don't see any infractions of these rules in the code below.
This is the codeblock from PAN/Api.pm. Line 179 is where the print starts.
sub submit () {
my $self = shift;
use IO::Socket::INET;
use IO::Socket::SSL;
my $socket = IO::Socket::INET->new(PeerAddr => $self->{server},
PeerPort => $self->{port},
Proto => 'tcp');
my $socketssl = IO::Socket::SSL->start_SSL( $socket,
SSL_version =>'TLSv1');
print $socketssl $self->xml;
$socketssl->close;
$socketssl->stop_SSL;
}
Both the IO::Socket::INET and IO::Socket::SSL lines should have error checking. Something like:
my $socket = IO::Socket::INET->new(....)
or die "Failed to create socket: $!"
And:
my $socketssl = IO::Socket::SSL->start_SSL(...)
or die "Failed to start SSL: ".IO::Socket::SSL::errstr();
Although instead of die I might go with Carp::confess.
when I run the following code, the execution is just hanging there, No response at all.
does any of you can tell me what's wrong with the sample code?
use strict;
use warnings;
use IO::Select;
use IO::Socket;
my $s = new IO::Socket (
LocalPort => 8889,
Proto => 'tcp',
Listen => 16,
Reuse => 1
);
die "could not create socket $!\n" unless $s;
If you provide arguments to the IO::Socket constructor it demands a Domain argument. Check out the full source here, specifically the configure subroutine which gets called from the constructor if you've provided arguments.
sub new {
...
return scalar(%arg) ? $sock->configure(\%arg)
: $sock;
}
sub configure {
my($sock,$arg) = #_;
my $domain = delete $arg->{Domain};
croak 'IO::Socket: Cannot configure a generic socket' unless defined $domain;
....
}
Perhaps you're thinking of IO::Socket::INET?
what's wrong with the sample code?
IO::Socket is a generic super class for Perl sockets.
You need to replace the IO::Socket with IO::Socket::INET.