Understanding of Io channels in glib

Source: Internet
Author: User
Tags gtk
Understanding of Io channels in glib

G_io_in There is data to read.
G_io_out Data can be written (without blocking ).
G_io_pri There is urgent data to read.
G_io_err Error condition.
G_io_hup Hung up (the connection has been broken, usually for pipes and
Sockets ).
G_io_nval Invalid request. The file descriptor is not open.

Original article:

The giochannel data type aims to provide a portable method for using File
Descriptors, pipes, and sockets, and integrating them into
Main Event loop.
Currently full support is available on UNIX platforms, though support
Windows is only partially complete.

 

To create a new giochannel on UNIX systems use g_io_channel_unix_new ().
This works for plain file descriptors, pipes and sockets.

 

Once a giochannel has been created, it can be used in a generic manner
With the functions g_io_channel_read (), g_io_channel_write (),
G_io_channel_seek (), and g_io_channel_close ().

 

To add a giochannel to
Main Event Loop
Use g_io_add_watch () or g_io_add_watch_full (). Here you specify which events
You are interested in on the giochannel, and provide a function to be
Called whenever these events occur.

 

Giochannel instances are created with an initial reference count of 1.
G_io_channel_ref () and g_io_channel_unref () can be used to increment or
Decrement the reference count respectively. When the reference count falls
To 0, the giochannel is freed. (though it isn't closed automatically .)
Using g_io_add_watch () or g_io_add_watch_full () Increments a channel's
Reference count.

 

GTK + contains the convenience function gtk_input_add_full ()
Which creates a giochannel from a file descriptor and adds it to
Main Event loop.
The event source can later be removed with gtk_input_remove ().
Similar functions can also be found in gdk.

The GUI system is event-driven. An event loop process must be used to obtain and process events. The same is true for GTK. The GTK event loop process is provided by glib, while iochannel is a means of integrating Io events into events in glib.

Iochannel can convert the events that occur on file descriptors, pipelines, and sockets specified by the developer to internal events of glib, so as to process Io events and user interaction in a unified way in the program.

Iochannel supports readable, writable, Urgent Data arrival, error, and hanging. Because iochannel is built based on file descriptors, pipelines, and sockets, the methods provided by iochannel include both the similarities and differences between the three.

So how can I add an iochannel to a program based on GTK or glib?

Generally, the steps are as follows:

1. Create a file descriptor.

You can open a common file, create a pipeline, or open a socket. The result is a file descriptor.

2. Create an iochannel and set the data encoding.

Iochannel is created using the following function:

Giochannel * g_io_channel_unix_new (int fd );

For example:

Io_channel = g_io_channel_unix_new (FD );

After creation, you can set the data encoding. I am not very clear about data encoding. Generally, I set the encoding to null so that no data is processed when I use the read/write functions provided by iochannel. The encoding setting function is as follows:

Giostatus g_io_channel_set_encoding (giochannel * channel, const gchar * encoding, gerror ** error );

For example, set the encoding to NULL:

G_io_channel_set_encoding (io_channel, null, & ERR );

3. Add the events on the file descriptor you want to process to the event loop.

Add the specified iochannel event to the event loop using the following function:

Guint g_io_add_watch (giochannel * channel, giocondition condition, giofunc func, gpointer user_data );

Giocondition includes g_io_in, g_io_out, g_io_pri, g_io_err, g_io_hup, and g_io_nval. You can specify multiple events simultaneously through their or operations. Of course, the callback function should determine which event caused the callback.

The callback function of iochannel is prototype:

Gboolean (* giofunc) (giochannel * Source, giocondition condition, gpointer data );

The second parameter is the value of the event that causes the callback.

The above step 1 serves to create a button, and step 2 serves to add an event to the event loop with g_signal_connect. To do these three jobs well, there are two more jobs:

1. Write the callback function.

In the callback function, you can use the Read and Write functions provided by iochannel, or use the file descriptor obtained by g_io_channel_unix_get_fd () to perform normal Io operations.

2. Exit the event loop and disable iochannel.

When the program ends or the file descriptor is useless, disable iochannel. You must exit the event loop before closing, and use g_source_remove (source_id) to complete the exit action. Source_id is the return value of g_io_add_watch.

Then you can close the iochannel, and use g_io_channel_shutdown (io_channel, true, null) to complete the closing action.

After the iochannel is disabled, the memory occupied by the iochannel has not been released. g_io_channel_unref (io_channel) is used to reduce the iochannel reference counter so that it is 0, and glib will automatically release the iochannel.

Based on your application, my suggestion is to use the socket file descriptor to create an iochannel after connecting to the server, and create a callback function for all events except Data writable (g_io_out, add an event loop. When data exists, it is passively read and actively sent when data is sent.

One iochannel can only be bound to one socket.

On the server side, an iochannel is created using FD (set as listen_fd) after listen.

When there is a connection, iochannel is displayed as listen_fd readable. In the callback function, accept is used to obtain a connection FD (set to connect_fd ). Create an iochannel for each connect_fd.

In short, the listen_fd callback function is used for accept; The connect_fd callback function is used for read and write, and each connect_fd callback function is the same.

Disable the iochannel after connect_fd is disabled.

You may use g_idle_add () to add a garbage collection function to disable iochannel.

Because the iochannel cannot be shutdown in the callback function of connect_fd.

The client must note that the connect timeout time is relatively long, and threads may be used to solve this problem.

If you want to implement "continuously read the serial port after the button event starts, until the serial port is shut down and the key event starts", using the while statement is not feasible. It is not feasible to add a non-blocking event only, because in the while loop, your program will not respond to the button event.

Multithreading can solve the problem, but try not to use it.

Iochannel is the most suitable. The method is roughly as follows:

1. Open the serial port in non-blocking mode. Non-blocking is required. The reason is described below.

FD = open ("/dev/ttys0", o_rdwr | o_nonblock, 0644 );

2. Create an iochannel.

Io_channel = g_io_channel_unix_new (FD );

G_io_channel_set_encoding (io_channel, null, & ERR);/* optional */

3. Add the file descriptor readable events to the program's event loop:

Source_id = g_io_add_watch (io_channel, g_io_in, read_ttys, null );

4. After completing these steps, you can use read_ttys () to read the serial port data.

You can use read () to directly read serial data, or use the iochannel provided by glib to read function reads.

However, it must be noted that the read operation can be completed only when there is no data readable in cyclic reading and an error is returned. This is because there is a buffer in the kernel. If all the data is not read at a time, you should
The data read in this callback will not be read until the next time. The data traffic of the serial port is not large. This solution is not required and may not be a problem, but it is better to be safe. Use non-blocking when opening the serial port above
The plug-in is used to complete the data.

5. When a stop read event occurs, the callback function should do the following:

* (1). Exit the event loop: g_source_remove (source_id );

* (2). Disable io_channel: g_io_channel_shutdown (io_channel, true, null );

* (3). Release io_channel: g_io_channel_unref (io_channel );

Disabling the iochannel operation will disable the file descriptor.

6. Others:

The order of enabling and disabling iochannels is unchangeable.

If you only want to temporarily not read the file, you can exit the event loop.

It is not guaranteed whether the data that comes after exiting the event loop will be cached in the kernel, or whether all the data during this period will be cached, therefore, when you exit the event loop and add data, you must check whether the data is what you need. (Not guaranteed because I have not performed any tests)

Iochannel is not a new technology. Its foundation is select/poll. Compare the event options and
What select/poll provides is clear. For select/poll, choose MAN 2 select_tut or man 2 poll.

The method mentioned above applies to other file descriptors. I used it on socket.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.