open_listen
open_listen (port, funcname[, data])
This function creates a channel to listen for incoming connections to implement a TCP service. open_listen returns a channel identifier on success that can be used in subsequent calls to open_accept. It returns -1 on failure and sets the pre-defined variable api_error to an error message describing the error.
port is the integer port on which to listen (for example, 21) or the name of the service provided, such as, “ftp”. funcname is the name of the function that can be called when a connection becomes available and must be declared as: function funcname(ch, op[, data]) where ch is the channel identifier returned by open_listen and op is an integer specifying the type of notification (which is always 0). This means that a connection is pending. data is the value of the user data argument passed to open_listen.
The callback function must call open_accept to create a channel for the new connection. As with the underlying Berkeley socket function, listen, open_listen limits the number of pending connections (the backlog) to 5.
The channel created by open_listen is non-blocking. It remains open until explicitly closed by calling close.
The example of the simple server that follows accepts and executes Arbortext Editor commands over a network channel. It uses a simple protocol where each incoming command is delimited by a CTRL+A character (“\001”) since commands may include embedded new lines. After executing the command, the server writes back the value of the predefined variable status as a string, again terminated by CTRL+A. The client should read the reply before sending another command.
package server
RE="\001"; # used as a message delimiter
function listen(port) {
local ch = open_listen(port, 'server::doaccept')
if (ch < 0) {
message "server::listen: $main::api_error"
}
return ch
}
function doaccept(ch, what) {
if (what == 0) {
local fid = open_accept(ch)
if (fid < 0) {
message "server: $main::api_error"
close(ch);
}
# set the connection to non-blocking mode
channel_set_callback(fid, 'server::notify')
}
}
function async_read(ch) {
local cmd, len
len = read(ch, cmd, 512, RE)
if (len == -2) {
return; # incomplete read
}
if (len <= 0) {
if (len == -1) {
message "server: $main::api_error"
}
close(ch)
return
}
chop(cmd); # remove RE
execute(cmd); # in context of current_doc()
# send back reply containing $status for command
write(ch, "=" . main::status . RE)
}
# Callback for I/O on server connection
function notify(ch, what) {
switch(what) {
case 0: # open
break;
case 1: #close
close (ch);
break;
case 2: # read
async_read(ch)
break;
}
}
Related Topics