GIO socket-server / -client 示例

Posted

技术标签:

【中文标题】GIO socket-server / -client 示例【英文标题】:GIO socket-server / -client example 【发布时间】:2012-03-19 18:39:36 【问题描述】:

我想创建一个使用 GIO 通过套接字进行通信的服务器和客户端应用程序。 GSocketService 和 GSocketClient 似乎非常适合此目的,但不幸的是我找不到一些教程或示例代码(GLib,GIO,......新手可以理解)。有人知道一些好的资源或可以在这里发布示例代码吗?

【问题讨论】:

你有进步吗?我正在寻找同样的东西。除了API 和这个SO answer 我什么都没找到。 @noisebleed:是的,我确实取得了进展。我实际上不明白为什么我在第一次尝试时无法同时创建服务器和客户端。可能我不应该尝试同时学习 C、glib 和 OGRE。 现在寻找任何 gio 示例的第一个地方是 glib 存储库的 gio/tests。那里有套接字示例。 【参考方案1】:

我终于设法使用 glib 和 gio 创建了一个简单的服务器和客户端。 我的服务器如下所示:

#include <glib.h>
#include <gio/gio.h>

/* this function will get called everytime a client attempts to connect */
gboolean
incoming_callback  (GSocketService *service,
                    GSocketConnection *connection,
                    GObject *source_object,
                    gpointer user_data)

  g_print("Received Connection from client!\n");
  GInputStream * istream = g_io_stream_get_input_stream (G_IO_STREAM (connection));
  gchar message[1024];
  g_input_stream_read  (istream,
                        message,
                        1024,
                        NULL,
                        NULL);
  g_print("Message was: \"%s\"\n", message);
  return FALSE;


int
main (int argc, char **argv)

  /* initialize glib */
  g_type_init();

  GError * error = NULL;

  /* create the new socketservice */
  GSocketService * service = g_socket_service_new ();

  /* connect to the port */
  g_socket_listener_add_inet_port ((GSocketListener*)service,
                                    1500, /* your port goes here */
                                    NULL,
                                    &error);

  /* don't forget to check for errors */
  if (error != NULL)
  
      g_error (error->message);
  

  /* listen to the 'incoming' signal */
  g_signal_connect (service,
                    "incoming",
                    G_CALLBACK (incoming_callback),
                    NULL);

  /* start the socket service */
  g_socket_service_start (service);

  /* enter mainloop */
  g_print ("Waiting for client!\n");
  GMainLoop *loop = g_main_loop_new(NULL, FALSE);
  g_main_loop_run(loop);
  return 0;

这是对应的客户端:

#include <glib.h>
#include <gio/gio.h>

int
main (int argc, char *argv[])

   /* initialize glib */
  g_type_init ();

  GError * error = NULL;

  /* create a new connection */
  GSocketConnection * connection = NULL;
  GSocketClient * client = g_socket_client_new();

  /* connect to the host */
  connection = g_socket_client_connect_to_host (client,
                                               (gchar*)"localhost",
                                                1500, /* your port goes here */
                                                NULL,
                                                &error);

  /* don't forget to check for errors */
  if (error != NULL)
  
      g_error (error->message);
  
  else
  
      g_print ("Connection successful!\n");
  

  /* use the connection */
  GInputStream * istream = g_io_stream_get_input_stream (G_IO_STREAM (connection));
  GOutputStream * ostream = g_io_stream_get_output_stream (G_IO_STREAM (connection));
  g_output_stream_write  (ostream,
                          "Hello server!", /* your message goes here */
                          13, /* length of your message */
                          NULL,
                          &error);
  /* don't forget to check for errors */
  if (error != NULL)
  
      g_error (error->message);
  
  return 0;

不过请注意,我还是 glib、gio 甚至 C 的新手,所以在使用之前请仔细检查我的代码。

【讨论】:

感谢分享。对于 GIO 新人来说,这将是宝贵的资源。参考文档很好,但缺少示例。 @noisebleed:对这里的文档有同样的看法。 其实你可以用"echo anyword |nc localhost 1500"这样一个命令作为客户端来验证服务器是否工作。 如果你也能从服务器读取响应,那就太棒了 添加pkg-config --cflags --libs glib-2.0 gio-2.0【参考方案2】:

来自传入的回调不应阻塞,来自 gio 文档:“处理程序必须启动连接的处理,但不能阻塞;本质上,必须使用异步操作。”

我在异步版本中遇到了一些连接问题,它必须由用户引用,否则在传入回调返回后连接将关闭。

一个不阻塞的服务器的完整示例,基于之前给出的示例:

#include <gio/gio.h>
#include <glib.h>

#define BLOCK_SIZE 1024
#define PORT 2345

struct ConnData 
  GSocketConnection *connection;
  char message[BLOCK_SIZE];
;

void message_ready (GObject * source_object,
    GAsyncResult *res,
    gpointer user_data)

  GInputStream *istream = G_INPUT_STREAM (source_object);
  GError *error = NULL;
  struct ConnData *data = user_data;
  int count;

  count = g_input_stream_read_finish (istream,
      res,
      &error);

  if (count == -1) 
    g_error ("Error when receiving message");
    if (error != NULL) 
      g_error ("%s", error->message);
      g_clear_error (&error);
    
  
  g_message ("Message was: \"%s\"\n", data->message);
  g_object_unref (G_SOCKET_CONNECTION (data->connection));
  g_free (data);


static gboolean
incoming_callback (GSocketService *service,
    GSocketConnection * connection,
    GObject * source_object,
    gpointer user_data)

  g_message ("Received Connection from client!\n");
  GInputStream *istream = g_io_stream_get_input_stream (G_IO_STREAM (connection));
  struct ConnData *data = g_new (struct ConnData, 1);

  data->connection = g_object_ref (connection);

  g_input_stream_read_async (istream,
      data->message,
      sizeof (data->message),
      G_PRIORITY_DEFAULT,
      NULL,
      message_ready,
      data);
  return FALSE;


int main ()

  GSocketService *service;
  GError *error = NULL;
  gboolean ret;

  service = g_socket_service_new ();
  ret = g_socket_listener_add_inet_port (G_SOCKET_LISTENER (service),
      PORT, NULL, &error);

  if (ret && error != NULL)
  
    g_error ("%s", error->message);
    g_clear_error (&error);
    return 1;
  

  g_signal_connect (service,
      "incoming",
      G_CALLBACK (incoming_callback),
      NULL);

  g_socket_service_start (service);
  GMainLoop *loop = g_main_loop_new(NULL, FALSE);
  g_main_loop_run(loop);

  /* Stop service when out of the main loop*/
  g_socket_service_stop (service);
  return 0;

【讨论】:

以上是关于GIO socket-server / -client 示例的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Gio.Settings 中获取可重定位模式的路径?

gio 和 gvfs 库支持哪些平台?

Gio.MemoryInputStream 关​​闭时不释放内存

Gio SimpleAction 调用函数

Gio.SimpleAction 未发出更改状态信号

异步 GIO 服务器/客户端