10.3QEMU基于VNC的桌面虚拟化原理


VNC(Virtual Network Computer)虚拟网络计算机的缩写,它使用RFB(Remote Frame Buffer)协议来控制另外一台计算机,Qemu使用该协议来进行图形界面的操作与维护。

 

10.3.1 Qemu中VNC工作架构

main(vl.c)==> vnc_display_init(ds);

voidvnc_display_init(DisplayState *ds) {

    VncDisplay *vs = g_malloc0(sizeof(*vs));

 

    dcl =g_malloc0(sizeof(DisplayChangeListener)); //dcl为全局变量

 

    ds->opaque= vs;

    dcl->idle = 1;

    vnc_display = vs;

    vs->lsock = -1;

 

    vs->ds = ds;

    QTAILQ_INIT(&vs->clients);

    vs->expires = TIME_MAX;

 

    if (keyboard_layout)

        vs->kbd_layout =init_keyboard_layout(name2keysym, keyboard_layout);

    else

        vs->kbd_layout = init_keyboard_layout(name2keysym,"en-us");

    。。。。。。。

    qemu_mutex_init(&vs->mutex);

//启动vnc线程,其函数为vnc_worker_thread

    vnc_start_worker_thread();

 

    //这一组为图形显示回调

    dcl->dpy_copy = vnc_dpy_copy;

    dcl->dpy_update = vnc_dpy_update;

    dcl->dpy_resize = vnc_dpy_resize;

    dcl->dpy_setdata = vnc_dpy_setdata;

 

    register_displaychangelistener(ds,dcl);

    ds->mouse_set = vnc_mouse_set;//鼠标位置的更新

    ds->cursor_define =vnc_dpy_cursor_define;

}

 

main==> vnc_display_open

该函数根据用户参数初始化VNC Server,最后调用qemu_set_fd_handler2(vs->lsock,NULL, vnc_listen_read, NULL, vs);等待客户端连接,并调用vnc_connect,其流程如下:

a. qemu_set_fd_handler2(vs->csock,NULL, vnc_client_read, NULL, vs);处理客户端发送的请求

b. vga_hw_update==> active_console->hw_update

c.发送RFB协议的版本到客户端,并注册protocol_version的回调

d. 初始化键盘输入为空reset_keys

e. 注册鼠标位置改变的回调

   vs->mouse_mode_notifier.notify =check_pointer_type_change;

   qemu_add_mouse_mode_change_notifier(&vs->mouse_mode_notifier);

f. vnc_init_timer注册一个timer定期用于屏幕的更新,更新回调为vnc_refresh。

 

vnc_refresh==> vnc_update_client

a. vnc_job_new 建立一个新的job

b. 将上次图形的更新区域提交到job

 

vnc_worker_thread==》 vnc_worker_thread_loop其流程如下:

a. 等待有任务到来qemu_cond_wait(&queue->cond, &queue->mutex);

b. 取一个jobjob =QTAILQ_FIRST(&queue->jobs);

c. 根据job向客户端发送更新的区域

  vnc_send_framebuffer_update(&vs,entry->rect.x, entry->rect.y,

                                       entry->rect.w, entry->rect.h);

 

下一个问题是vnc模块如何接收鼠标与键盘数据,vnc_client_read用于读取客户端的数据,并响应。通过vs->read_handler读取客户端数据并数据拷贝到memmove(vs->input.buffer,vs->input.buffer + len, (vs->input.offset - len));

根据客户与服务器的连接装填, 该回调在不同时期为不同函数,但彻底建立连接后为protocol_client_msg

VNC_MSG_CLIENT_KEY_EVENT用户响应键盘

key_event==》  do_key_event ==> press_key ==> kbd_put_keycode==> qemu_put_kbd_event

 

VNC_MSG_CLIENT_POINTER_EVENT用于响应鼠标

pointer_event==> kbd_mouse_event ==> entry->qemu_put_mouse_event

 

下一节我们将分析虚拟驱动的数据和vnc数据的关联

10.3.2虚拟驱动的数据输入输出

下面以显示数据更新为例来看看显卡的数据如何到达vnc layer.

cirrus_do_copy==》 qemu_console_copy ==> dpy_copy

staticinline void dpy_copy(struct DisplayState *s, int src_x, int src_y,

                             int dst_x, intdst_y, int w, int h) {

    struct DisplayChangeListener *dcl =s->listeners;

    while (dcl != NULL) {

        if (dcl->dpy_copy)

            dcl->dpy_copy(s, src_x, src_y,dst_x, dst_y, w, h);

        else /* TODO */

            dcl->dpy_update(s, dst_x, dst_y,w, h);

        dcl = dcl->next;

    }

}

 

dcl->dpy_copy==> vnc_dpy_copy ==> vnc_copy

其中vnc_framebuffer_update会更新dirty区域,下次refresh时会使用该区域

 

下面在来分析键盘qemu_add_kbd_event_handler会注册实际的处理函数,

下面分析最简单的ps2键盘:

ps2_kbd_init==》 qemu_add_kbd_event_handler(ps2_put_keycode,s);

 

最后来分析鼠标,其注册函数为qemu_add_mouse_event_handler

ps2_mouse_init==》 qemu_add_mouse_event_handler(ps2_mouse_event,s, 0, "QEMU PS/2 Mouse");

 

vnc最终调用到鼠标与键盘的回调,虚拟驱动就能得到数据,并向虚拟机返回数据了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值