我有一个用 Vala 编写的带有 websocket 连接的简单 GTK 应用程序(使用 libsoup-2.4)。问题:我的应用程序有时会在启动时冻结(每 10 次启动)并且根本不显示 gui 窗口,因为在套接字连接上阻塞了 libsoup 中的某个位置。
瓦拉 0.40.25 与
- gtk+-3.0
- glib-2.0
- gobject-2.0
- libsoup-2.4
这里的代码:
using Gtk;
class WebsocketConnection {
private Soup.WebsocketConnection websocket_connection;
public signal void ws_message(int type, string message);
public signal void connection_succeeded();
public signal void connection_established();
public signal void connection_failed();
public signal void connection_disengaged();
private string host;
public WebsocketConnection(string host) {
this.host = host;
}
private static string decode_bytes(Bytes byt, int n) {
return (string)byt.get_data();
}
public void init_connection_for(string host) {
MainLoop loop = new MainLoop();
var socket_client = new Soup.Session();
string url = "ws://%s:8080/".printf(host);
message(@"connect to $url");
var websocket_message = new Soup.Message("GET", url);
socket_client.websocket_connect_async.begin(websocket_message, null, null, null, (obj, res) => {
try {
websocket_connection = socket_client.websocket_connect_async.end(res);
message("Connected!");
connection_succeeded();
if (websocket_connection != null) {
websocket_connection.message.connect((type, m_message) => {
ws_message(type, decode_bytes(m_message, m_message.length));
});
websocket_connection.closed.connect(() => {
message("Connection closed");
connection_disengaged();
});
}
} catch (Error e) {
message("Remote error: " + e.message + " " + e.code.to_string());
connection_failed();
loop.quit();
}
loop.quit();
});
loop.run();
}
}
class Main : Gtk.Application {
public Main() {
Object(
application_id: "com.github.syfds.websocket-libsoup-vala-example",
flags : ApplicationFlags.FLAGS_NONE
);
}
protected override void activate() {
var window = new ApplicationWindow(this);
window.title = "Hello, World!";
window.border_width = 10;
window.window_position = WindowPosition.CENTER;
window.set_default_size(350, 70);
window.destroy.connect(Gtk.main_quit);
var grid = new Grid();
grid.orientation = Orientation.VERTICAL;
grid.column_spacing = 5;
grid.row_spacing = 5;
var main_label = new Label("...");
var websocket_host_input = new Entry();
var send_message_btn = new Button.with_label("Connect");
var websocket_host = "192.168.1.252";
var connection = new WebsocketConnection(websocket_host);
connection.connection_succeeded.connect(() => {
message("Connection succeeded");
main_label.set_text("Connection succeeded");
});
connection.connection_failed.connect(() => {
message("Connection failed");
});
connection.ws_message.connect((type, msg) => {
message("message received " + msg);
});
connection.init_connection_for(websocket_host);
grid.add(main_label);
window.add(grid);
window.show_all();
}
public static int main(string[] args) {
var app = new Main();
return app.run(args);
}
}
如果我通过 gdb 连接到进程,我会看到以下图片:
(gdb) info thr
Id Target Id Frame
* 1 Thread 0x7f38e6cbbac0 (LWP 29885) "com.github.syfd" 0x00007f38e53098f6 in __libc_recv (
fd=14, buf=0x55890440bc00, len=1024, flags=0) at ../sysdeps/unix/sysv/linux/recv.c:28
2 Thread 0x7f38d5d1c700 (LWP 29886) "gmain" 0x00007f38e52fbcb9 in __GI___poll (
fds=0x558903d13b40, nfds=2, timeout=-1) at ../sysdeps/unix/sysv/linux/poll.c:29
3 Thread 0x7f38d551b700 (LWP 29887) "gdbus" 0x00007f38e52fbcb9 in __GI___poll (
fds=0x558903d30760, nfds=2, timeout=-1) at ../sysdeps/unix/sysv/linux/poll.c:29
4 Thread 0x7f38cffff700 (LWP 29888) "dconf worker" 0x00007f38e52fbcb9 in __GI___poll (
fds=0x558903f6ccb0, nfds=1, timeout=-1) at ../sysdeps/unix/sysv/linux/poll.c:29
(gdb) bt
#0 0x00007f38e53098f6 in __libc_recv (fd=14, buf=0x55890440bc00, len=1024, flags=0)
at ../sysdeps/unix/sysv/linux/recv.c:28
#1 0x00007f38e5eb54f4 in () at /usr/lib/x86_64-linux-gnu/libgio-2.0.so.0
#2 0x00007f38e5667558 in () at /usr/lib/x86_64-linux-gnu/libsoup-2.4.so.1
#3 0x00007f38e59173a5 in g_main_context_dispatch () at /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
#4 0x00007f38e5917770 in () at /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
#5 0x00007f38e59177fc in g_main_context_iteration () at /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
#6 0x00007f38e5ed8f3d in g_application_run () at /usr/lib/x86_64-linux-gnu/libgio-2.0.so.0
#7 0x0000558902d69e8f in main_main (args=0x7ffeb2b775f8, args_length1=1)
at /home/sergej/workspace/websocket-libsoup-vala-example-v2/src/Main.vala:121
#8 0x0000558902d69ed2 in main (argc=1, argv=0x7ffeb2b775f8)
at /home/sergej/workspace/websocket-libsoup-vala-example-v2/src/Main.vala:119
看起来__libc_recv at ../sysdeps/unix/sysv/linux/recv.c:28
这里被阻塞了,但我不明白为什么以及如何以非阻塞方式进行连接。
我感谢任何帮助/提示如何解决阻塞 UI 的问题或如何使用 libsoup 创建非阻塞 websocket 连接。