Plasma GitLab Archive
Projects Blog Knowledge

Module Netchannels


module Netchannels: sig .. end
Object-oriented I/O: Basic types and classes

Contents

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 How to close channels in case of errors.

exception Closed_channel
Raised when channel operations are called when the channel is closed
exception 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.
exception 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.
class type rec_in_channel = object .. end
Recommended input class type for library interoperability.
class type raw_in_channel = object .. end
Basic Unix-level class type for input channels as used by ocamlnet.
class type rec_out_channel = object .. end
Recommended output class type for library interoperability.
class type raw_out_channel = object .. end
Basic Unix-level class type for output channels as used by ocamlnet.
class type raw_io_channel = object .. end
A channel supporting both input and output.
class type compl_in_channel = object .. end
Further methods usually supported by ocamlnet channel implementations.
class type in_obj_channel = object .. end
The application-level input channel supports raw and complemented methods
class type compl_out_channel = object .. end
Further methods usually supported by ocamlnet channel implementations.
class type out_obj_channel = object .. end
The application-level output channel supports raw and complemented methods
class type io_obj_channel = object .. end
A channel supporting both input and output.
class type trans_out_obj_channel = object .. end
A transactional output channel has a buffer for uncommitted data.

Input channels


class input_channel : Pervasives.in_channel -> in_obj_channel
Creates an input channel from an in_channel, which must be open.
class input_command : string -> in_obj_channel
Runs the command with /bin/sh, and reads the data the command prints to stdout.
class input_string : ?pos:int -> ?len:int -> string -> in_obj_channel
Creates an input channel from a (constant) string.
val create_input_netbuffer : Netbuffer.t -> in_obj_channel * (unit -> unit)
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.

val lexbuf_of_in_obj_channel : in_obj_channel -> Lexing.lexbuf
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.

val string_of_in_obj_channel : in_obj_channel -> string
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.

val with_in_obj_channel : (#in_obj_channel as 'a) -> ('a -> 'b) -> 'b
with_in_obj_channel ch f: Computes f ch and closes ch. If an exception happens, the channel is closed, too.

Output channels


class output_channel : ?onclose:unit -> unit -> Pervasives.out_channel -> out_obj_channel
Creates an output channel writing into an out_channel.
class output_command : ?onclose:unit -> unit -> string -> out_obj_channel
Runs the command with /bin/sh, and data written to the channel is piped to stdin of the command.
class output_buffer : ?onclose:unit -> unit -> Buffer.t -> out_obj_channel
This output channel writes the data into the passed buffer.
class output_netbuffer : ?onclose:unit -> unit -> Netbuffer.t -> out_obj_channel
This output channel writes the data into the passed netbuffer.
class output_null : ?onclose:unit -> unit -> unit -> out_obj_channel
This output channel discards all written data.
val with_out_obj_channel : (#out_obj_channel as 'a) -> ('a -> 'b) -> 'b
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.
class rec_in_channel_delegation : ?close:bool -> rec_in_channel -> rec_in_channel
class raw_in_channel_delegation : ?close:bool -> raw_in_channel -> raw_in_channel
class in_obj_channel_delegation : ?close:bool -> in_obj_channel -> in_obj_channel
class rec_out_channel_delegation : ?close:bool -> rec_out_channel -> rec_out_channel
class raw_out_channel_delegation : ?close:bool -> raw_out_channel -> raw_out_channel
class out_obj_channel_delegation : ?close:bool -> out_obj_channel -> out_obj_channel

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.
val lift_in : ?eol:string list ->
?buffered:bool ->
?buffer_size:int ->
[ `Raw of raw_in_channel | `Rec of rec_in_channel ] ->
in_obj_channel
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 ...)
 


eol : The accepted end-of-line delimiters. The method input_line recognizes any of the passed strings as EOL delimiters. When more than one delimiter matches, the longest is taken. Defaults to ["\n"] . The default cannot be changed when buffered=false (would raise Invalid_argument). The delimiter strings must neither be empty, nor longer than buffer_size.
buffered : Whether a buffer is added, by default true
buffer_size : The size of the buffer, if any, by default 4096
val lift_out : ?buffered:bool ->
?buffer_size:int ->
[ `Raw of raw_out_channel | `Rec of rec_out_channel ] ->
out_obj_channel
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 ...)
 


buffered : Whether a buffer is added, by default true
buffer_size : The size of the buffer, if any, by default 4096
class virtual augment_raw_in_channel : object .. end
This class implements the methods from compl_in_channel by calling the methods of raw_in_channel.
class lift_rec_in_channel : ?start_pos_in:int -> rec_in_channel -> in_obj_channel
This class implements pos_in and the methods from compl_in_channel by calling the methods of rec_in_channel.
class virtual augment_raw_out_channel : object .. end
This class implements the methods from compl_out_channel by calling the methods of raw_out_channel.
class lift_raw_out_channel : raw_out_channel -> out_obj_channel
This class implements the methods from compl_out_channel by calling the methods of raw_out_channel.
class lift_rec_out_channel : ?start_pos_out:int -> rec_out_channel -> out_obj_channel
This class implements pos_out and the methods from compl_out_channel by calling the methods of rec_out_channel.
type input_result = [ `Data of int | `Separator of string ] 
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

class type enhanced_raw_in_channel = object .. end
Defines private methods reading text line by line
class buffered_raw_in_channel : ?eol:string list -> ?buffer_size:int -> raw_in_channel -> enhanced_raw_in_channel
This class adds a buffer to the underlying raw_in_channel.
class buffered_raw_out_channel : ?buffer_size:int -> raw_out_channel -> raw_out_channel
This class adds a buffer to the underlying raw_out_channel.

Channels over descriptors


class input_descr : ?blocking:bool -> ?start_pos_in:int -> Unix.file_descr -> raw_in_channel
Creates a raw_in_channel for the passed file descriptor, which must be open for reading.
class output_descr : ?blocking:bool -> ?start_pos_out:int -> Unix.file_descr -> raw_out_channel
Creates a raw_out_channel for the passed file descriptor, which must be open for writing.
class socket_descr : ?blocking:bool -> ?start_pos_in:int -> ?start_pos_out:int -> Unix.file_descr -> raw_io_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.

Transactional channels


type close_mode = [ `Commit | `Rollback ] 
Whether a close_out implies a commit or rollback operation
class buffered_trans_channel : ?close_mode:close_mode -> out_obj_channel -> trans_out_obj_channel
A transactional output channel with a transaction buffer implemented in memory
val make_temporary_file : ?mode:int ->
?limit:int ->
?tmp_directory:string ->
?tmp_prefix:string ->
unit -> string * Pervasives.in_channel * Pervasives.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.


mode : The creation mask of the file; defaults to 0o600, i.e. the file is private for the current user
limit : Limits the number of trials to find the unique suffix. Defaults to 1000.
tmp_directory : By default the current directory
tmp_prefix : By default "netstring". It is better to have a prefix that is likely to be unique, e.g. the process ID, or the current time.
class tempfile_trans_channel : ?close_mode:close_mode -> ?tmp_directory:string -> ?tmp_prefix:string -> out_obj_channel -> trans_out_obj_channel
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.
class pipe : ?conv:Netbuffer.t -> bool -> Netbuffer.t -> unit -> ?buffer_size:int -> unit -> io_obj_channel
A pipe has two internal buffers (realized by Netbuffer).
class output_filter : io_obj_channel -> out_obj_channel -> out_obj_channel
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.
class input_filter : in_obj_channel -> io_obj_channel -> in_obj_channel
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.

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.

This web site is published by Informatikbüro Gerd Stolpmann
Powered by Caml