由 gio 库实现的简单线程服务器

Simple threaded server implemented by gio library

提问人:robinchm 提问时间:8/26/2015 更新时间:8/26/2015 访问量:617

问:

我正在尝试学习 gio 库,尤其是 giostream 和 gthreadedsocketservice。我想编写一个简单的服务器:

  1. 每个传入连接将由一个单独的新线程处理
  2. 在客户端,用户键入一个字符串,该字符串将被发送到服务器;在服务器端收到字符串后,立即将其显示给 stdout。
  3. 除非服务器或客户端终止,否则不会关闭连接。也就是说,可以从客户端发送到服务器的多条消息,而无需多次连接。

我尝试的代码是: 客户端:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <glib.h>
#include <gio/gio.h>

int main(int argc, char* argv[]){
 GError* error = NULL;
 GSocketConnection* connection = NULL;
 GOutputStream* ostream = NULL;
 GSocketClient* client = g_socket_client_new();
 gchar message[1024];

 connection = g_socket_client_connect_to_host(client, (gchar*)"localhost", 1500, NULL, &error);

 if (error) {
  g_error(error->message);
  g_error_free(error);
  return 1;
 }
 else g_print("Message: connected.\n");

 while(TRUE){
  scanf("%s", message);
  ostream = g_io_stream_get_output_stream(G_IO_STREAM(connection));
  g_output_stream_write(ostream, message, strlen(message), NULL, &error);
  if (error) {
   g_error(error->message);
   g_error_free(error);
   return 1;
  }
 }

 g_print("Message: client terminated.\n");
 return 0;
}

服务器端:

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

gboolean run_callback(GThreadedSocketService*, GSocketConnection*, GObject*, gpointer);

int main(int argc, char **argv){
 int port = 1500;
 GError* error = NULL;
 GMainLoop* loop = NULL;
 GThreadedSocketService* service = NULL;

 service = (GThreadedSocketService*)g_threaded_socket_service_new(-1);
 g_socket_listener_add_inet_port((GSocketListener*)service, port, NULL, &error);
 if (error != NULL) {g_error(error->message);}
 g_signal_connect(service, "run", G_CALLBACK(run_callback), NULL);
 g_socket_service_start((GSocketService*)service);
 g_print("Message: server launched...\n");
 loop = g_main_loop_new(NULL, FALSE);
 g_main_loop_run(loop);

 return 0;
}

gboolean run_callback(GThreadedSocketService* service, GSocketConnection* connection, GObject* source_object, gpointer user_data){
 GInputStream* instream = NULL;
 gchar message[1024];
 GError* error = NULL;

 instream = g_io_stream_get_input_stream(G_IO_STREAM(connection));
 g_input_stream_read_all(instream, message, 1024, NULL, NULL, &error);
 if (error != NULL) {
  g_error(error->message);
  g_error_free(error);
  return FALSE;
 }
 g_print("Received: %s\n", message);

 g_print("Message: connection terminated.\n");
 if (error) g_error_free(error);
 return FALSE;
}

问题是当我测试它时,在客户端我输入了三行:

aaa
bbb
ccc

但是服务器端没有显示任何内容。只有当我退出客户端时,服务器屏幕上才会显示:

aaabbbccc

但是我想要的是,当我输入“aaa”并输入时,它会立即显示在服务器屏幕上。

知道哪里出了问题吗?

C 服务器 IOSTREAM GIO

评论


答:

1赞 Some programmer dude 8/26/2015 #1

问题是你使用 .注意到名称中的后缀了吗?这意味着它将尝试读取您传递给它的大小,仅在收到所有这些字节或出现错误或断开连接时返回。g_input_stream_read_allall

请改用例如 在一个循环中。g_input_stream_read

评论

0赞 robinchm 8/26/2015
经过测试,可以正常工作。我可以问一下,当我运行一个循环时,我在其中调用 g_input_stream_read(),并且目前没有输入,函数是否返回并且循环继续,直到有一些输入(类似于轮询),或者它是否阻塞在这个线程中等待输入?
0赞 Some programmer dude 8/26/2015
@robinchm套接字默认是阻塞的,这在链中一直向上,这意味着当你从阻塞套接字中读取时,读取调用(无论它是什么功能)都应该阻塞,直到有东西要读。
0赞 robinchm 8/26/2015
多谢!因为 gio 在他们的手册中也提供了异步 io 和不同类型的 socketservice,但没有示例来说明它们的用法,所以我在学习它时遇到了很多困难。