Glib学习(23) IO通道 IO Channels

阳光穿透心脏的1/2处 2022-01-22 14:47 199阅读 0赞

glib源码下载:http://ftp.gnome.org/pub/gnome/sources/glib/
glib帮助文档:https://developer.gnome.org/glib/

IO通道 - 可移植的支持使用文件,管道和套接字

Includes
#include

描述

GIOChannel数据类型旨在提供一种可移植的方法,用于使用文件描述符,管道和套接字,并将它们集成到main event loop。 目前,在UNIX平台上提供完全支持,对Windows的支持仅部分完成。
要在UNIX系统上创建新的GIOChannel,请使用g_io_channel_unix_new()。 这适用于普通文件描述符,管道和套接字。 或者,可以使用g_io_channel_new_file()以与系统无关的方式为文件创建通道。
创建GIOChannel后,可以使用函数g_io_channel_read_chars(),g_io_channel_write_chars(),g_io_channel_seek_position()和g_io_channel_shutdown()以通用方式使用它。
要将GIOChannel添加到main event loop,请使用g_io_add_watch()或g_io_add_watch_full()。 在这里,您可以在GIOChannel上指定您感兴趣的事件,并提供在发生这些事件时要调用的函数。
创建GIOChannel实例,初始引用计数为1. g_io_channel_ref()和g_io_channel_unref()可分别用于递增或递减引用计数。 当引用计数降至0时,释放GIOChannel。 (虽然它不会自动关闭,除非它是使用g_io_channel_new_file()创建的。)使用g_io_add_watch()或g_io_add_watch_full()增加通道的引用计数。
新函数g_io_channel_read_chars(),g_io_channel_read_line(),g_io_channel_read_line_tring(),g_io_channel_read_to_end(),g_io_channel_write_chars(),g_io_channel_seek_position()和g_io_channel_flush()不应与不推荐使用的函数g_io_channel_read(),g_io_channel_write()和g_io_channel_seek混合使用( )在同一channel上。

函数

g_io_channel_unix_new ()
给定文件描述符创建新的GIOChannel。 在UNIX系统上,这适用于普通文件,管道和套接字。
返回的GIOChannel的引用计数为1。
GIOChannel的默认编码是UTF-8。 如果您的应用程序正在使用via管道从命令读取输出,则可能需要使用g_io_channel_set_encoding()函数将编码设置为当前语言环境的编码(请参阅g_get_charset())。 默认情况下,当删除对GIOChannel数据结构的最终引用时,将不会关闭传递的fd。
如果要在没有解释的情况下读取原始二进制数据,则使用NULL为编码参数调用g_io_channel_set_encoding()函数。
此功能在Windows上的GLib中也可用,但您应该避免在Windows上使用它。 文件描述符和套接字的域重叠。 如果传递给此函数的参数恰好是有效的文件描述符和套接字,则GLib无法知道您的意思。 如果发生这种情况,则会发出警告,并且GLib假定它是您所指的文件描述符。
返回值
一个新的GIOChannel。
g_io_channel_unix_get_fd ()
返回GIOChannel的文件描述符。
在Windows上,此函数返回GIOChannel的文件描述符或套接字。

g_io_channel_init ()
初始化GIOChannel结构。
在创建GIOChannel时,上述每个函数都会调用它,因此应用程序员通常不需要这样做(除非您要创建新类型的GIOChannel)。

g_io_channel_new_file ()
使用mode模式将文件文件名作为GIOChannel打开。 当删除对它的最后一个引用时,该channel将被关闭,因此不需要调用g_io_channel_close()(尽管这样做不会导致问题,只要在关闭后没有尝试访问该通道)。
参数
mode
“r”,“w”,“a”,“r +”,“w +”,“a +”之一。 这些与fopen()中的含义相同
返回值
成功时的GIOChannel,失败时为NULL。
g_io_channel_read_chars ()
使用新API替换g_io_channel_read()。
参数
count
缓冲区的大小。 请注意,如果剩余数据不是完整字符,即使缓冲区中有数据,缓冲区也可能无法完全填充。
[in]
bytes_read
读取的字节数。 如果count <6并且channel的编码为非NULL,则即使成功也可能为零。 这表示下一个UTF-8字符对于缓冲区来说太宽。
[out][optional]

返回值
操作的状态。
g_io_channel_read_unichar ()
从通道读取Unicode字符。 无法在具有NULL编码的通道上调用此函数。

