spice测试工程

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_t
sock_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, 3
event_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]# 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值