I’ve been rewriting a small UDP server using GLib. I found it difficult to get started with GLib, but well worth it – the code is a lot cleaner now. One thing that took me particularly long to figure out is how to integrate listening on a UDP socket into the GLib main loop. It’s not really complicated, but the parts are scattered in different parts of the GLib and GIO API documentation.
GSocket is necessary. I want my socket to listen on IPv6 UDP. I know that assertions are not the best error handling, but they are good enough for an example. 😉
GSocket *sock; GError *err = NULL; sock = g_socket_new(G_SOCKET_FAMILY_IPV6, G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP, &err); g_assert(err == NULL);
Bind the socket (
addr is the
GInetSocketAddress* to listen on):
g_socket_bind(sock, G_SOCKET_ADDRESS(addr), TRUE, &err); g_assert(err == NULL);
Hint: if you want to listen on all interfaces, use g_inet_address_new_any() to create the
GInetAddress part of the socket’s address. Under Linux “any IPv6 address” includes IPv4, I don’t know if this applies on other platforms as well.
To get an event when the socket receives data, the following steps are necessary:
- Get a file descriptor for the socket.
- Use the file descriptor to create a
GIOChannelfor the socket.
- Add a watch for the
G_IO_INcondition on the channel.
int fd = g_socket_get_fd(sock); GIOChannel* channel = g_io_channel_unix_new(fd); guint source = g_io_add_watch(channel, G_IO_IN, (GIOFunc) callback_function, data); g_io_channel_unref(channel);
callback_function has to match the
GIOFunc pattern. It must not block, so I use it to start a thread which will do the real work. The main loop needs to be initialized before attaching the event. After the event is attached, just run the main loop (if you need more info about that, look here). Cleaning up is pretty simple: Use
g_source_remove(source) to disconnect the event source and
g_object_unref() the objects.