unix平台下I/O聚集和分离的一种方案

来源:互联网 发布:公司地址网络怎么收录 编辑:程序博客网 时间:2024/04/28 07:29

最近学习了两个unix平台下两个软件的构架,其中一个就是大名鼎鼎的oracle,首先oracle的体系结构官方又很多资料,以前的大牛也分析了很多,我就不说了(因为说起了又是一篇文章)。我对它们的I/O处理有一些认识,猜测其使用的技术。基本是前端有个listener接受请求,让后将“请求”发给server进程(这个里面有复杂的session机制在里面)。unix下“请求”的本质就是“文件描述符”所以这篇文章的技术本质就是“进程间传输文件描述符”!

一下是我对中间件I/O处理的一个实现:

假设一个系统有大量的不同的I/O请求(这个在中间件开发中尤其常见),我们的怎个平台设计可以类oracle

listener----〉server当然可以是多对多的关系!

listener:这里我们可以做I/O路由,请求缓存,甚至可以是异步处理!

server:当然就是业务逻辑的处理。

实现:

listener创建一个tcp服务,一个map(做I/O路由),unix socket(用于和server之间传输fd),一块共享内存(用来缓存请求的数据)

server创建一个unix socket(用于接收listener发送的文件描述符)。

服务的流程:

client---(tcp)--〉listener---(unix socket)---〉server

server--〉结果返回给client

我实现了一份具体的代码,可以去这里下载:http://download.csdn.net/detail/littlegrizzly/4090915

以下就是进程间传输文件描述符需要的两个功能函数:

/*
 * @file    server_utility.c
 * @author  Luo ZhiHui <camel.flying@gmail.com>
 * @version 1.0
 *
 * @section LICENSE
 *
 *
 * @section DESCRIPTION
 * Unix domain socket transfer multiple file descripers.
 */

#include <sys/types.h>
#include <sys/socket.h>

#define SEND_FD_NUMBER 2
#define    HAVE_MSGHDR_MSG_CONTROL
#define UNIX_SOCKET_PATH "/tmp/transmissionFD"

ssize_t send_fd(int fd, void *ptr, size_t nbytes, int *send_fd_array, size_t send_fd_num)
{
    struct msghdr    msg;
    struct iovec    iov[1];
    int index=0;

#ifdef    HAVE_MSGHDR_MSG_CONTROL
    union {
      struct cmsghdr    cm;
      char                control[CMSG_SPACE(sizeof(int)*send_fd_num)];
    } control_un;
    struct cmsghdr    *cmptr;

    msg.msg_control = control_un.control;
    msg.msg_controllen = sizeof(control_un.control);

    cmptr = CMSG_FIRSTHDR(&msg);
    cmptr->cmsg_len  =CMSG_LEN(sizeof(int)*send_fd_num);
    cmptr->cmsg_level = SOL_SOCKET;
    cmptr->cmsg_type = SCM_RIGHTS;
       
    for(index=0; index<send_fd_num; index++)
    {
        *((int*)(CMSG_DATA(cmptr)+sizeof(int)*index)) = send_fd_array[index];
    }
#else
    msg.msg_accrights = (caddr_t)send_fd_array
    msg.msg_accrightslen = sizeof(int)*send_fd_num;
#endif

    msg.msg_name = NULL;
    msg.msg_namelen = 0;

    iov[0].iov_base = ptr;
    iov[0].iov_len = nbytes;
    msg.msg_iov = iov;
    msg.msg_iovlen = 1;

    return(sendmsg(fd, &msg, 0));
}

ssize_t recv_fd(int fd, void *ptr, size_t nbytes, int *recv_fd_array, size_t recv_fd_num)
{
    struct msghdr    msg;
    struct iovec    iov[1];
    ssize_t            n;
    int index;

#ifdef    HAVE_MSGHDR_MSG_CONTROL
    union
    {
      struct cmsghdr    cm;
      char                control[CMSG_SPACE(sizeof(int)*(recv_fd_num))];
    } control_un;
    struct cmsghdr    *cmptr;

    msg.msg_control = control_un.control;
    msg.msg_controllen = sizeof(control_un.control);
#else
    int    newfd;

    msg.msg_accrights = (caddr_t)recv_fd_array;
    msg.msg_accrightslen = sizeof(int)*recv_fd_num;
#endif

    msg.msg_name = NULL;
    msg.msg_namelen = 0;

    iov[0].iov_base = ptr;
    iov[0].iov_len = nbytes;
    msg.msg_iov = iov;
    msg.msg_iovlen = 1;

    if ((n=recvmsg(fd, &msg, 0)) <= 0)
        return(n);

#ifdef    HAVE_MSGHDR_MSG_CONTROL
    if((cmptr = CMSG_FIRSTHDR(&msg))!=NULL && cmptr->cmsg_len==CMSG_LEN(sizeof(int)*(recv_fd_num)))
    {
        if(cmptr->cmsg_level != SOL_SOCKET)
        {
            return -1;
        }
        if(cmptr->cmsg_type != SCM_RIGHTS)
        {
            return -2;
        }
        for(index=0; index<recv_fd_num; index++)
        {
            recv_fd_array[index] =*((int *)(CMSG_DATA(cmptr)+sizeof(int)*index));
        }
    }
    else
    {
        recv_fd_array[0] = -1;        /* descriptor was not passed */
    }
#else
    if(msg.msg_accrightslen == sizeof(int)*recv_fd_num)
    {
        ;
    }
    else
    {
        recv_fd_array[0] = -1;        /* descriptor was not passed */
    }
#endif

    return(n);
}

申明:以上代码载自unix环境高级编程,参考代码是传输一个fd,本人将其改成一次传输多个fd(不知道是不是一种改进)在linux和aix下测试过

关于以上代码的解释可以参照这里:http://www.lslnet.com/linux/f/docs1/i48/big5327458.htm。

总结:传输fd好像用得并不多,通过自己的测试,进程间传递文件描述符的代价还是太大,但是确实有很多事情可以去这样做。很常见的方案就是多个用户态线程协作,把I/O分离解决(当然这是对I/O密集型系统)。

 

参考资料:

steven unix高级环境编程,

unix网络编程I

unix网络编程II

原创粉丝点击