NAME
Net::Socket::NonBlock - Perl extension for easy creation multi-socket single-thread application, especially non-forking TCP servers
SYNOPSIS
# TCP port forwarder with logging
# Works on Win32!
use Net::Socket::NonBlock;
my $LocalPort = shift
or die "Usage: $0 <LocalPort> <RemoteHost:RemotePort>\n";
my $RemoteHost = shift
or die "Usage: $0 <LocalPort> <RemoteHost:RemotePort>\n";
my $SockNest = Net::Socket::NonBlock->new(SelectT => 0.05,
SilenceT => 60,
)
or die "Error creating sockets nest: $@\n";
# Autoflush on
$| = 1;
$SockNest->Listen(LocalPort => $LocalPort,
Proto => 'tcp',
Accept => \&NewConnection,
SilenceT => 0,
Listen => 10,)
or die "Could not listen on port \"$LocalPort\": $@\n";
my %ConPool = ();
while($SockNest->IO())
{
my $Pstr = '';
my $ClnSock = undef;
my $SrvSock = undef;
while (($ClnSock, $SrvSock) = each(%ConPool))
{
my $Str = undef;
my $ClientID = sprintf("%15.15s:%-5.5s", $SockNest->PeerAddr($ClnSock), $SockNest->PeerPort($ClnSock));
while(($Str = $SockNest->Read($ClnSock)) && length($Str))
{
$Pstr .= " $ClientID CLIENT ".SafeStr($Str)."\n";
$SockNest->Puts($SrvSock, $Str);
};
if (!defined($Str))
{
$SockNest->Close($SrvSock);
delete($ConPool{$ClnSock});
$Pstr .= " $ClientID CLIENT closed\n";
next;
};
while(($Str = $SockNest->Read($SrvSock)) && length($Str))
{
$Pstr .= " $ClientID SERVER ".SafeStr($Str)."\n";
$SockNest->Puts($ClnSock, $Str);
};
if (!defined($Str))
{
$SockNest->Close($ClnSock);
delete($ConPool{$ClnSock});
$Pstr .= " $ClientID SERVER closed\n";
next;
};
};
if (length($Pstr))
{ print localtime()."\n".$Pstr; };
};
sub NewConnection
{
my $ClnSockID = $_[0];
$ConPool{$ClnSockID} = $SockNest->Connect(PeerAddr => $RemoteHost,
Proto => 'tcp',);
if (!defined($ConPool{$ClnSockID}))
{
warn "Can not connect to \"$RemoteHost\": $@\n";
delete($ConPool{$ClnSockID});
return;
};
return 1;
};
DESCRIPTION
This module provides simple way to work with number of non-blocking sockets. It hides most of routine operations with IO::Socket::INET, IO::Select and provides you the asynchronous Input-Output functions.
Module was designed as a part of a multi-connection SMTP relay for WinNT platform.
The Net::Socket::NonBlock methods
new(%PARAMHASH);-
The
newmethod creates theSocketsNestobject and returns a handle to it. This handle is then used to call the methods below.The
SocketsNestitself is the table contains socket handlers, InOut buffers, etc.SocketsNestalso contain aIO::Selectobject which is common for all sockets inSocketsNest.To create new socket you will have to use
ListenorConnectmethods (see below). Also, socket could be created automatically during TCP connection accept procedure inside ofIOmethod.The %PARAMHASH could contain the following keys:
-
SelectT-
SelectTis the timeout forIO::Select->can_readandIO::Select->can_writefunction. See IO::Select for details. Default is 0.1 second. SilenceT-
If no data was transferred trough socket for
SilenceTseconds the socket will be closed. Default is 3600 seconds (1 hour). IfSilenceT = 0socket will nether been closed by timeout.This value is the default for all sockets created by
ListenorConnectmethod if another value will not be provided inListenorConnectparameters. Also, you will be able to change this parameter for any socket in nest usingPropertiesmethod (see below). BuffSize-
The size of buffer for
IO::Socket::INET->recvfunction (see IO::Socket::INET). Default ifPOSIX::BUFSIZ(seePOSIX).This is default for all sockets which will be created and could be overwritten by
Listen,ConnectorProperties. InstDeath-
By default, socket become to be unavailable for read not immediately after close request or IO error but after all data from incoming buffer will be read. Also, by default all data which was written to output buffer before socket close request will be flushed to socket before actual closing. You are able to change this behaviour by set the
InstDeathparameter to'true'value. In this case the socket will be closed immediately after request, all data in input and output buffer will be lost.This is default for all sockets which will be created and could be overwritten by
Listen,ConnectorProperties.
-
IO();-
The most important method :) This method performs actual socket input-output, accept incoming connection, close sockets, etc. You have to call it periodically, as frequently as possible.
IOalways returns 1. SelectT([$Timeout]);-
If
$Timeoutis not specified theSelectTmethod returns a current value ofSelectT.If
$Timeoutis specified theSelectTmethod set theSelectTto the provided value and returns a previous one.
The Net::Socket::NonBlock methods for manipulating sockets
Listen(%PARAMHASH);-
The
Listenmethod create new socket listening onLocalAddr:LocalPort.The
Listentake the same list of arguments asIO::Socket::INET->new. The Proto key is required. If Proto = 'tcp' theAcceptkey is also required. TheAcceptkey must contain the pointer to the external accept function provided by you.When the new connection will be detected by listening TCP socket the new socket will be created by
IO::Socket::INET->acceptfunction. After that the externalAcceptfunction will be called with just one parameter: the ID for the new socket. ExternalAccepthave to returntruevalue otherwise new socket will be closed and connection will be rejected.Listenmethod returns theSocketID, the symbolic name which have to be used for work with particular socket in nest usingGets,Puts,RecvandPropertiesmethods. In case of problemsListenreturnsundefvalue.$@will contain a error message. Connect(%PARAMHASH);-
The
Connectmethod create new socket connected toPeerAddr:PeerPort.The
Connecttake the same list of arguments asIO::Socket::INET->new. The Proto key is required.Connectmethod returns theSocketID, the symbolic name which have to be used for work with particular socket in nest usingGets,Puts,RecvandPropertiesmethods. In case of problemsConnectreturnsundefvalue.$@will contain a error message. - Important note
-
ListenandConnectare synchronous. So if connection establishing take a long time - for eaxmple because of slow DNS resolving - your program will be frozen for a long time. Gets($SocketID, [$MaxLength]);-
For TCP sockets the
Getsmethod returns a string received from corresponding socket. "String" means(.*\n).If data is available for reading but
"\n"is not presented in first$MaxLengthbytes, the$MaxLengthbytes will be returned.For non-TCP sockets the
Getsworks with blocks of data read from socket by singleIO::Socket::INET->recvcall. It is necessary to provide correctPeerAddrandPeerPort. So, if"\n"found in the block and length of string is no more than$MaxLength, the string will be returned. If no"\n"found in the block and block length is no more than$MaxLength, the whole block will be returned. If string is too long or block is too big,$MaxLengthbytes will be returned.Default
$MaxLengthis socketBiffSize.$MaxLengthforGetshave to be no more than32766. It will be adjusted automaticaly otherwise.If no data available for reading,
Getsreturns empty string.If socket closed or
$SocketIDis invalidGetsreturnsundef.In list context method returns an array of 3 elements: [0] - string as in scalar context [1] - PeerAddr [2] - PeerPort
Note:
Getsis not reading data from the socket but takes it from special buffer filled byIOmethod with data read from socket during last call.If you did not read all the data available in buffer new data will be appended to the end of buffer.
Recv($SocketID, [$MaxLength]);-
For TCP sockets the
Recvmethod returns all data available from corresponding socket if data length is no more than$MaxLength. Otherwise$MaxLengthbytes returned.For non-TCP sockets the
Recvworks with blocks of data read from socket by singleIO::Socket::INET->recvcall. It is necessary to provide correctPeerAddrandPeerPort. So, if block length is no more than$MaxLength, the whole block will be returned. If block is too big,$MaxLengthbytes will be returned.Default
$MaxLengthis socketBiffSize.If no data available for reading,
Recvreturns empty string.If socket is closed or
$SocketIDis invalidRecvreturnsundef.In list context method returns an array of 3 elements: [0] - string as in scalar context [1] - PeerAddr [2] - PeerPort
Note:
Recvis not reading data from the socket but takes it from special buffer filled byIOmethod. Read($SocketID, [$MaxLength]);-
This method is little bit eclectic but I found it's useful.
If string
"\n"is presented in the buffer this method will act asGetsmethod. Otherwise it will act asRecv.$MaxLengthforReadhave to be no more than32766. It will be adjusted automaticaly otherwise. Puts($SocketID, $Data, $PeerAddr, $PeerPort);-
The
Putsmethod puts data to the corresponding socket outgoing buffer.$PeerAddr:$PeerPortpair is the destination which$Datamust be sent. If not specified these fields will be taken from socket properties.$PeerAddr:$PeerPortwill be ignored on TCP sockets.If socket closed or
$SocketIDis invalidRecvreturnsundef. Otherwise it returns 1.Note:
Putsis not writing data directly to the socket but puts it to the special buffer which will be flushed to socket byIOmethod during next call. Send($SocketID, $Data);-
Just a synonym for
Puts. PeerAddr($SocketID);-
For TCP sockets the
PeerAddrmethod returns the IP address which is socket connected to or empty string for listening sockets.For non-TCP sockets the
PeerAddrmethod returns the IP address which was used for sending last time or IP address which is corresponding to data read by lastGetsorRecvcall.If socket closed or
$SocketIDis invalidPeerAddrreturnsundef. PeerPort($SocketID);-
For TCP sockets the
PeerPortmethod returns the IP address which is socket connected to or empty string for listening sockets.undefFor non-TCP sockets the
PeerPortmethod returns the port which was used for sending last time or port which is corresponding to data read by lastGetsorRecvcall.If socket closed or
$SocketIDis invalidPeerPortreturnsundef. LocalAddr($SocketID);-
The
LocalAddrmethod returns the IP address for this end of the socket connection.If socket closed or
$SocketIDis invalidLocalAddrreturnsundef. LocalPort($SocketID);-
The
LocalPortmethod returns the IP address for this end of the socket connection.If socket closed or
$SocketIDis invalidLocalPortreturnsundef. Handle($SocketID);-
The
Handlemethod returns the handle to theIO::Socket::INETobject associated with$SocketIDorundefif$SocketIDis invalid or socket closed. Properties($SocketID, [%PARAMHASH]);-
The
Propertiesmethod returns the hash in list context or pointer to the hash in scalar context. Hash itself is containing socket properties which are:-
Handle-
The handle to the socket associated with
$SocketID. Read-only. Input-
The length of data in buffer waiting to be read by
GetsorRecv. Read-only. Output-
The length of data in buffer waiting for sending to the socket. Read-only.
BytesIn-
The number of bytes which was received from socket. Read-only.
BytesOut-
The number of bytes which was sent out to socket. Read-only.
CTime-
The socket creation time as was returned by
time(). Read-only. ATime-
The socket time when socket was sending or receiving data last time. Read-only.
PeerAddr-
The value is the same as returned by
PeerAddrmethod. Read-only. PeerPort-
The value is the same as returned by
PeerPortmethod. Read-only. LocalAddr-
The value is the same as returned by
LocalAddrmethod. Read-only. LocalPort-
The value is the same as returned by
LocalPortmethod. Read-only. SilenceT-
If no data was sent to or received from socket for
SilenceTthe socket will be closed. BuffSize-
The size of buffer for
IO::Socket::INET->recvfunction. InstDeath-
The current state of
instant deathflag. Seenewfor details. Accept-
The pointer to the external
Acceptfunction. SeeListenfor details.
The following parameters could be changed if new value will be provided in the
%PARAMHASH:-
SilenceTBuffSizeInstDeathAccept-
Note: you will be able to set
Acceptproperty only for TCP listening sockets.
-
Close($SocketID);-
Put the "close" request for the socket
$SocketID. The actual removing will be done byIOmethod during next call.Remember: it is important to call
Closefor all socket which have to be removed even they become to be unavailable because ofsend()orrecv()error.
SafeStr($Str);-
Just change all dangerous symbols (
\x00-\x1Fand\xFF) in a string to their hexadecimal codes and returns the updated string. Nothing relative to sockets but can be very usefull for logging pourposes
EXPORT
SafeStr
AUTHOR
Daniel Podolsky, <tpaba@cpan.org>
SEE ALSO
1 POD Error
The following errors were encountered while parsing the POD:
- Around line 1216:
'=item' outside of any '=over'