NAME
Nginx::Engine - asynchronous framework based on nginx
SYNOPSIS
use Nginx::Engine;
ngxe_init("./ngxe-error.log", 0, 4096);
# Creating server that accepts connection,
# sends "hi" and closes connection
ngxe_server('*', 55555, sub {
ngxe_writer($_[0], 1, 1000, "hi", sub {
if ($_[1]) {
return;
}
ngxe_close($_[0]);
});
});
# Creating server that reads whatever
# comes first and closes connection
ngxe_server('*', 55555, sub {
ngxe_reader($_[0], 1, 1000, sub {
if ($_[1]) {
return;
}
print "got $_[2]\n";
ngxe_close($_[0]);
});
});
# Connecting to 127.0.0.1:80 and disconnecting
ngxe_client('*', '127.0.0.1', 80, 2000, sub {
if ($_[1]) {
warn "$_[1]\n";
return;
}
print "Connected, closing\n";
ngxe_close($_[0]);
});
# Saying N. Hello, World! every second
ngxe_interval_set(1000, sub {
print "$_[2]. Hello, $_[1]!\n";
$_[2]++
}, "World", 1);
# Saying Hello world once in 5 seconds.
ngxe_timeout_set(5000, sub { print "Hello, $_[1]!"; }, "World");
ngxe_loop;
DESCRIPTION
Nginx::Engine is a simple high-performance asynchronous networking framework. It's intended to bring nodejs-like performance and nginx's stability into Perl.
The main difference from other frameworks is a little higher level of abstraction. There are no descriptors nor sockets, everything works with connections instead.
SUPPORTED OS
Any unix or linux with gcc, sh, perl and nginx should be ok.
Tested on: FreeBSD 6.4 i386 FreeBSD 8.0 i386 Fedora Linux 2.6.33.6-147.fc13.i686.PAE Fedora Linux 2.6.18-128.2.1.el5.028stab064.7
EXPORT
The following functions are exported by default:
ngxe_init
ngxe_timeout_set
ngxe_timeout_clear
ngxe_interval_set
ngxe_interval_clear
ngxe_server
ngxe_client
ngxe_reader
ngxe_reader_start
ngxe_reader_stop
ngxe_writer
ngxe_writer_start
ngxe_writer_stop
ngxe_close
ngxe_loop
INITIALIZATION
Before you can do anything you MUST initialize the engine by calling ngxe_init()
at the very beginning of your code. You cannot call any other fuction before that.
ngxe_init(error_log_path, use_stderr, connections)
Nginx requires error log to start. It is important to log error if some system call fails or nginx runs out of some resource, like number of connections or open files. You should always use log. But you can leave it empty if you want to.
To use STDERR as a log too you should set use_stderr flag to 1.
Number of connections must be less than number of open files and sockets per process allowed by the system. You probably would need to tune your system anyway to use more then a couple of thousands.
So, I suggest to start with something like this:
ngxe_init("./ngxe-error.log", 0, 4096);
TIMER
ngxe_timeout_set(TIMEOUT, CALLBACK, ...)
ngxe_timeout_set
creates new timer event to execute a callback after TIMEOUT ms. Takes any number of extra arguments after CALLBACK and stores them internally. CALLBACK must be a CODE reference.
Returns timer identifier which can be used to remove event from the loop with ngxe_timeout_clear
.
First argument passed to the callback is timer identifier and the rest are all those extra arguments you set.
$_[0] - timer
@_[1..$#_] - extra args
For example, here is how to say "Hello, World" in 5 seconds, where "World" is an extra argument:
ngxe_timeout_set(5000, sub { print "Hello, $_[1]!"; }, "World");
ngxe_timeout_clear(TIMER)
Prevents TIMER event from happening, removes from the loop.
INTERVAL
ngxe_interval_set(TIMEOUT, CALLBACK, ...)
Ceates new timer event to execute a callback after TIMEOUT ms. Resets timer every time until ngxe_interval_clear
is called. Takes any number of extra arguments after CALLBACK and stores them internally. CALLBACK must be a CODE reference.
Returns timer identifier which can be used to remove event from the loop with ngxe_interval_clear
.
First argument passed to the callback is timer identifier and the rest are all those extra arguments you set.
$_[0] - timer
@_[1..$#_] - extra args
For example, here is how to say "N. Hello, World" every second, where "World" and "N" are extra arguments:
ngxe_interval_set(1000, sub {
print "$_[2]. Hello, $_[1]!\n";
$_[2]++;
}, "World", 1);
ngxe_interval_clear(TIMER)
Stops interval identified as TIMER, removes from the loop.
SERVER
ngxe_server(BIND_ADDRESS, BIND_PORT, CALLBACK, ...)
Creates new server connection, binds to the BIND_ADDRESS:BIND_PORT, listens, accept new connections and executes CALLBACK on them with extra arguments if any. Empty or '*' BIND_ADDRESS will result in using INADDR_ANY instead.
First and second arguments passed to the callback are connection identifier and IP address of the remote host. All the rest - extra arguments you set.
$_[0] - connection
$_[1] - IP address connected
@_[2..$#_] - extra args
For example, to accept new connection, print its address and close it you need to create server and call ngxe_close
right inside the callback:
ngxe_server('*', 55555, sub {
print "$_[1] connected and discarded\n";
ngxe_close($_[0]);
});
CLIENT
ngxe_client(BIND_ADDR, REMOTE_ADDR, REMOTE_PORT, TIMEOUT, CALLBACK, ...)
Creates new client connection, binds to the BIND_ADDR, connects to the REMOTE_ADDR:REMOTE_PORT. And tries to do all of it in TIMEOUT ms. Executes CALLBACK after with any extra arguments.
Returns connection identifier.
First argument passed to the callback is connection identifier, second - error variable and the rest are extra arguments.
$_[0] - connection
$_[1] - error indicator
@_[2..$#_] - extra args
If error is set and TRUE than callback must return without any other ngxe_* functions beign called on this connection.
Example, connecting to 127.0.0.1:80 and immediately closing connection:
ngxe_client('127.0.0.1', '127.0.0.1', 80, 2000, sub {
if ($_[1]) {
warn "$_[1]\n";
return;
}
print "Connected, closing\n";
ngxe_close($_[0]);
});
Notice, we are returning from callback on error. This is required behaviour.
READER AND WRITER
Reader is a way to receive data from connection asynchronously. It executes callback every time new data arrived. You should do whatever you need with read buffer and clear it afterwards to avoid too much memory consumption.
Writer is a bit different and it will execute a callback only when entire write buffer has been send. Writer clears write buffer for you. You can modify it inside the callback and writer will send it again. You can achieve streaming this way.
Read and write buffers can be used in both reader and writer.
And both reader and writer can be recreated to achieve different processing schemes.
ngxe_reader(CONN, START, TIMEOUT, CALLBACK, ...)
Creates a reader for connection identified as CONN. Starts it immediately if START is 1. If no data has been received in TIMEOUT ms executes i<CALLBACK> with error flag set to timeout. Extra args can be placed after CALLBACK, as usual.
Returns undef on error.
First argument paseed to the callback is connection identifier. Second is error.variable. Third and 4th are read and write buffers.
$_[0] - connection
$_[1] - error indicator
$_[2] - read buffer
$_[3] - write buffer
@_[4..$#_] - extra args
If error is set you must return from the subroutine avoiding any ngxe_* calls on current connection identifier $_[0].
For example, let's create server, read a few bytes from new connection and close it:
ngxe_server('*', 55555, sub {
ngxe_reader($_[0], 1, 1000, sub {
if ($_[1]) {
return;
}
print "got $_[2]\n";
ngxe_close($_[0]);
});
});
ngxe_reader_start(CONN)
Starts reader for CONN.
ngxe_reader_stop(CONN)
Stops reader for CONN.
ngxe_writer(CONN, START, TIMEOUT, DATA, CALLBACK, ...)
Creates a writer for connection identified as CONN. Starts it immediately if START is 1. If no data has been send in TIMEOUT ms executes i<CALLBACK> with error flag set to timeout. Extra args can be placed after CALLBACK, as usual. Puts DATA into the write buffer.
Returns undef on error.
First argument paseed to the callback is connection identifier. Second is error.variable. Third and 4th are read and write buffers.
$_[0] - connection
$_[1] - error indicator
$_[2] - read buffer
$_[3] - write buffer
@_[4..$#_] - extra args
If error is set you must return from the subroutine avoiding any ngxe_* calls on current connection identifier $_[0]
.
For example, let's create server, send a few bytes to new connection and close it:
ngxe_server('*', 55555, sub {
ngxe_writer($_[0], 1, 1000, "hi", sub {
if ($_[1]) {
return;
}
ngxe_close($_[0]);
});
});
ngxe_writer_start(CONN)
Starts writer for CONN.
ngxe_writer_stop(CONN)
Stops writer for CONN
CLOSE
ngxe_close(CONN)
Destroys reader, writer, closes socket and removes connection from the loop.
EXAMPLE: ECHO SERVER
A bit more complex example involving manipulation with the buffers.
use Nginx::Engine;
ngxe_init("", 0, 64),
ngxe_server("*", 55555, sub {
ngxe_reader($_[0], 0, 5000, sub {
# $_[0] - connection identifier
# $_[1] - error condition
# $_[2] - recv buffer
# $_[3] - send buffer
# @_[4..$#_] -- args, but we didn't set any
if ($_[1]) {
return;
}
# copying read buffer to the write buffer
$_[3] = $_[2];
# clearing read buffer
$_[2] = '';
# switching to writer
ngxe_reader_stop($_[0]);
ngxe_writer_start($_[0]);
});
ngxe_writer($_[0], 0, 1000, "", sub {
# $_[0] - connection identifier
# $_[1] - error condition
# $_[2] - recv buffer
# $_[3] - send buffer
# @_[4..$#_] -- args, but we didn't set any
if ($_[1]) {
return;
}
# switching back to reader
ngxe_writer_stop($_[0]);
ngxe_reader_start($_[0]);
});
ngxe_reader_start($_[0]);
});
ngxe_loop;
SEE ALSO
node.js http://nodejs.org/, nginx http://nginx.org/, POE, EV, AnyEvent
AUTHOR
Alexandr Gomoliako <zzz@zzz.org.ua>
LICENSE
Copyright 2010 Alexadnr Gomoliako. All rights reserved.
FreeBSD-like license. Take a look at LICENSE and LICENSE.nginx files.