spice-gtk如何實現斷網提醒

spice-gtk現狀

使用過spice-gtk進行遠程連接虛擬機的朋友應該都知道,正在連接虛擬機的過程中,如果網絡斷開,虛擬機窗口界面就會卡死,也不會給出任何提示信息,那麼下面我們來實現spice-gtk網絡超時後自動退出。

設置socket超時關閉選項

首先找到spice-channel.c這個是spice-gtk的核心網絡層,找到setsockopt函數所在位置加入:

    int keepAlive = 1; // 設定 KeepAlive

    int keepIdle = 3; // 開始首次 KeepAlive 探測前的 TCP 空閉時間

    int keepInterval = 3; // 兩次 KeepAlive 探測間的時間間隔

    int keepCount = 1; // 判定斷開前的 KeepAlive 探測次數

    setsockopt(g_socket_get_fd(c->sock), SOL_SOCKET, SO_KEEPALIVE, (void*)&keepAlive, sizeof(keepAlive));
    setsockopt(g_socket_get_fd(c->sock), SOL_TCP, TCP_KEEPIDLE, (void *)&keepIdle, sizeof(keepIdle));
    setsockopt(g_socket_get_fd(c->sock), SOL_TCP, TCP_KEEPINTVL, (void *)&keepInterval, sizeof(keepInterval));
    setsockopt(g_socket_get_fd(c->sock), SOL_TCP, TCP_KEEPCNT, (void *)&keepCount, sizeof(keepCount));

    int keepAlive = 1;    // 設定 KeepAlive
    int keepIdle = 3;     // 開始首次 KeepAlive 探測前的 TCP 空閉時間
    int keepInterval = 3; // 兩次 KeepAlive 探測間的時間間隔
    int keepCount = 1;    // 判定斷開前的 KeepAlive 探測次數

    if (setsockopt(g_socket_get_fd(c->sock), SOL_SOCKET, SO_KEEPALIVE, (void*)&keepAlive, sizeof(keepAlive)) == -1)
        printf("keepAlive error\n");
    if (setsockopt(g_socket_get_fd(c->sock), SOL_TCP, TCP_KEEPIDLE, (void *)&keepIdle, sizeof(keepIdle)) == -1)
        printf("keepIdle error\n");
    if (setsockopt(g_socket_get_fd(c->sock), SOL_TCP, TCP_KEEPINTVL, (void *)&keepInterval, sizeof(keepInterval)) == -1)
        printf("keepInterval error\n");
    if (setsockopt(g_socket_get_fd(c->sock), SOL_TCP, TCP_KEEPCNT, (void *)&keepCount, sizeof(keepCount)) == -1)
        printf("keepCount error\n");

    rc = setsockopt(g_socket_get_fd(c->sock), IPPROTO_TCP, TCP_NODELAY,
                    (const char*)&delay_val, sizeof(delay_val));

超時後的反應

超時候虛擬機會在下面地方作出反應:spice_channel_iterate這個函數是處理所有信息的循環,一旦socket出現問題,這邊都是會做出反應的。在ret = g_socket_condition_check(c->sock, G_IO_IN | G_IO_ERR);這個函數中添加一個參數變成:

ret = g_socket_condition_check(c->sock, G_IO_IN | G_IO_ERR | G_IO_HUP);   G_IO_HUP就代表着我們io超時的情況,所有這邊加了之後一旦網絡超時了就會在這邊觸發,觸發之後設置c->event = SPICE_CHANNEL_ERROR_IO;這個信號是傳輸到spicy.c裏面的,畢竟spice-channel.c是庫,spicy.c是主界面客戶端,是spicy.c調用spice-channel.c庫的,一旦庫裏面的socket出現了問題,會通過信號傳輸給spicy.c。

static gboolean spice_channel_iterate(SpiceChannel *channel)
{
    SpiceChannelPrivate *c = channel->priv;

    if (c->state == SPICE_CHANNEL_STATE_MIGRATING &&
        !g_coroutine_condition_wait(&c->coroutine, wait_migration, channel))
        CHANNEL_DEBUG(channel, "migration wait cancelled");

    /* flush any pending write and read */
    if (!c->has_error)
        SPICE_CHANNEL_GET_CLASS(channel)->iterate_write(channel);
    if (!c->has_error)
        SPICE_CHANNEL_GET_CLASS(channel)->iterate_read(channel);

    if (c->has_error) {
        GIOCondition ret;

        if (!c->sock) {
            return FALSE;
        }
        /* We don't want to report an error if the socket was closed gracefully
         * on the other end (VM shutdown) */
        ret = g_socket_condition_check(c->sock, G_IO_IN | G_IO_ERR | G_IO_HUP);

        if ((ret & G_IO_ERR) || (ret & G_IO_HUP)) {
            CHANNEL_DEBUG(channel, "channel got error");
            if (c->state > SPICE_CHANNEL_STATE_CONNECTING) {
                if (c->state == SPICE_CHANNEL_STATE_READY)
                    c->event = SPICE_CHANNEL_ERROR_IO;
                else
                    c->event = SPICE_CHANNEL_ERROR_LINK;
            }
        }
        return FALSE;
    }

    return TRUE;
}

spicy.c客戶端信號出發

spice-channel.c裏面設置c->event = SPICE_CHANNEL_ERROR_IO;之後會在spicy.c裏面接收到這個信號,位置在:

static void main_channel_event(SpiceChannel *channel, SpiceChannelEvent event,
                               gpointer data)
{
    const GError *error = NULL;
    spice_connection *conn = data;
    char password[64];
    int rc;

    switch (event) {
        。
        。
        。
        case SPICE_CHANNEL_ERROR_IO:
            g_message("main channel: error io");
            connection_disconnect(conn);
        break;
        。
        。
        。
    }
}

可以直接調用connection_disconnect結束官方版spice-gtk的進程,或者調用自己寫的界面,提示用戶此時網絡已經斷開,作出友好提醒。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章