⬆️ ⬇️

Multi-threaded perl server? Easy!

Sometimes it becomes necessary to write some simple TCP or UDP server. For example, now I have quite successfully in production working own implementation of DHCP (the existing ones are not suitable because of the specifics). Usually this is done simply - one cycle, listening to the socket - and voila! But the “stupid” approach is not always justified (something more complicated is needed - working in several streams, for example), and using heavy artillery is too expensive.



Interesting? Welcome under cat.



Preparation, or what we need



First of all, Perl itself is needed. Any more or less modern version will do. Immediately make a reservation - how to do it under Windows, I do not know, I did not check the code, but it should work.

As it turned out, CPAN already has a ready-made Net :: Server module for such tasks. Download and install it using the tools of your batch manager (libnet-server-perl on Debian / Ubuntu) or directly cpan (for an amateur):

cpan Net::Server 


Theory



Net :: Server provides several multi- streaming models: Single (one stream), Fork (a new child process for each connection), PreFork (it seems, but smarter), INET (for use with inetd), MultiType (choosing one of the models - from the configuration or automatically) and so on. I personally like PreFork (fairly simple and stable, but effective), which I will use. In reality, it is better to use MultiType - it can fallback to another model if the one we need is not available.

All that this package provides (module, class, as you wish) is the base. You need to inherit it, redefine several functions (well, well, well, at least one!), Give it a config, and then run it. In fact, everything we need is provided by the base class. It is necessary to add just a little bit. The basic version described in synopsis (which, by the way, is not deprived of some Perl-magic - for example, inheritance without declaring a class of successor), looks like this:

 #!/usr/bin/perl use Net::Server::PreFork; @ISA = qw(Net::Server::PreFork); sub process_request { #...code... } __PACKAGE__->run(); 


Works. Simply. Strong. Effectively. And nifiga is not clear (which, in general, is also a plus - you can show someone). In practice, we will bring it all into a more human form.



Practice



For the program it is better to select a folder somewhere. We will have 3 files (package, configuration, and the executable file itself). Without further ado, the code:

lib / Net / Server / Hello.pm

 #!/usr/bin/perl package Net::Server::Hello; #    use strict; #     ;) use warnings; use base qw(Net::Server::PreFork); #  sub process_request { # ,        my $self = shift; #    .  Perl - while (<STDIN>) { # Net::Server     STDIN + STDOUT! print "Hello!\n"; # .      . } } 1; # Perl-:    return 


etc / myserver.cfg

 #  -   port 9999 proto tcp 




bin / myserver.pl

 #!/usr/bin/perl use strict; use warnings; use FindBin; use lib "$FindBin::Bin/../lib"; #  :     bin, #   () -  lib,  .. use Net::Server::Hello; #    ; , ,      our $server = Net::Server::Hello->new(conf_file => "$FindBin::Bin/../etc/myserver.cfg"); $server->run(); # ! 


If now this is all started, connect to it by telnet-ohm and ask something, you get something like this:

$ telnet 127.0.0.1 9999

Trying 127.0.0.1...

Connected to 127.0.0.1.

Escape character is '^]'.

!

Hello!

Hi!

Hello!



Hello!

^]quit



telnet> quit

Connection closed.



')

What's next?



Using Net :: Server is far from being limited to writing simple network “Hello world” or writing articles on habre . For example, I already have a working prototype of a RADIUS server, which I am going to use for my own VPN service (Kebrum, hello!). Also, on CPAN there are tons of code that somehow uses Net :: Server - for example, an HTTP server. Read the documentation - it taxis. And may the force be with you.



Picture from xkcd .

If anything, this is my first habratopic, therefore, please ask me to drop rotten eggs right away to me at habrapochta.

Source: https://habr.com/ru/post/120170/



All Articles