原文地址:
http://my.oschina.net/eatapple/blog/89847
asterisk.c
以前一直困扰在gtk中使用多线程更新界面的问题,今天终于解决。在写下解决方法,以备后查。
这里以textview中动态显示socket更新数据为例。首先建立socket,然后使用g_idle_add函数添加读取socket函数。在该函数中更新textview中的数据,并且返回一个正值(或者false,用以让gtk循环执行该函数,如果不返回或者返回true则在执行一次后或者返回true后gtk不再执行该函数)。在该函数中利用select解决socket的堵塞问题即可。利用shutdown关闭socket,在idle函数中通过select和recv的函数返回值可以检测socket是否关闭。可以选择在关闭的时候通过g_idle_remove_by_data取消该函数的执行,或者在idle函数中检测socket关闭后返回true。
callback.c
01 | #include "callback.h" |
02 | #include "asterisk.h" |
03 |
04 | void on_connect_clicked(GtkToolItem *button,gpointer data) |
05 | { |
06 | if (asterisk_in()!=-1) |
07 | { |
08 | gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(button),GTK_STOCK_DISCONNECT); |
09 | g_signal_connect(G_OBJECT(button), "clicked" ,G_CALLBACK(on_disconnect_clicked),data); |
10 | g_idle_add((GSourceFunc)asterisk_refresh_ui,data); |
11 | } |
12 | } |
13 |
14 | void on_disconnect_clicked(GtkToolItem *button,gpointer data) |
15 | { |
16 | if (asterisk_out()==0) |
17 | { |
18 | GtkTextBuffer *buffer; |
19 |
20 | gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(button),GTK_STOCK_CONNECT); |
21 | g_signal_connect(G_OBJECT(button), "clicked" ,G_CALLBACK(on_connect_clicked),data); |
22 | g_idle_remove_by_data(data); |
23 | buffer=gtk_text_view_get_buffer(GTK_TEXT_VIEW(data)); |
24 | gtk_text_buffer_set_text(buffer, "" ,-1); |
25 | } |
26 | } |
01 | #include "asterisk.h" |
02 |
03 | int sockfd; |
04 |
05 | int asterisk_in() |
06 | { |
07 | struct sockaddr_in addr; |
08 | char buffer[1024]; |
09 |
10 | bzero(&addr, sizeof (addr)); |
11 | addr.sin_family=AF_INET; |
12 | addr.sin_port=htons(5038); |
13 | addr.sin_addr.s_addr=inet_addr( "127.0.0.1" ); |
14 |
15 | if ((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1) |
16 | { |
17 | perror ( "create socket" ); |
18 | return -1; |
19 | } |
20 | if (connect(sockfd,( struct sockaddr *)&addr, sizeof (addr))==-1) |
21 | { |
22 | perror ( "connect to socket" ); |
23 | return -1; |
24 | } |
25 | sprintf (buffer, "Action: login\r\nUsername: ami\r\nSecret: ami\r\n\r\n" ); |
26 | if (send(sockfd,buffer, strlen (buffer),0)!= strlen (buffer)) |
27 | return -1; |
28 | |
29 | return sockfd; |
30 | } |
31 |
32 | int asterisk_out() |
33 | { |
34 | close(sockfd); |
35 | shutdown(sockfd,2); |
36 |
37 | return 0; |
38 | } |
39 |
40 | int asterisk_refresh_ui(GtkWidget *textview) |
41 | { |
42 | char content[BUFSIZ]; |
43 | fd_set fd; |
44 | struct timeval stime={0,0}; |
45 | GtkTextBuffer *buffer; |
46 | GtkTextIter end; |
47 |
48 | FD_ZERO(&fd); |
49 | FD_SET(sockfd,&fd); |
50 | if (select(sockfd+1,&fd,NULL,NULL,&stime)>0 && FD_ISSET(sockfd,&fd)) |
51 | { |
52 | bzero(content, sizeof (content)); |
53 | recv(sockfd,content, sizeof (content),0); |
54 | buffer=gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview)); |
55 | gtk_text_buffer_get_end_iter(buffer,&end); |
56 | gtk_text_buffer_insert(buffer,&end,content,-1); |
57 | } |
58 |
59 | return 1; |
60 | } |