最近学习了两个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
我实现了一份具体的代码,可以去这里下载:
以下就是进程间传输文件描述符需要的两个功能函数:
/* * @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下测试过
关于以上代码的解释可以参照这里:
参考资料:
steven unix高级环境编程,
unix网络编程I
unix网络编程II