Non-blocking socket communication with GIO

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

Non-blocking socket communication with GIO

Gergely Polonkai

Hello,

i’m working on an app that communicates with a network service using a
custom binary protocol.  For that i have a GSocketClient.  The
destination can, in theory, be either a TCP/IP or a UNIX socket (only
TCP/IP is implemented yet).  I initiate the connection like this:

    scuttler->socket_client = g_socket_client_new();

    address = g_inet_address_new_from_string("127.0.0.1");
    destination = g_inet_socket_address_new(address, 8008);
    g_object_unref(address);

    g_task_set_task_data(task, g_object_ref(scuttler), (GDestroyNotify)g_object_unref);

    g_socket_client_connect_async(scuttler->socket_client, G_SOCKET_CONNECTABLE(destination), cancellable, connection_finished, task);

Then, in connecion_finished(), among other things, i do this:

    scuttler->connection = connection;

    if (!ssb_scuttler_shs_connect(scuttler, &err)) {
        g_task_return_error(task, err);
        g_object_unref(task);

        return;
    }

    socket = g_socket_connection_get_socket(connection);
    g_socket_set_blocking(socket, FALSE);
    socket_source = g_socket_create_source(socket, G_IO_IN | G_IO_PRI, NULL);
    g_source_set_callback(socket_source,
                          (GSourceFunc)read_inbound,
                          g_object_ref(scuttler), g_object_unref);
    g_source_attach(socket_source, g_main_context_get_thread_default());

However, my read_inbound() function never gets called, even though my
request ends up in the server (i can see it in the logs).  Am i missing
something fundamental here?

(Also, this is not really GTK, but more like GLib/GIO specific; if there
is a better mailing list to send this, please advise.)

Best,
Gergely
_______________________________________________
gtk-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/gtk-list
Reply | Threaded
Open this post in threaded view
|

Re: Non-blocking socket communication with GIO

Gergely Polonkai
Hello,

yes, the first two bytes of the response is the message length. If i explicitly read exactly two bytes (to get the message length) and then explicitly read that many bytes to get the response, i’m fine.

What is not working as i expected is the polling. I thought that if i

* set the socket to non-blocking (g_socket_set_blocking())
* create a source for the socket with the G_IO_IN and G_IO_PRI flags (inbound data + priority inbound data, although i’m pretty sure priority inbound doesn’t happen on this protocol)
* set a callback function with g_source_set_callback()

then my callback will be called whenever there is data available. At least that’s what i’d do if i’d be using plain Linux sockets, using select()/poll()/epoll().

Best,
Gergely

mið., 23. jan. 2019 kl. 10:48 skrifaði Göran Hasse <[hidden email]>:
Den 2019-01-10 kl. 15:02, skrev Gergely Polonkai:
>
> Hello,

Hello,

First. If you ar using a binary protocol - how do you recognise the
frame?

All socket reading sould recognice a frame header, where the size of
the frame is stated and then read that amount of bytes. An alternative
is to read one byte at a time and try to figure out when you have a
frame end.

/gh


>
> i’m working on an app that communicates with a network service using a
> custom binary protocol.  For that i have a GSocketClient.  The
> destination can, in theory, be either a TCP/IP or a UNIX socket (only
> TCP/IP is implemented yet).  I initiate the connection like this:
>
>      scuttler->socket_client = g_socket_client_new();
>
>      address = g_inet_address_new_from_string("127.0.0.1");
>      destination = g_inet_socket_address_new(address, 8008);
>      g_object_unref(address);
>
>      g_task_set_task_data(task, g_object_ref(scuttler), (GDestroyNotify)g_object_unref);
>
>      g_socket_client_connect_async(scuttler->socket_client, G_SOCKET_CONNECTABLE(destination), cancellable, connection_finished, task);
>
> Then, in connecion_finished(), among other things, i do this:
>
>      scuttler->connection = connection;
>
>      if (!ssb_scuttler_shs_connect(scuttler, &err)) {
>          g_task_return_error(task, err);
>          g_object_unref(task);
>
>          return;
>      }
>
>      socket = g_socket_connection_get_socket(connection);
>      g_socket_set_blocking(socket, FALSE);
>      socket_source = g_socket_create_source(socket, G_IO_IN | G_IO_PRI, NULL);
>      g_source_set_callback(socket_source,
>                            (GSourceFunc)read_inbound,
>                            g_object_ref(scuttler), g_object_unref);
>      g_source_attach(socket_source, g_main_context_get_thread_default());
>
> However, my read_inbound() function never gets called, even though my
> request ends up in the server (i can see it in the logs).  Am i missing
> something fundamental here?
>
> (Also, this is not really GTK, but more like GLib/GIO specific; if there
> is a better mailing list to send this, please advise.)
>
> Best,
> Gergely
> _______________________________________________
> gtk-list mailing list
> [hidden email]
> https://mail.gnome.org/mailman/listinfo/gtk-list
>


--
-----------------------------
Göran Hasse
Raditex Control AB
http://www.rscada.se http://www.raditex.nu
Boo 229, 715 91 ODENSBACKEN
Phone: +46 19 450105
Mobile: 070-5530148



_______________________________________________
gtk-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/gtk-list
Reply | Threaded
Open this post in threaded view
|

Re: Non-blocking socket communication with GIO

Gtk+ - General mailing list
On Wed, 23 Jan 2019 13:34:08 +0100
Gergely Polonkai <[hidden email]> wrote:

> Hello,
>
> yes, the first two bytes of the response is the message length. If i
> explicitly read exactly two bytes (to get the message length) and then
> explicitly read that many bytes to get the response, i’m fine.
>
> What is not working as i expected is the polling. I thought that if i
>
> * set the socket to non-blocking (g_socket_set_blocking())
> * create a source for the socket with the G_IO_IN and G_IO_PRI flags
> (inbound data + priority inbound data, although i’m pretty sure priority
> inbound doesn’t happen on this protocol)
> * set a callback function with g_source_set_callback()
>
> then my callback will be called whenever there is data available. At least
> that’s what i’d do if i’d be using plain Linux sockets, using
> select()/poll()/epoll().

glib file descriptor polling works in the way you describe - on
unix-like systems it is a front end for poll().  Is your callback
returning TRUE or G_SOURCE_CONTINUE?  If it isn't, after the first read
the source will be removed.

I know the documentation says that there is no need to apply the
G_IO_HUP flag but I would still add it and see if it makes a
difference, should an end-of-file event be missing.
_______________________________________________
gtk-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/gtk-list