g_io_channel_read_line ()
从GIOChannel读取一行(包括终止字符)到新分配的字符串。 如果返回值为G_IO_STATUS_NORMAL,则str_return将包含已分配的内存。
参数
str_return
从GIOChannel读取的行,包括行终止符。 不再需要时,应使用g_free()释放此数据。 这是一个以空字符结尾的字符串。 如果返回零长度,则将为NULL。
[out]
length
存储读取数据长度的位置,或NULL。
[out][optional]
terminator_pos

存储行终止符位置的位置,或NULL。
[out][optional]
error

返回GConvertError或GIOChannelError类型错误的位置
返回值
操作的状态。
g_io_channel_read_line_string ()
使用GString作为缓冲区从GIOChannel读取一行。
参数
g_io_channel_read_to_end ()
从文件中读取所有剩余数据。
返回值
G_IO_STATUS_NORMAL成功。 此函数永远不会返回G_IO_STATUS_EOF。
g_io_channel_write_unichar ()
将Unicode字符写入通道。 无法在具有NULL编码的通道上调用此函数。

g_io_channel_flush ()
刷新GIOChannel的写缓冲区。
返回值
操作的状态:G_IO_STATUS_NORMAL,G_IO_STATUS_AGAIN或G_IO_STATUS_ERROR之一。
g_io_channel_shutdown ()
关闭IO通道。 如果flush为TRUE,则将刷新任何要写入的待处理数据。 在使用g_io_channel_unref()删除最后一个引用之前,不会释放该通道。
g_io_create_watch ()
创建在满足给定通道条件时调度的GSource。 例如,如果condition是G_IO_IN,则当有可用于读取的数据时,将调度source。
对于您希望以默认优先级将source添加到默认主循环上下文的情况,g_io_add_watch()是同一功能的简单接口。

g_io_add_watch ()
使用默认优先级将GIOChannel添加到默认主循环上下文中。
g_io_add_watch_full ()
将GIOChannel添加到具有给定优先级的默认主循环上下文中。
这在内部使用g_io_create_watch()创建一个主循环source,并使用g_source_attach()将其附加到主循环上下文。 如果需要更好的控制,可以手动执行这些步骤。
[rename-to g_io_add_watch]

gboolean
(*GIOFunc) (GIOChannel *source,
GIOCondition condition,
gpointer data);
指定传递给g_io_add_watch()或g_io_add_watch_full()的函数类型,该函数在满足GIOChannel上的请求条件时调用。

g_io_channel_get_line_term ()
这将返回GIOChannel用于确定文件在哪里发生换行的字符串。 值NULL表示自动检测。
g_io_channel_set_line_term ()
这将设置GIOChannel用于确定文件中断行发生位置的字符串。

g_io_channel_get_buffered ()
返回缓冲通道。
g_io_channel_set_buffered ()
只有在通道编码为NULL时才能设置缓冲状态。 对于任何其他编码,必须缓冲通道。
如果刷新了通道的内部缓冲区,则只能将缓冲通道设置为无缓冲。 返回G_IO_STATUS_EOF的新创建的频道或频道不需要这样的flush。 对于只写通道,调用g_io_channel_flush()就足够了。 对于所有其他通道,可以通过调用g_io_channel_seek_position()来刷新缓冲区。 这包括寻找类型G_SEEK_CUR和零偏移的可能性。 请注意,这意味着一旦从其中读取数据,就无法将基于套接字的通道设置为无缓冲。
在无缓冲通道上,如果维护旧代码是必要的,则可以安全地混合来自新旧API的读写调用。
缓冲通道的默认状态。

