Boostez la puissance de C avec ces bibliothèques open source

Le Système d’objet GLib (GObject) est une bibliothèque fournissant un framework orienté objet flexible et extensible pour C. Dans cet article, je démontre l’utilisation de la version 2.4 de la bibliothèque.
Les bibliothèques GObject étendent la norme ANSI C, avec des typedefs pour les types courants tels que :
- gchar: un type de caractère
- guchar: un type de caractère non signé
- gunichar: un type unichar fixe de 32 bits de largeur
- gbooléen: un type booléen
- gint8, gint16, gint32, gint64: Entiers 8, 16, 32 et 64 bits
- guint8, guint16, guint32, guint64: entiers non signés de 8, 16, 32 et 64 bits
- flotteur: un nombre à virgule flottante simple précision conforme à la norme IEEE 754
- gdouble: un nombre à virgule flottante double précision conforme à la norme IEEE 754
- gpointeur: un type de pointeur générique
Contents
Pointeurs de fonction
GObject introduit également un système de types et d’objets avec des classes et des interfaces. Cela est possible car le langage ANSI C comprend les pointeurs de fonction.
Pour déclarer un pointeur de fonction, vous pouvez faire ceci :
void (*my_callback)(gpointer data);
Mais d’abord, vous devez attribuer le my_callback
variable:
void my_callback_func(gpointer data)
{
//do something
}my_callback = my_callback_func;
Le pointeur de fonction my_callback
peut être invoqué comme ceci :
gpointer data;
data = g_malloc(512 * sizeof(gint16));
my_callback(data);
Classes d’objets
La classe de base GObject se compose de 2 structures (GObject
et GObjectClass
) dont vous héritez pour implémenter vos propres objets.
Vous intégrez GObject et GObjectClass comme premier champ struct :
struct _MyObject
{
GObject gobject;
//your fields
};struct _MyObjectClass
{
GObjectClass gobject;
//your class methods
};GType my_object_get_type(void);
L’implémentation de l’objet contient des champs, qui peuvent être exposés en tant que propriétés. GObject fournit également une solution aux champs privés. Il s’agit en fait d’une structure dans le fichier source C, au lieu du fichier d’en-tête. La classe contient généralement uniquement des pointeurs de fonction.
Une interface ne peut pas être dérivée d’une autre interface et est implémentée comme suit :
struct _MyInterface
{
GInterface ginterface;
//your interface methods
};
Les propriétés sont accessibles par g_object_get()
et g_object_set()
appels de fonction. Pour obtenir une propriété, vous devez fournir l’emplacement de retour du type spécifique. Il est recommandé d’initialiser d’abord l’emplacement de retour :
gchar *strstr = NULL;
g_object_get(gobject,
"my-name", &str,
NULL);
Ou vous pouvez définir la propriété :
g_object_set(gobject,
"my-name", "Anderson",
NULL);
La bibliothèque HTTP libsoup
Le libsoup
Le projet fournit une bibliothèque client et serveur HTTP pour GNOME. Il utilise GObjects et la boucle principale glib pour s’intégrer aux applications GNOME, et dispose également d’une API synchrone à utiliser dans les outils de ligne de commande. Tout d’abord, créez un libsoup
session avec un rappel d’authentification spécifié. Vous pouvez également utiliser des cookies.
SoupSession *soup_session;
SoupCookieJar *jar;soup_session = soup_session_new_with_options(SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_AUTH_BASIC,
SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_AUTH_DIGEST,
NULL);jar = soup_cookie_jar_text_new("cookies.txt",
FALSE);soup_session_add_feature(soup_session, jar);
g_signal_connect(soup_session, "authenticate",
G_CALLBACK(my_authenticate_callback), NULL);
Ensuite, vous pouvez créer une requête HTTP GET comme suit :
SoupMessage *msg;
SoupMessageHeaders *response_headers;
SoupMessageBody *response_body;
guint status;
GError *error;msg = soup_form_request_new("GET",
"http://127.0.0.1:8080/my-xmlrpc",
NULL);status = soup_session_send_message(soup_session,
msg);response_headers = NULL;
response_body = NULL;g_object_get(msg,
"response-headers", &response_headers,
"response-body", &response_body,
NULL);g_message("status %d", status);
cookie = NULL;
soup_message_headers_iter_init(&iter,
response_headers);while(soup_message_headers_iter_next(&iter, &name, &value)){
g_message("%s: %s", name, value);
}g_message("%s", response_body->data);
if(status == 200){
cookie = soup_cookies_from_response(msg);
while(cookie != NULL){
char *cookie_name;
cookie_name = soup_cookie_get_name(cookie->data);
//parse cookies
cookie = cookie->next;
}
}
Le rappel d’authentification est appelé lorsque le serveur Web demande une authentification.
Voici une signature de fonction :
#define MY_AUTHENTICATE_LOGIN "my-username"
#define MY_AUTHENTICATE_PASSWORD "my-password"void my_authenticate_callback(SoupSession *session,
SoupMessage *msg,
SoupAuth *auth,
gboolean retrying,
gpointer user_data)
{
g_message("authenticate: ****");
soup_auth_authenticate(auth,
MY_AUTHENTICATE_LOGIN,
MY_AUTHENTICATE_PASSWORD);
}
Un serveur libsoup
Pour que l’authentification HTTP de base fonctionne, vous devez spécifier un chemin de rappel et de contexte de serveur. Ensuite, vous ajoutez un gestionnaire avec un autre rappel.
Cet exemple écoute n’importe quelle adresse IPv4 sur le port 8080 de l’hôte local :
SoupServer *soup_server;
SoupAuthDomain *auth_domain;
GSocket *ip4_socket;
GSocketAddress *ip4_address;
MyObject *my_object;
GError *error;soup_server = soup_server_new(NULL);
auth_domain = soup_auth_domain_basic_new(SOUP_AUTH_DOMAIN_REALM, "my-realm",
SOUP_AUTH_DOMAIN_BASIC_AUTH_CALLBACK, my_xmlrpc_server_auth_callback,
SOUP_AUTH_DOMAIN_BASIC_AUTH_DATA, my_object,
SOUP_AUTH_DOMAIN_ADD_PATH, "my-xmlrpc",
NULL);soup_server_add_auth_domain(soup_server, auth_domain);
soup_server_add_handler(soup_server,
"my-xmlrpc",
my_xmlrpc_server_callback,
my_object,
NULL);ip4_socket = g_socket_new(G_SOCKET_FAMILY_IPV4,
G_SOCKET_TYPE_STREAM,
G_SOCKET_PROTOCOL_TCP,
&error);ip4_address = g_inet_socket_address_new(g_inet_address_new_any(G_SOCKET_FAMILY_IPV4),
8080);
error = NULL;
g_socket_bind(ip4_socket,
ip4_address,
TRUE,
&error);
error = NULL;
g_socket_listen(ip4_socket, &error);error = NULL;
soup_server_listen_socket(soup_server,
ip4_socket, 0, &error);
Dans cet exemple de code, il y a deux rappels. L’un gère l’authentification et l’autre gère la demande elle-même.
Supposons que vous souhaitiez qu’un serveur Web autorise une connexion avec le nom d’utilisateur des informations d’identification Mon nom d’utilisateur et le mot de passe mon mot de passeet pour définir un cookie de session avec une chaîne d’ID utilisateur unique (UUID) aléatoire.
gboolean my_xmlrpc_server_auth_callback(SoupAuthDomain *domain,
SoupMessage *msg,
const char *username,
const char *password,
MyObject *my_object)
{
if(username == NULL || password == NULL){
return(FALSE);
}if(!strcmp(username, "my-username") &&
!strcmp(password, "my-password")){
SoupCookie *session_cookie;
GSList *cookie;
gchar *security_token;
cookie = NULL;security_token = g_uuid_string_random();
session_cookie = soup_cookie_new("my-srv-security-token",
security_token,
"localhost",
"my-xmlrpc",
-1);cookie = g_slist_prepend(cookie,
session_cookie);
soup_cookies_to_request(cookie,
msg);
return(TRUE);
}
return(FALSE);
}
Un gestionnaire pour le chemin de contexte mon-xmlrpc:
void my_xmlrpc_server_callback(SoupServer *soup_server,
SoupMessage *msg,
const char *path,
GHashTable *query,
SoupClientContext *client,
MyObject *my_object)
{
GSList *cookie;
cookie = soup_cookies_from_request(msg);
//check cookies
}
Un C plus puissant
J’espère que mes exemples montrent comment les projets GObject et libsoup donnent un coup de pouce très réel au C. Des bibliothèques comme celles-ci étendent C au sens littéral et, ce faisant, elles rendent C plus accessible. Ils font beaucoup de travail pour vous, vous pouvez donc vous concentrer sur l’invention d’applications étonnantes dans le langage C simple, direct et intemporel.