Re: How to use GIOChannel to read an Unix socket



On Sun, 24 Jan 2010 00:02:49 -0800
silverburgh <silverburgh meryl gmail com> wrote:
> Hi,
> 
> I create a GIOChannel which wraps around a socket on linux:
> 
> GIOChannel* channel = g_io_channel_unix_new(sock);
> g_io_add_watch(channel, G_IO_IN,
> 			gio_read_socket, NULL));
> g_io_add_watch(channel, G_IO_HUP,
> 			gio_close_socket, NULL));
> 
> And my function gio_read_socket() does get called whenever there is
> data available on the socket. And I am able to retrieve data using
> g_io_channel_read_line ().
> But when the other side of the socket get closed().  My function
> g_io_channel_read_line() get called infinite number of times with the
> number of data read = 0. Can you please tell me how can I fix my
> problem? And my function gio_close_socket() which registered for
> G_IO_HUP were never get called.
> 
> static gboolean
> gio_read_socket (GIOChannel *gio, GIOCondition condition, gpointer
> data) {
>        printf (" gio_read_socket \n");
>         GIOStatus ret;
>         GError *err = NULL;
>         gchar *msg;
>         gsize len;
> 
>         ret = g_io_channel_read_line (gio, &msg, &len, NULL, &err);
>         if (ret == G_IO_STATUS_ERROR)
>                 g_error ("Error reading: %s\n", err->message);
> 
>         printf ("Read %u bytes: %s\n", len, msg);
>         g_free (msg);
>         // Try to close the socket when nothing is there.
>         if (len == 0) {
>               close(g_io_channel_unix_get_fd(gio));
> 	      g_io_channel_close(gio);
>         }
> 
>         return TRUE;
> }

You need to check the return value of g_io_channel_read_line() for more
than just an error - in particular for G_IO_STATUS_EOF.  You also should
not normally have a separate callback for a G_IO_HUP condition because
POLL_HUP is not of itself a reliable indicator of end of file.
(Instead bitwise-or it with G_IO_IN for a single handler.)

See this for further details:
http://www.greenend.org.uk/rjk/2001/06/poll.html

Actually, you have attempted to fix your problem in a different way,
by closing the socket when the read data length is 0, assuming that you
are doing blocking reads.  However, you need to free the GIOChannel
object. The easiest way to do that is to call g_io_channel_unref() on
the GIOChannel object immediately after you have called
g_io_add_watch() on it. g_io_channel_*_new() returns a GIOChannel
object with a reference count of one.  g_io_add_watch() adds a further
reference count - if you decrement it by 1, the callback will be
disconnected and the relevant GSource object removed when the callback
returns FALSE, which it should do when it detects end-of-file, or if
you call g_source_remove() on the return value of g_io_add_watch().
(Incidentally, you are also supposed to use g_io_channel_shutdown()
rather than g_io_channel_close(), but that of itself is not sufficient
to free the GIOCondition object and it is not necessary anyway in this
usage.)  I agree that the documentation on this isn't very good.

Chris




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]