spice测试工程

来源:互联网 发布:国外数据库 编辑:程序博客网 时间:2024/06/06 19:54

test-stream.c

参考:linux文件描述符传递
http://blog.csdn.net/sparkliang/article/details/5486069
http://blog.csdn.net/sparkliang/article/details/5490242


spice-server
版本:spice-0.14.0
测试工程:test-stream.c

struct RedsStream {    int socket;    SpiceWatch *watch;    RedsStreamPrivate *priv;};
int main(int argc, char *argv[]){    RedsStream *st[2];//结构体定义    int sv[2];    int ret, fd = -1;    char c;    //spice定义的断言    spice_return_val_if_fail(server_init() == 0, -1);    //创建socketpair:create a pair of connected sockets    if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sv) == -1) {        spice_error("socketpair failed %s", strerror(errno));        return -1;    }    //创建两个RedsStream 结构体    st[0] = reds_stream_new(server, sv[0]);    spice_assert(reds_stream_is_plain_unix(st[0]));    st[1] = reds_stream_new(server, sv[1]);    spice_assert(reds_stream_is_plain_unix(st[1]));    /* send stdin, for the fun of it */    ret = reds_stream_send_msgfd(st[0], 0); //关键函数:发送    spice_assert(ret == 1);   //sendmsg系统调用返回值为1,为发送的一个字节    ret = sock_fd_read(sv[1], &c, 1, &fd);//关键函数:接收    spice_assert(c == '@');  //断言是否为接收的数据‘@’    spice_assert(ret == 1);  //recvmsg系统调用返回值为1,位接收一个字节    spice_assert(fd != -1);  //reds_stream_send_msgfd函数将文件描述符"0",也就是标准输入传给了Redstream st[1],也就是传入的fd。    close(fd);  //将fd,就是标准输入关闭 本进程的。 每一个进程默认都有标准输入,标准输出, 标准错误输出    /* send invalid fd behaviour */ //此时fd等于0,参考下面的关键函数。 走另一条路径sendmsg/read    上面的收发是sendmsg/recvmsg    ret = reds_stream_send_msgfd(st[0], -1);    spice_assert(ret == 1);    ret = sock_fd_read(sv[1], &c, 1, &fd);    spice_assert(c == '@');    spice_assert(ret == 1);    spice_assert(fd == -1);    /* batch test */   //模拟发送一批。但是只发送了两次    ret = reds_stream_send_msgfd(st[0], 0);    spice_assert(ret == 1);    ret = reds_stream_send_msgfd(st[0], 0);    spice_assert(ret == 1);    ret = sock_fd_read(sv[1], &c, 1, &fd);    spice_assert(c == '@');    spice_assert(ret == 1);    spice_assert(fd != -1);    close(fd);    ret = sock_fd_read(sv[1], &c, 1, &fd);    spice_assert(c == '@');    spice_assert(ret == 1);    spice_assert(fd != -1);    close(fd);    reds_stream_free(st[0]);    reds_stream_free(st[1]);    return 0;}

//核心关键函数int reds_stream_send_msgfd(RedsStream *stream, int fd){    struct msghdr msgh = { 0, };    struct iovec iov;    int r;    const size_t fd_size = 1 * sizeof(int);    struct cmsghdr *cmsg;    // 使用联合体,保证cmsghdr和msg_control的对齐     union {        struct cmsghdr hdr;        char data[CMSG_SPACE(fd_size)];    } control;    spice_return_val_if_fail(reds_stream_is_plain_unix(stream), -1);    /* set the payload */    iov.iov_base = (char*)"@"; //发送的ascii码,一个字符    iov.iov_len = 1;  //iov.iov_base的长度    msgh.msg_iovlen = 1;  //只发送一个 struct iovec    msgh.msg_iov = &iov;    if (fd != -1) {//main中的第一个测试。ret = reds_stream_send_msgfd(st[0], 0);        //上面的union体与msgh结构体建立联系,为辅助缓冲区和长度          msgh.msg_control = control.data;        msgh.msg_controllen = sizeof(control.data);        /* CMSG_SPACE() might be larger than CMSG_LEN() as it can include some         * padding. We set the whole control data to 0 to avoid valgrind warnings         */        memset(control.data, 0, sizeof(control.data));//清空数据        cmsg = CMSG_FIRSTHDR(&msgh);//从辅助缓冲区中取出一个辅助缓冲区,下面设置必要的字段值        cmsg->cmsg_len = CMSG_LEN(fd_size);        cmsg->cmsg_level = SOL_SOCKET;        cmsg->cmsg_type = SCM_RIGHTS;        memcpy(CMSG_DATA(cmsg), &fd, fd_size); //要传递的文件描述符    }    //发送数据,不成功不罢休。    do {        r = sendmsg(stream->socket, &msgh, MSG_NOSIGNAL);    } while (r < 0 && (errno == EINTR || errno == EAGAIN));    return r;}
//关键函数,接收数据static ssize_tsock_fd_read(int sock, void *buf, ssize_t bufsize, int *fd){    ssize_t size;    if (fd) {        struct msghdr msg;        struct iovec iov;        union {//数据对齐            struct cmsghdr cmsghdr;            char control[CMSG_SPACE(sizeof (int))];        } cmsgu;        struct cmsghdr *cmsg;        //设置接收缓冲区与长度        iov.iov_base = buf;        iov.iov_len = bufsize;        msg.msg_name = NULL;        msg.msg_namelen = 0;        msg.msg_iov = &iov;        msg.msg_iovlen = 1;        //设置辅助缓冲区与长度        msg.msg_control = cmsgu.control;        msg.msg_controllen = sizeof(cmsgu.control);        size = recvmsg(sock, &msg, 0); //接收数据        if (size < 0) {            perror ("recvmsg");            exit(1);        }        cmsg = CMSG_FIRSTHDR(&msg);//取出第一个辅助缓冲区数据指针地址        if (cmsg && cmsg->cmsg_len == CMSG_LEN(sizeof(int))) {            if (cmsg->cmsg_level != SOL_SOCKET) {                fprintf(stderr, "invalid cmsg_level %d\n",                        cmsg->cmsg_level);                exit(1);            }            if (cmsg->cmsg_type != SCM_RIGHTS) {                fprintf(stderr, "invalid cmsg_type %d\n",                        cmsg->cmsg_type);                exit(1);            }            //判读有效后,复制给fd ,文件描述符传输成功。            memcpy(fd, CMSG_DATA(cmsg), sizeof(*fd));        } else            *fd = -1;    } else {        size = read(sock, buf, bufsize);        if (size < 0) {            perror("read");            exit(1);        }    }    return size;}
[root@net01 tests]# ./test-stream event_loop_channel_event: channel event con, type, id, event: 0, 0, 0, 3event_loop_channel_event: channel event con, type, id, event: 0, 0, 0, 3[root@net01 tests]# pwd/root/spice-0.14.0/server/tests[root@net01 tests]# 
原创粉丝点击