示例代码:

  1. #include <sys/types.h>
  2. #include <sys/stat.h>
  3. #include <fcntl.h>
  4. #include <unistd.h>
  5. #include <errno.h>
  6. #include <stdlib.h>
  7. #include <glib.h>
  8. #include <glib/gprintf.h>
  9. void channel_unix_new_test(void)
  10. {
  11. g_printf ("%s() in\n", __func__);
  12. int fd = open("test.txt", O_RDONLY);
  13. GIOChannel *giofile = g_io_channel_unix_new (fd);
  14. gchar *str_return;
  15. gsize length, terminator_pos;
  16. GError *error = NULL;
  17. GIOStatus giostatus = g_io_channel_read_line (giofile,
  18. &str_return,
  19. &length,
  20. &terminator_pos,
  21. &error);
  22. if (giostatus == G_IO_STATUS_NORMAL)
  23. g_printf ("read_line:%s, length:%ld, terminator_pos:%ld\n", str_return, length, terminator_pos);
  24. else if (giostatus == G_IO_STATUS_ERROR)
  25. g_printf ("read_line error G_IO_STATUS_ERROR:%s\n", error->message);
  26. else if (giostatus == G_IO_STATUS_EOF)
  27. g_printf ("read_line error G_IO_STATUS_EOF:%s\n", error->message);
  28. else if (giostatus == G_IO_STATUS_AGAIN)
  29. g_printf ("read_line error G_IO_STATUS_AGAIN:%s\n", error->message);
  30. GString *buffer = g_string_new (NULL);
  31. giostatus = g_io_channel_read_line_string (giofile,
  32. buffer,
  33. &terminator_pos,
  34. &error);
  35. if (giostatus == G_IO_STATUS_NORMAL)
  36. g_printf ("read_line_string:%s\n", buffer->str);
  37. else if (giostatus == G_IO_STATUS_ERROR)
  38. g_printf ("read_line_string error G_IO_STATUS_ERROR:%s\n", error->message);
  39. else if (giostatus == G_IO_STATUS_EOF)
  40. g_printf ("read_line_string error G_IO_STATUS_EOF:%s\n", error->message);
  41. else if (giostatus == G_IO_STATUS_AGAIN)
  42. g_printf ("read_line_string error G_IO_STATUS_AGAIN:%s\n", error->message);
  43. g_string_free (buffer, TRUE);
  44. giostatus = g_io_channel_read_to_end (giofile,
  45. &str_return,
  46. &length,
  47. &error);
  48. if (giostatus == G_IO_STATUS_NORMAL)
  49. g_printf ("read_to_end:%s, length:%ld\n", str_return, length);
  50. else if (giostatus == G_IO_STATUS_ERROR)
  51. g_printf ("read_to_end error G_IO_STATUS_ERROR:%s\n", error->message);
  52. else if (giostatus == G_IO_STATUS_EOF)
  53. g_printf ("read_to_end error G_IO_STATUS_EOF:%s\n", error->message);
  54. else if (giostatus == G_IO_STATUS_AGAIN)
  55. g_printf ("read_to_end error G_IO_STATUS_AGAIN:%s\n", error->message);
  56. gint gfd = g_io_channel_unix_get_fd (giofile);
  57. g_io_channel_shutdown (giofile, TRUE, &error);
  58. close(gfd);
  59. g_printf ("%s() out\n", __func__);
  60. }
  61. void channel_read_chars_test(void)
  62. {
  63. g_printf ("%s() in\n", __func__);
  64. GError *error = NULL;
  65. GIOChannel *giofile = g_io_channel_new_file ("test.txt",
  66. "r",
  67. &error);
  68. gchar *buf = g_new0(gchar, 1024);
  69. gsize bytes_read;
  70. GIOStatus giostatus = g_io_channel_read_chars (giofile,
  71. buf,
  72. 1024,
  73. &bytes_read,
  74. &error);
  75. if (giostatus == G_IO_STATUS_NORMAL)
  76. g_printf ("read_chars:%s, length:%ld\n", buf, bytes_read);
  77. else if (giostatus == G_IO_STATUS_ERROR)
  78. g_printf ("read_chars error G_IO_STATUS_ERROR:%s\n", error->message);
  79. else if (giostatus == G_IO_STATUS_EOF)
  80. g_printf ("read_chars error G_IO_STATUS_EOF:%s\n", error->message);
  81. else if (giostatus == G_IO_STATUS_AGAIN)
  82. g_printf ("read_chars error G_IO_STATUS_AGAIN:%s\n", error->message);
  83. g_io_channel_shutdown (giofile, TRUE, &error);
  84. g_free (buf);
  85. g_printf ("%s() out\n", __func__);
  86. }
  87. void channel_read_unichar_test(void)
  88. {
  89. g_printf ("%s() in\n", __func__);
  90. GError *error = NULL;
  91. GIOChannel *giofile = g_io_channel_new_file ("ansi.txt",
  92. "r",
  93. &error);
  94. GError *err = NULL;
  95. GIOStatus giostatus = g_io_channel_set_encoding (giofile,
  96. "ANSI",
  97. &err);
  98. gunichar thechar;
  99. giostatus = g_io_channel_read_unichar (giofile,
  100. &thechar,
  101. &error);
  102. if (giostatus == G_IO_STATUS_NORMAL)
  103. g_printf ("read_unichar:%d\n", thechar);
  104. else if (giostatus == G_IO_STATUS_ERROR)
  105. g_printf ("read_unichar error G_IO_STATUS_ERROR:%s\n", error->message);
  106. else if (giostatus == G_IO_STATUS_EOF)
  107. g_printf ("read_unichar error G_IO_STATUS_EOF:%s\n", error->message);
  108. else if (giostatus == G_IO_STATUS_AGAIN)
  109. g_printf ("read_unichar error G_IO_STATUS_AGAIN:%s\n", error->message);
  110. g_io_channel_shutdown (giofile, TRUE, &error);
  111. g_printf ("%s() out\n", __func__);
  112. }
  113. void channel_write_chars_test(void)
  114. {
  115. g_printf ("%s() in\n", __func__);
  116. GError *error = NULL;
  117. GIOChannel *giofile = g_io_channel_new_file ("write.txt",
  118. "a+",
  119. &error);
  120. gsize bytes_written;
  121. GIOStatus giostatus = g_io_channel_write_chars (giofile,
  122. "g_io_channel_write_chars",
  123. -1,
  124. &bytes_written,
  125. &error);
  126. if (giostatus == G_IO_STATUS_ERROR)
  127. g_printf ("write_chars error G_IO_STATUS_ERROR:%s\n", error->message);
  128. else if (giostatus == G_IO_STATUS_EOF)
  129. g_printf ("write_chars error G_IO_STATUS_EOF:%s\n", error->message);
  130. else if (giostatus == G_IO_STATUS_AGAIN)
  131. g_printf ("write_chars error G_IO_STATUS_AGAIN:%s\n", error->message);
  132. giostatus = g_io_channel_flush (giofile,
  133. &error);
  134. if (giostatus == G_IO_STATUS_ERROR)
  135. g_printf ("flush error G_IO_STATUS_ERROR:%s\n", error->message);
  136. else if (giostatus == G_IO_STATUS_EOF)
  137. g_printf ("flush error G_IO_STATUS_EOF:%s\n", error->message);
  138. else if (giostatus == G_IO_STATUS_AGAIN)
  139. g_printf ("flush error G_IO_STATUS_AGAIN:%s\n", error->message);
  140. g_io_channel_shutdown (giofile, TRUE, &error);
  141. g_printf ("%s() out\n", __func__);
  142. }
  143. gboolean GIOFifoFunc (GIOChannel *source, GIOCondition condition, gpointer data)
  144. {
  145. g_printf ("GIOFifoFunc data:%s\n", (char *)data);
  146. g_printf ("condition:%d\n", condition);
  147. if(condition & G_IO_HUP) {
  148. g_error("error:Pipe Disconnected!\n");
  149. }
  150. GError *error = NULL;
  151. gsize bytes_read;
  152. gsize length, terminator_pos;
  153. gchar *str_return;
  154. GIOStatus giostatus = g_io_channel_read_line (source,
  155. &str_return,
  156. &length,
  157. &terminator_pos,
  158. &error);
  159. if (giostatus == G_IO_STATUS_NORMAL)
  160. g_printf ("read_line:%s, length:%ld, terminator_pos:%ld\n", str_return, length, terminator_pos);
  161. else if (giostatus == G_IO_STATUS_ERROR)
  162. g_printf ("read_chars error G_IO_STATUS_ERROR:%s\n", error->message);
  163. else if (giostatus == G_IO_STATUS_EOF)
  164. g_printf ("read_chars error G_IO_STATUS_EOF:%s\n", error->message);
  165. else if (giostatus == G_IO_STATUS_AGAIN)
  166. g_printf ("read_chars error G_IO_STATUS_AGAIN:%s\n", error->message);
  167. g_free (str_return);
  168. return TRUE;
  169. }
  170. void FifoDestroyNotify (gpointer data)
  171. {
  172. g_printf ("FifoDestroyNotify data:%s\n", (char *)data);
  173. }
  174. gboolean TimeoutSourceFunc (gpointer user_data)
  175. {
  176. g_printf ("%s() in\n", __func__);
  177. GMainLoop *loop = (GMainLoop *)user_data;
  178. g_main_loop_quit (loop);
  179. return FALSE;
  180. }
  181. void setup_child(gint input[]) {
  182. g_printf ("%s() in\n", __func__);
  183. GIOChannel *channel_read;
  184. char *user_data = "test user data!";
  185. // 关闭不必要的 Pipe 输入
  186. close(input[1]);
  187. GMainLoop *loop = g_main_loop_new (NULL, FALSE);
  188. channel_read = g_io_channel_unix_new(input[0]);
  189. if(channel_read == NULL) {
  190. g_error("error:Unable to establish GIOChannels!\n");
  191. }
  192. guint source_id = g_io_add_watch_full(channel_read, G_PRIORITY_DEFAULT, G_IO_IN|G_IO_HUP, GIOFifoFunc, (gpointer) user_data, FifoDestroyNotify);
  193. if(source_id == 0) {
  194. g_error("error:Unable to add watch!\n");
  195. }
  196. g_timeout_add (1000, TimeoutSourceFunc, (gpointer)loop);
  197. g_main_loop_run (loop);
  198. g_source_remove (source_id);
  199. g_printf ("g_source_remove\n");
  200. sleep(1);
  201. }
  202. void setup_parent(gint output[]) {
  203. g_printf ("%s() in\n", __func__);
  204. sleep(1);
  205. GIOChannel *channel_write;
  206. GError *error = NULL;
  207. gsize bytes_written;
  208. // 关闭不用的 Pipe 输出
  209. close(output[0]);
  210. // 建立 GIOChannel
  211. channel_write = g_io_channel_unix_new(output[1]);
  212. if(channel_write == NULL) {
  213. g_error("错误:无法建立 GIOChannels!\n");
  214. }
  215. GIOStatus giostatus = g_io_channel_write_chars (channel_write,
  216. "setup parent\n",
  217. -1,
  218. &bytes_written,
  219. &error);
  220. giostatus = g_io_channel_flush (channel_write, &error);
  221. if (giostatus == G_IO_STATUS_ERROR)
  222. g_printf ("flush error G_IO_STATUS_ERROR:%s\n", error->message);
  223. else if (giostatus == G_IO_STATUS_EOF)
  224. g_printf ("flush error G_IO_STATUS_EOF:%s\n", error->message);
  225. else if (giostatus == G_IO_STATUS_AGAIN)
  226. g_printf ("flush error G_IO_STATUS_AGAIN:%s\n", error->message);
  227. sleep(5);
  228. }
  229. void io_add_watch(void)
  230. {
  231. g_printf ("%s() in\n", __func__);
  232. gint parent_to_child[2];
  233. if(pipe(parent_to_child) == -1) { // 开启Pipe
  234. g_error("Error:%s\n", g_strerror(errno));
  235. return;
  236. }
  237. // fork 子程序
  238. switch(fork()) {
  239. case -1:
  240. g_error("error:%s\n", g_strerror(errno));
  241. break;
  242. case 0: // 这是子程序
  243. setup_child(parent_to_child);
  244. break;
  245. default: // 这是父程序
  246. setup_parent(parent_to_child);
  247. }
  248. g_printf ("%s() out\n", __func__);
  249. }
  250. int main(int argc, char **argv)
  251. {
  252. g_printf ("main() in\n");
  253. channel_unix_new_test();
  254. channel_read_chars_test();
  255. channel_read_unichar_test();
  256. channel_write_chars_test();
  257. io_add_watch();
  258. g_printf ("main() out\n");
  259. return 0;
  260. }

输出结果:

  1. ~/glibtest$ ./gio
  2. main() in
  3. io_add_watch() in
  4. setup_parent() in
  5. setup_child() in
  6. GIOFifoFunc data:test user data!
  7. condition:1
  8. read_line:setup parent
  9. , length:13, terminator_pos:12
  10. TimeoutSourceFunc() in
  11. FifoDestroyNotify data:test user data!
  12. g_source_remove
  13. io_add_watch() out
  14. main() out
  15. io_add_watch() out
  16. main() out

文本文件:

ansi.txt

20190606164251397.png

test.txt

20190606164411210.png

write.txt

20190606164457587.png

发表评论

表情:
评论列表 (有 0 条评论,199人围观)

还没有评论,来说两句吧...

相关阅读

    相关 GO语言:channel通道

    通道可以被认为是Goroutines通信的管道。类似于管道中的水从一端到另一端的流动,数据可以从一端发送到另一端,通过通道接收。 在前面讲Go语言的并发时候,我们就说过,当多