EasyTCP(3pm) | User Contributed Perl Documentation | EasyTCP(3pm) |
Net::EasyTCP - Easily create secure, bandwidth-friendly TCP/IP clients and servers
use Net::EasyTCP; # # Create the server object # $server = new Net::EasyTCP( mode => "server", port => 2345, ) || die "ERROR CREATING SERVER: $@\n"; # # Tell it about the callbacks to call # on known events # $server->setcallback( data => \&gotdata, connect => \&connected, disconnect => \&disconnected, ) || die "ERROR SETTING CALLBACKS: $@\n"; # # Start the server # $server->start() || die "ERROR STARTING SERVER: $@\n"; # # This sub gets called when a client sends us data # sub gotdata { my $client = shift; my $serial = $client->serial(); my $data = $client->data(); print "Client $serial sent me some data, sending it right back to them again\n"; $client->send($data) || die "ERROR SENDING TO CLIENT: $@\n"; if ($data eq "QUIT") { $client->close() || die "ERROR CLOSING CLIENT: $@\n"; } elsif ($data eq "DIE") { $server->stop() || die "ERROR STOPPING SERVER: $@\n"; } } # # This sub gets called when a new client connects # sub connected { my $client = shift; my $serial = $client->serial(); print "Client $serial just connected\n"; } # # This sub gets called when an existing client disconnects # sub disconnected { my $client = shift; my $serial = $client->serial(); print "Client $serial just disconnected\n"; }
use Net::EasyTCP; # # Create a new client and connect to a server # $client = new Net::EasyTCP( mode => "client", host => 'localhost', port => 2345, ) || die "ERROR CREATING CLIENT: $@\n"; # # Send and receive a simple string # $client->send("HELLO THERE") || die "ERROR SENDING: $@\n"; $reply = $client->receive() || die "ERROR RECEIVING: $@\n"; # # Send and receive complex objects/strings/arrays/hashes by reference # %hash = ("to be or" => "not to be" , "just another" => "perl hacker"); $client->send(\%hash) || die "ERROR SENDING: $@\n"; $reply = $client->receive() || die "ERROR RECEIVING: $@\n"; foreach (keys %{$reply}) { print "Received key: $_ = $reply->{$_}\n"; } # # Send and receive large binary data # for (1..8192) { for (0..255) { $largedata .= chr($_); } } $client->send($largedata) || die "ERROR SENDING: $@\n"; $reply = $client->receive() || die "ERROR RECEIVING: $@\n"; # # Cleanly disconnect from the server # $client->close();
This class allows you to easily create TCP/IP clients and servers and provides an OO interface to manage the connection(s). This allows you to concentrate on the application rather than on the transport.
You still have to engineer your high-level protocol. For example, if you're writing an SMTP client-server pair, you will have to teach your client to send "HELO" when it connects, and you will have to teach your server what to do once it receives the "HELO" command, and so forth.
What you won't have to do is worry about how the command will get there, about line termination, about binary data, complex-structure serialization, encryption, compression, or about fragmented packets on the received end. All of these will be taken care of by this class.
new() expects to be passed a hash. The following keys are accepted:
Also, when encryption using a symmetric encryption module is used, this password is included as part of the secret "key" for encrypting the data. (Optional)
[C] = Available to objects created as mode "client"
[H] = Available to "hybrid" client objects, as in "the server-side client objects created when a new client connects". These are the objects passed to your server's callbacks. Such hybrid clients behave almost exactly like a normal "client" object you create yourself, except for a slight difference in the available methods to retrieve data.
[S] = Available to objects created as mode "server"
The compliment of this function is deleteclientip() .
The compliment of this function is addclientip() .
It accepts an optional parameter, a timeout value in seconds. If none is supplied it will default to 300.
It accepts one parameter, and that is the data to send. The data can be a simple scalar or a reference to something more complex.
setcallback() expects to be passed a hash. Each key in the hash is the callback type identifier, and the value is a reference to a sub to call once that callback type event occurs.
Valid keys in that hash are:
Whenever a callback sub is called, it is passed a single parameter, a CLIENT OBJECT. The callback code may then use any of the methods available to client objects to do whatever it wants to do (Read data sent from the client, reply to the client, close the client connection etc...)
Note that eventhough there's nothing stopping you from reading and writing directly to the socket handle you retrieve via this method, you should never do this since doing so would definately corrupt the internal protocol and may render your connection useless. Instead you should use the send() and receive() methods.
If you need to concurrently do other things when the server is running, then you can supply to start() the optional reference to a subroutine (very similar to the callback() method). If that is supplied, it will be called every loop. This is very similar to the callback subs, except that the called sub will be passed the server object that the start() method was called on (unlike normal client callbacks which are passed a client object). The other alternative to performing other tasks concurrently is to not use the start() method at all and directly call do_one_loop() repeatedly in your own program.
Clients and servers written using this class will automatically compress and/or encrypt the transferred data if the appropriate modules are found.
Compression will be automatically enabled if one (or more) of: Compress::Zlib or Compress::LZF are installed on both the client and the server.
As-symmetric encryption will be automatically enabled if Crypt::RSA is installed on both the client and the server.
Symmetric encryption will be automatically enabled if one (or more) of: Crypt::Rijndael* or Crypt::RC6* or Crypt::Blowfish* or Crypt::DES_EDE3* or Crypt::DES* or Crypt::Twofish2* or Crypt::Twofish* or Crypt::TEA* or Crypt::CipherSaber are installed on both the client and the server.
Strong randomization will be automatically enabled if Crypt::Random is installed; otherwise perl's internal rand() is used to generate random keys.
Preference to the compression/encryption method used is determind by availablity checking following the order in which they are presented in the above lists.
Note that during the negotiation upon connection, servers and clients written using Net::EasyTCP version lower than 0.20 communicated the version of the selected encryption/compression modules. If a version mismatch is found, the client reported a connection failure stating the reason (module version mismatch). This behavior was necessary since it was observed that different versions of the same module could produce incompatible output. If this is encountered, it is strongly recommended you upgrade the module in question to the same version on both ends, or more preferrably, Net::EasyTCP on both ends to the latest version, at a minimum 0.20. However, if you wish to forcefully connect overlooking a version mismatch (risking instability/random problems/data corruption) you may supply the "donotcheckversion" key to the new() constructor of the client object. This is no longer a requirement of Net::EasyTCP version 0.20 or higher since these newer versions have the ability to use different-version modules as long as their data was compatible, which was automatically determined at negotiation time.
To find out which module(s) have been negotiated for use you can use the compression() and encryption() methods.
* Note that for this class's purposes, Crypt::CBC is a requirement to use any of the encryption modules with a * next to it's name in the above list. So eventhough you may have these modules installed on both the client and the server, they will not be used unless Crypt::CBC is also installed on both ends.
* Note that the nature of symmetric cryptography dictates sharing the secret keys somehow. It is therefore highly recommend to use an As-symmetric cryptography module (such as Crypt::RSA) for serious encryption needs; as a determined hacker might find it trivial to decrypt your data with other symmetric modules.
* Note that if symmetric cryptography is used, then it is highly recommended to also use the "password" feature on your servers and clients; since then the "password" will, aside from authentication, be also used in the "secret key" to encrypt the data. Without a password, the secret key has to be transmitted to the other side during the handshake, significantly lowering the overall security of the data.
If the above modules are installed but you want to forcefully disable compression or encryption, supply the "donotcompress" and/or "donotencrypt" keys to the new() constructor. If you would like to forcefully disable the use of only some modules, supply the "donotcompresswith" and/or "donotencryptwith" keys to the new() constructor. This could be used for example to disable the use of Crypt::RSA if you cannot afford the time it takes to generate it's keypairs etc...
The constructor and all methods return something that evaluates to true when successful, and to false when not successful.
There are a couple of exceptions to the above rule and they are the following methods:
The above methods may return something that evaluates to false (such as an empty string, an empty array, or the string "0") eventhough there was no error. In that case check if the returned value is defined or not, using the defined() Perl function.
If not successful, the variable $@ will contain a description of the error that occurred.
In other words, if you write a server using this class, write the client using this class also, and vice versa.
This leads to the following limitation: When a server calls one of your callback subs, it waits for it to return and therefore cannot do anything else. If your callback sub takes 5 minutes to return, then the server will not be able to do anything for 5 minutes, such as acknowledge new clients, or process input from other clients.
In other words, make the code in your callbacks' subs' minimal and strive to make it return as fast as possible.
Mina Naguib http://www.topfx.com mnaguib@cpan.org
Perl(1), IO::Socket, IO::Select, Compress::Zlib, Compress::LZF, Crypt::RSA, Crypt::CBC, Crypt::Rijndael, Crypt::RC6, Crypt::Blowfish, Crypt::DES_EDE3, Crypt::DES, Crypt::Twofish2, Crypt::Twofish, Crypt::TEA, Crypt::CipherSaber, Crypt::Random, defined(), rand()
Copyright (C) 2001-2003 Mina Naguib. All rights reserved. Use is subject to the Perl license.
2022-10-13 | perl v5.34.0 |