Module NetchannelsSource
Object-oriented I/O: Basic types and classes * * Contents * * - Types * - Input channels * - Output channels * - Delegation classes * - Lifting channels * - Channels over descriptors * - Transactional channels * - Pipes and Filters *
* * The tutorial has been moved to Netchannels_tut.
Types
There are three levels of class types for channels: * - rec_in_channel and rec_out_channel: Primitive, but standardized level * - raw_in_channel and raw_out_channel: Unix level * - in_obj_channel and out_obj_channel: Application level * * The "rec" level has been recently introduced to improve interoperability * with other libraries (e.g. camomile). The idea is to standardize the * real core methods of I/O, so they have the same meaning in all libraries. * Read * "Basic I/O class types" * for more. * * The "raw" level represents the level of Unix file descriptors. * * The application level is what should be used in programs. In addition * to the "raw" level one can find a number of convenience methods, * e.g. input_line to read a line from the channel. The downside is that * these methods usually work only for blocking I/O. * * One can lower the level by coercion, e.g. to turn an in_obj_channel * into a rec_in_channel, apply the function * * (fun ch -> (ch : in_obj_channel :> rec_in_channel)) * * To higher the level, apply lift_in or lift_out, defined below.
Interface changes: Since ocamlnet-0.98, the semantics of * the methods input and output has slightly changed. When the end * of the channel is reached, input raises now End_of_file. In previous * releases of ocamlnet, the value 0 was returned. When the channel cannot * process data, but is in non-blocking mode, both methods now return the * value 0. In previous releases of ocamlnet, the behaviour was not * defined. * * Ocamlnet-3.0 changed the behavior of close_out. Errors are no longer * reported - instead, the exception is logged to Netlog. For a stricter * error handling, it is suggested to call flush first. Also, close_in * and close_out no longer raise Closed_channel when the channel is * already closed. Read more about this in the section * Netchannels.rec_out_channel.close_error.
Sourceexception Closed_channel Raised when channel operations are called when the channel is closed
Sourceexception Buffer_underrun Raised by input methods if the internal buffer of the channel is too * empty to read even one byte of data. * This exception is only used by certain implementations of channel * classes.
Sourceexception Command_failure of Unix.process_status Raised by close_in or close_out if the channel is connected with * another process, and the execution of that process fails.
Recommended input class type for library interoperability.
Basic Unix-level class type for input channels as used by ocamlnet. In addition * to the recommended standard, ocamlnet always support a position counter
Recommended output class type for library interoperability.
Basic Unix-level class type for output channels as used by ocamlnet. In addition * to the recommended standard, ocamlnet always support a position counter
A channel supporting both input and output. The input and output * aspects are strictly separated
Further methods usually supported by ocamlnet channel implementations. * These methods are only reasonable when the channel is of blocking type, * i.e. waits for input when not enough data are available to perform an * operation. Implementations may choose to fail when they detect the * channel is non-blocking.
The application-level input channel supports raw and complemented methods
Further methods usually supported by ocamlnet channel implementations. * These methods are only reasonable when the channel is of blocking type, * i.e. waits for output readiness when the underlying resource currently * cannot process enough data. Implementations may choose to fail when they * detect the channel is non-blocking.
The application-level output channel supports raw and complemented methods
A channel supporting both input and output. The input and output * aspects are strictly separated
A transactional output channel has a buffer for uncommitted data. * This means that all data written to this channel is collected in the * buffer until either commit_work or rollback_work is called. * * When the channel is closed, the buffer may optionally be committed. * This is implementation-defined. * * The method flush does not have any effect on the transaction * buffer.
Creates an input channel from an in_channel, which must be open. * * The method pos_in reflects the real position in the channel as * returned by Pervasives.pos_in. This works for both seekable and * non-seekable channels. * * The method close_in also closes the underlying in_channel. * * The function onclose is called after the in_channel has been closed.
Runs the command with /bin/sh, and reads the data the command prints * to stdout. * * The method pos_in returns the number of read octets. * * When close_in is invoked, the subprocess is waited for. If the * process exits with code 0, the method returns normally. Otherwise, * the exception Command_failure is raised.
Creates an input channel from a (constant) string. * * The method pos_in reflects the real position in the string, i.e. * a character read at position k can be found at s.[k] in the string * s. * *
Same for tagged strings (only as function)
Creates an input channel and a shutdown function for a netbuffer. * This is a destructive * implementation: Every time data is read, the octets are taken from the * beginning of the netbuffer, and they are deleted from the netbuffer * (recall that a netbuffer works like a queue of characters). * * Conversely, the user of this class may add new data to the netbuffer * at any time. When the shutdown function is called, the EOF condition * is recorded, and no further data must be added. * * If the netbuffer becomes empty, the input methods raise Buffer_underrun * when the EOF condition has not yet been set, and they raise * End_of_file when the EOF condition has been recorded. * * keep_data: do not delete read data from the buffer
Creates a lexical buffer from an input channel. The input channel * is not closed when the end is reached * * This function does not work for non-blocking channels.
Reads from the input channel until EOF and returns the characters * as string. The input channel is not closed. * * This function does not work for non-blocking channels.
Reads from the input channel until EOF and returns the lines * as string list. The input channel is not closed. * * This function does not work for non-blocking channels.
with_in_obj_channel ch f: * Computes f ch and closes ch. If an exception happens, the channel is * closed, too.
Output channels
Creates an output channel writing into an out_channel. * * The method pos_out reflects the real position in the channel as * returned by Pervasives.pos_out. This works for both seekable and * non-seekable channels. * * The method close_out also closes the underlying out_channel. * There is some implicit logic to either use close_out or close_out_noerr * depending on whether the immediately preceding operation already reported * an error. * *
Runs the command with /bin/sh, and data written to the channel is * piped to stdin of the command. * * The method pos_out returns the number of written octets. * * When close_out is invoked, the subprocess is waited for. If the * process exits with code 0, the method returns normally. Otherwise, * the exception Command_failure is raised. (The channel is closed * even if this exception is raised.) * *
This output channel writes the data into the passed buffer. * * The method pos_out returns the number of written octets. * *
This output channel writes the data into the passed netbuffer. * * The method pos_out returns the number of written octets. * *
This output channel discards all written data. * * The method pos_out returns the number of discarded bytes. * *
with_out_obj_channel ch f: * Computes f ch and closes ch. If an exception happens, the channel is * closed, too.
Delegation classes
Delegation classes just forward method calls to an parameter * object, i.e. when method m of the delegation class is called, * the definition of m is just to call the method with the same * name m of the parameter object. This is very useful in order * to redefine methods individually. * * For example, to redefine the method pos_in of an in_obj_channel, * use *
* class my_channel = object(self)
* inherit in_obj_channel_delegation ...
* method pos_in = ...
* end
*
* * As a special feature, the following delegation classes can suppress * the delegation of close_in or close_out, whatever applies. * Just pass close:false to get this effect, e.g. *
* class input_channel_don't_close c =
* in_obj_channel_delegation ~close:false (new input_channel c)
*
* This class does not close c : in_channel when the close_in * method is called.
Description * * This class type is defined in * "Basic I/O class types" * as collaborative effort of several library creators.
Description * * This class type is defined in * "Basic I/O class types" * as collaborative effort of several library creators.
Lifting channels
The following classes and functions add missing methods to reach * a higher level in the hierarchy of channel class types. For most * uses, the lift_in and lift_out functions work best.
Turns a rec_in_channel or raw_in_channel, depending on the passed * variant, into a full in_obj_channel object. (This is a convenience * function, you can also use the classes below directly.) If you * want to define a class for the lifted object, use *
* class lifted_ch ... =
* in_obj_channel_delegation (lift_in ...)
*
* *
Turns a rec_out_channel or raw_out_channel, depending on the passed * variant, into a full out_obj_channel object. (This is a convenience * function, you can also use the classes below directly.) If you * want to define a class for the lifted object, use *
* class lifted_ch ... =
* out_obj_channel_delegation (lift_out ...)
*
* *
This class implements the methods from compl_in_channel by calling * the methods of raw_in_channel. There is no additional buffering. * The performance of the method input_line is very bad (consider * to override it, e.g. by enhanced_input_line as defined below).
This class implements pos_in and the methods from compl_in_channel * by calling the methods of rec_in_channel. * There is no additional buffering. * * The performance of the method input_line is very bad (consider * to override it, e.g. by enhanced_input_line as defined below). * * The method pos_in is implemented by counting the number of octets * read by the input method. * *
This class implements the methods from compl_out_channel by calling * the methods of raw_out_channel. There is no additional buffering.
This class implements the methods from compl_out_channel by calling * the methods of raw_out_channel. There is no additional buffering.
This class implements pos_out and the methods from compl_out_channel * by calling the methods of rec_out_channel. * There is no additional buffering. * * The method pos_out is implemented by counting the number of octets * read by the output method. * *
This type is for the method enhanced_input of enhanced_raw_in_channel. * - `Data n means that n bytes have been copied to the target string * - `Separator s means that no bytes have been copied, but that an * end-of-line separator s has been found
Defines private methods reading text line by line
This class adds a buffer to the underlying raw_in_channel. * As additional feature, the method enhanced_input_line is a fast * version of input_line that profits from the buffer. * *
This class adds a buffer to the underlying raw_out_channel. * *
Channels over descriptors
Creates a raw_in_channel for the passed file descriptor, which must * be open for reading. * * The pos_in method returns logical positions, i.e. it counts the number * of read octets. It is not tried to determine the real file position. * * The method close_in also closes the file descriptor. * * This class also supports Win32 proxy descriptors referring to an input * channel. * *
Creates a raw_out_channel for the passed file descriptor, which must * be open for writing. * * The pos_out method returns logical positions, i.e. it counts the number * of written octets. It is not tried to determine the real file position. * * The method close_out also closes the file descriptor. * * This class also supports Win32 proxy descriptors referring to an output * channel. * *
Creates a raw_io_channel for the passed socket descriptor, which must * be open for reading and writing, and not yet shut down in either * direction. The raw_io_channel is used to represent a bidirectional * channel: close_out shuts the socket down for sending, close_in * shuts the socket down for reading, and when both directions are down, * the descriptor is closed. * * The pos_in and pos_out methods returns logical positions. * * This class supports sockets and Win32 named pipes. Note, however, * that for Win32 named pipes it is not possible to shut down only one * direction of the bidirectional data channel. * *
Transactional channels
Sourcetype close_mode = [ | `Commit| `Rollback
] Whether a close_out implies a commit or rollback operation
A transactional output channel with a transaction buffer implemented * in memory * *
Sourceval make_temporary_file :
?mode:int ->
?limit:int ->
?tmp_directory:string ->
?tmp_prefix:string ->
unit ->
string * in_channel * out_channel Creates a temporary file in the directory tmp_directory with a name * prefix tmp_prefix and a unique suffix. The function returns * the triple (name, inch, outch) containing the file name, * the file opened as in_channel inch and as out_channel outch. * *
A transactional output channel with a transaction buffer implemented * as temporary file * *
Pipes and Filters
Note that this has nothing to do with "pipes" on the Unix level. * It is, however, the same idea: Connecting two I/O resources with an * intermediate buffer.
A pipe has two internal buffers (realized by Netbuffer). The * output methods of the class write to the incoming buffer. When * new data are appended to the incoming buffer, the conversion function * conv is called; the arguments are the incoming buffer and the outgoing * buffer. The conversion function must convert the data available in the * incoming buffer and append the result to the outgoing buffer. Finally, * the input methods of the class return the data found in the outgoing * buffer. * * The conversion function is called as follows: * conv incoming_buffer at_eof outgoing_buffer * * The conversion function is allowed to do nothing if the incoming data * are not complete enough to be converted. It is also allowed to convert * only the beginning of the incoming buffer. * * If the outgoing buffer is empty, the input methods will raise * Buffer_underrun. * * If close_out is invoked, the end of the data stream will be recorded. * In this case, the conversion function is called with at_eof = true, * and it is expected that this function converts the whole data found * in the incoming buffer. * * close_in implies close_out. * * The conversion function may raise exceptions. The exceptions will * fall through to the caller of the input methods. (The output methods * and close_in, close_out never fail because of such exceptions.) * * The default conversion function copies everything from the incoming * buffer to the outgoing buffer without modification.
An output_filter filters the data written to it through the * io_obj_channel (usually a pipe), and writes the filtered data * to the passed out_obj_channel. * * If the filter is closed, the io_obj_channel will be closed, too, * but not the destination out_obj_channel (so you can still append * further data).
An input_filter filters the data read from it through the * io_obj_channel (usually a pipe after the data have been * retrieved from the passed in_obj_channel. * * An input_filter object never generates Buffer_underrun exceptions. * However, if the passed in_obj_channel or io_obj_channel raises such * an exception, the exception will fall through the calling chain. * * If the filter is closed, the io_obj_channel will be closed, too, * but not the source in_obj_channel (so you can still read further * data from it).
Notes, Examples
If you have the choice, prefer output_filter over input_filter. * The latter is slower. * * The primary application of filters is to encode or decode a channel * on the fly. For example, the following lines write a BASE64-encoded file: * *
let ch = new output_channel (open_out "file.b64") in
* let encoder = new Netencoding.Base64.encoding_pipe ~linelength:76 () in
* let ch' = new output_filter encoder ch in
* ... (* write to ch' *)
* ch' # close_out();
* ch # close_out(); (* you must close both channels! *)
*
* * All bytes written to ch' are BASE64-encoded and the encoded bytes are * written to ch. * * There are also pipes to decode BASE64, and to encode and decode the * "Quoted printable" format. Encoding and decoding work even if the * data is delivered in disadvantageous chunks, because the data is * "re-chunked" if needed. For example, BASE64 would require that data * arrive in multiples of three bytes, and to cope with that, the BASE64 pipe * only processes the prefix of the input buffer that is a multiple of three, * and defers the encoding of the extra bytes till the next opportunity.