Beefy Boxes and Bandwidth Generously Provided by pair Networks
No such thing as a small change

Re^3: Improve my tcp-mqtt server

by huck (Parson)
on Jul 01, 2020 at 19:46 UTC ( #11118771=note: print w/replies, xml ) Need Help??

in reply to Re^2: Improve my tcp-mqtt server
in thread Improve my tcp-mqtt server

"besides , the code you provided is not working.". I guess you missed where i mentioned "some untested cut&paste code for you to look at. "

This is a proxie for your client, you may run as many of these as you like. ive had dozens running at once on multiple computers.

#!/usr/bin/perl use strict; use warnings; use IO::Socket::INET; # proxy for client use Getopt::Long; my $toip =''; my $toport =1001; my @optdef=("toip=s" => \$toip ,"toport=s" => \$toport ); GetOptions ( @optdef ) or die("Error in command line arguments\n"); my $n=0; while (1) { if (my $toserver=IO::Socket::INET->new(Proto=> "tcp",PeerAddr => +$toip.':'.$toport)) { my $local_port = $toserver->sockport(); print " connect $local_port\n"; while (my $in=<$toserver>){ chomp $in; next unless (length($in)); unless (int(rand(20))) {print "dont reply close\n"; last;} # unless (int(rand(20))) {print "dont reply wait\n"; next;} print $toserver $$,' ',$local_port,' ',$in,' ',$n++,"\n"; } close $toserver; my $sleep=int(rand(20)); print "sleep $sleep\n"; sleep $sleep; } # got }
This is the server that cleans up after itself, does not spawn a new thread for each client every 5 min, and handles all three datapoints. watch it run for a while and figure out what is happening.
#!/usr/bin/perl use strict; use warnings; use IO::Socket::INET; use threads; #use Net::MQTT::Simple; use POSIX qw(strftime); #use Sys::Syslog qw(:DEFAULT :standard :macros); use IO::Select; my $mqtt; my $client; my $ident='tcp-mqtt_server'; my $logopt='ndelay'; my $facility='LOG_USER'; my $th_id; my $topic; my $value; my $holdtime=20; my $timeout=5; my @wants=qw/TEMP VBAT VLIN/; sub Main { my $sel_read = IO::Select->new(); my $conn=0; # $mqtt = Net::MQTT::Simple->new("localhost:1883"); # openlog($ident, $logopt, $facility); # don't forget this # flush after every write $| = 1; my ( $socket, $client_socket ); # Bind to listening address and port $socket = new IO::Socket::INET ( LocalHost => '', LocalPort => '1001', Proto => 'tcp', Listen => 5, Reuse => 1 ) or die "Could not open socket: ".$!."\n"; $sel_read-> add($socket); print "SERVER Waiting for client connections...\n"; # syslog(LOG_INFO,"tcp-mqtt server starting"); my %clients; superloop:while(1) { my ($rd_ptr,$wr_ptr,$er_ptr)=IO::Select->select($sel_read,unde +f,undef,$timeout); print "superloop clients ",scalar((keys(%clients))),"\n"; for my $client_socket( sort { $clients{$a}{topen} <=> $clients +{$b}{topen}} keys(%clients) ) { my $pid=$clients{$client_socket}{peer_address}.':'.$client +s{$client_socket}{peer_port}; print ' ',$pid,' ',$clients{$client_socket}{copen},"\n"; } for my $fh (@$rd_ptr) { if ($fh == $socket) { $conn++; # Waiting for new client connection. $client_socket = $socket->accept(); # Push new client connection to it's own thread $clients {$client_socket}={ socket =>$client_socket ,thread =>threads->create( \&clientHan +dler, $client_socket ) ,peer_address =>$client_socket->peerhost() ,peer_port =>$client_socket->peerport() ,local_port =>$client_socket->sockport() ,topen =>time }; $clients{$client_socket}{copen}=strftime "%a %b %e %H: +%M:%S %Y", localtime $clients{$client_socket}{topen}; my $started=$clients{$client_socket}{thread}; my $nclients=scalar((keys(%clients))); my $pid=$clients{$client_socket}{peer_address}.':'.$cl +ients{$client_socket}{peer_port}; print "Connection $conn $pid clients $nclients\n" } # socket } # fh my @opened=keys(%clients); my @eofable=(); for my $open ( @opened ) { my $thread=$clients{$open}{thread}; if( $thread->is_joinable() ) { $thread->join(); my $pid=$clients{$open}{peer_address}.':'.$clients{$op +en}{peer_port}; print "Joined $pid\n"; push @eofable,$open; } # joinable } #opened for my $open ( @eofable ) { # my $socket=$clients{$open}{socket}; # magic lost in strin +gified key # close($socket); my $pid=$clients{$open}{peer_address}.':'.$clients{$open}{p +eer_port}; delete $clients{$open}; # destroys socket and thread object +s; my $nclients=scalar((keys(%clients))); print "Cleaned $pid clients $nclients\n"; } # eofable } # superloop $socket->close(); return 1; } sub clientHandler { my ($client_socket) = @_; my %user = (); $user{peer_address} = $client_socket->peerhost(); $user{peer_port} = $client_socket->peerport(); $user{local_port} = $client_socket->sockport(); $th_id = threads->tid(); my $isopen=1; my $pid=$user{peer_address}.":".$user{peer_port}; print "Client ".$user{peer_address}.":".$user{peer_port}.":".$user +{local_port}."\n"; # syslog(LOG_INFO,"Client $user{peer_address}:$user{peer_port}:$ +user{local_port}:$th_id is connected"); eval{ while ($isopen) { my $datestring = strftime "%a %b %e %H:%M:%S %Y", localtim +e; print "$datestring\n"; print $client_socket "\n"; for my $want (@wants) { $isopen=0; print $client_socket $want,"\n"; while( my $buffer = <$client_socket> ) { $isopen=1; print $pid,' ',$buffer; my $value = substr $buffer, 0,-2; # $mqtt->retain("minimon/VLIN" => $buffer); # syslog(LOG_INFO,"VLIN: $buffer"); last; } last unless ($isopen); } # want sleep($holdtime) if ($isopen); } # isopen }; if($@){ print "tcp-mqtt exception:$@->getErrorMessage()"; # syslog(LOG_INFO,"tcp-mqtt exception:$@->getErrorMessage()" +); } $client_socket->shutdown(2); #$client_socket->close(); print "Client exit from ".$user{peer_address}.":".$user{peer_port} +."\n"; # Client has exited so thread should exit too threads->exit(); } # Start the Main loop Main();

This method still suffers from some problems. One is in your choice of line ends.

#The Internet line terminator is "\015\012". 
#Under ASCII variants of Unix, that could usually be written as "\r\n", 
#but under other systems, "\r\n" might at times be "\015\015\012", 
#        "\012\012\015", 
# or something completely different. 
# The standards specify writing "\015\012" to be conformant (be strict in what you provide), 
# but they also recommend accepting a lone "\012" on input (but be lenient in what you require). 

Another is the semantics of closeing both ends of a socket between computers is complicated and and result in the server end seeming to be open with an outstanding blocking read on it, while the other end is plain gone. This will result in a client haning out in the %clients table forever

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://11118771]
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others studying the Monastery: (3)
As of 2021-02-28 12:48 GMT
Find Nodes?
    Voting Booth?

    No recent polls found