2015-08-26 68 views
0

我想學習gio庫,特別是giostream和gthreadedsocketservice。我想編寫一個簡單的服務器:由gio庫實現的簡單線程服務器

  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; 
} 

問題是,當我測試了它,在客戶端我輸入3行:

aaa 
bbb 
ccc 

但是服務器上沒有顯示任何內容側。只有當我退出客戶端,服務器屏幕上它顯示:

aaabbbccc 

但我想要的是當我輸入「AAA」,進入,它會立即顯示在服務器屏幕上。

任何想法出錯的地方?

回答

1

問題是你用g_input_stream_read_all。請注意後綴all的名字?這意味着它會嘗試讀取您傳遞給它的大小,只有在收到這些字節時才返回,或者出現錯誤或斷開連接。

代替使用例如g_input_stream_read在一個循環中。

+0

經過測試,它的工作原理。我可以問一下,當我運行一個循環時,我在其中調用g_input_stream_read(),並且此刻沒有輸入,該函數是否會返回並繼續循環,直到出現一些輸入(類似於輪詢),還是阻塞這個線程在等待輸入嗎? – robinchm

+0

@robinchm套接字默認爲*阻塞*,並且這在鏈中一路上升,這意味着當您從阻塞套接字讀取時,讀取調用(無論它是什麼函數)應該阻塞,直到有東西要讀取。 –

+0

非常感謝!因爲gio在他們的手冊中也提供了異步IO和不同類型的套接字服務,但沒有例子來說明它們的用法,所以我努力學習它很多。 – robinchm