学习7-关于RPC的学习

2017年第一次修改:

最进准备学习rpc的代码,在网上找了一下代码,C语言的代码与C++的都可以快熟学习,研究整个软件的核心

研究片段服务层:简称Server

研究片段客服端:简称client


Server  段代码:

主要研究两个函数

 ch = minipc_server_create(argv[1], 0); 

shm_export_functions(ch)


minipc_server_action(ch, 1000);



而其中函数

int shm_export_functions(struct minipc_ch *ch)
{
int i;


/* Use a handy table for the registration loop */
static struct {
struct minipc_pd *desc;
minipc_f *f;
} export_list [] = {
{&rpc_getenv, shm_server_do_getenv},
{&rpc_setenv, shm_server_do_setenv},
{&rpc_add, shm_server_do_add},
{&rpc_strlen, shm_server_do_strlen},
{&rpc_strcat, shm_server_do_strcat},
{&rpc_stat, shm_server_do_stat},
};


其中:

struct minipc_pd rpc_stat = {
.name = "stat",
.retval = MINIPC_ARG_ENCODE(MINIPC_ATYPE_STRUCT, struct stat),
.args = {
MINIPC_ARG_ENCODE(MINIPC_ATYPE_STRING, char *),
MINIPC_ARG_ENCODE(MINIPC_ATYPE_STRING, char *),
MINIPC_ARG_END,
},
};

static int shm_server_do_strcat(const struct minipc_pd *pd,
      uint32_t *args, void *ret)
{
char *s, *t;
char scat[256];


s = (void *)args;
args = minipc_get_next_arg(args, pd->args[0]);
t = (void *)args;


strncpy(scat, s, sizeof(scat));
strncat(scat, t, sizeof(scat) - strlen(s));


strcpy(ret, scat); /* FIXME: max size */
return 0;
}

这段代码我们可以分析出:

分析一 :

shm_server_do_stat  函数地址存到了minipc_f *f;

参数:函数shm_server_do_stat的第一个参数const struct minipc_pd *pd,的作用是什么呢?

其实他的总用就是会存入参数的长度

而args参数这是全部字符串的集合,与使我们可以很轻松的得到全部的变量的值,

在单个函数的层面我分析完了此函数 

分析二:

//在函数的集合层面上来分析如何选着这个函数的

我们的Server段会在第二步:

shm_export_functions(ch) ;

我们就是会选着函数那么怎么实现的呢?

int minipc_export(struct minipc_ch *ch, const struct minipc_pd *pd)
{
struct mpc_link *link = mpc_get_link(ch);
struct mpc_flist *flist;


CHECK_LINK(link);


flist = calloc(1, sizeof(*flist));
if (!flist)
return -1;
flist->pd = pd;
flist->next = link->flist;
link->flist = flist;
return 0;
}

这个函数给了我们很好的解释:

他将server所有注册的函数存入一个Flistt的链表中(逻辑上连续),而我们要选着的函数的select着在ch中也存入了flist-》pd中(在同一个层级(地址上连续))

在这不中我并么有看到调用此函数的代码,这段代码主要是将他们存入flist链表中 

我们于是会问flist链表从哪里来的呢?

static void *calloc(size_t unused, size_t unused2)
{
int i;
struct mpc_flist *p;


for (p = __static_flist, i = 0; i < MINIPC_MAX_EXPORT; p++, i++)
if (!p->pd)
break;
if (i == MINIPC_MAX_EXPORT) {
errno = ENOMEM;
return NULL;
}
return p;
}

这段代码给了我们很好地启示:

tatic struct mpc_flist __static_flist[MINIPC_MAX_EXPORT];

它存贮在了一个全局的数组里面,此时我们知道了这个数组很关键,里面包含重要的数据

以上我们已经把第二步全部分析完成了 。


我们来分析第一步:

ch = minipc_server_create(argv[1], 0);


struct minipc_ch *__minipc_link_create(const char *name, int flags)
{
struct mpc_link *link;
struct sockaddr_un sun;
int fd, i;


link = calloc(1, sizeof(*link));
if (!link) return NULL;
link->magic = MPC_MAGIC;
link->flags = flags;
strncpy(link->name, name, sizeof(link->name) -1);


/* special-case the memory-based channels */
if (!strncmp(name, "shm:", 4) || !strncmp(name, "mem:", 4)) {
if (!__minipc_memlink_create(link))
goto out_free;
goto out_success;
}
/* now create the socket and prepare the service */
fd = socket(SOCK_STREAM, AF_UNIX, 0);
if(fd < 0)
goto out_free;
link->ch.fd = fd;
sun.sun_family = AF_UNIX;
strcpy(sun.sun_path, MINIPC_BASE_PATH);
strcat(sun.sun_path, "/");
strcat(sun.sun_path, link->name);
mkdir(MINIPC_BASE_PATH, 0777); /* may exist, ignore errors */


if (flags & MPC_FLAG_SERVER) {
unlink(sun.sun_path);
if (bind (fd, (struct sockaddr *)&sun, sizeof(sun)) < 0)
goto out_close;
if (listen(fd, 5) < 0)
goto out_close;
} else { /* client */
if (connect(fd, (struct sockaddr *)&sun, sizeof(sun)) < 0)
goto out_close;
}


/* success: fix your fd values, link to the list and return */
 out_success:
if (flags & MPC_FLAG_SERVER) {
for (i = 0; i < MINIPC_MAX_CLIENTS; i++)
link->fd[i] = -1;
FD_ZERO(&link->fdset);
FD_SET(link->ch.fd, &link->fdset);
}
link->addr = sun;
link->nextl = __mpc_base;
__mpc_base = link;
return &link->ch;


 out_close:
close(fd);
 out_free:
free(link);
return NULL;
}

这段代码给了我们很好的解释

它从存贮mpc_flist 中选着个list

之后干嘛

list 存 1:args参数

           2:flags参数

           3:存入socket句柄


我们第一步干了什么?其实就是选着了一个空的struct,之后存入已经连接上了可以读取数据的socket



第三部分析:

mpc_handle_client(link, -1, ch->fd);

for (i = 0; i < MINIPC_MAX_CLIENTS; i++) {
if (link->fd[i] < 0)
continue;
if (!FD_ISSET(link->fd[i], &set))
continue;
mpc_handle_client(link, i, link->fd[i]);
}


着两类又分为

1对1关系

1对多关系

static void mpc_handle_client(struct mpc_link *link, int pos, int fd)
{
struct mpc_req_packet *p_in, _pkt_in;
struct mpc_rep_packet *p_out, _pkt_out;
struct mpc_shmem *shm = link->memaddr;
const struct minipc_pd *pd;
struct mpc_flist *flist;
int i;


if (shm) {
p_in = &shm->request;
p_out = &shm->reply;
/* read one byte, it's just a signal */
read(fd, &i, 1);
} else {
p_in = & _pkt_in;
p_out = & _pkt_out;
/* receive the packet and manage errors */
i = recv(fd, p_in, sizeof(*p_in), 0);
if (i < 0 && errno == EINTR)
return;
if (i <= 0)
goto close_client;
}


/* use p_in->name to look for the function */
for (flist = link->flist; flist; flist = flist->next)
if (!(strcmp(p_in->name, flist->pd->name)))
break;
if (!flist) {
if (link->logf)
fprintf(link->logf, "%s: function %s not found\n",
__func__, p_in->name);
p_out->type = MINIPC_ARG_ENCODE(MINIPC_ATYPE_ERROR, int);
*(int *)(&p_out->val) = EOPNOTSUPP;
goto send_reply;
}
pd = flist->pd;
if (link->logf)
fprintf(link->logf, "%s: request for %s\n",
__func__, pd->name);


/* call the function and send back stuff */
i = pd->f(pd, p_in->args, p_out->val);
if (i < 0) {
p_out->type = MINIPC_ARG_ENCODE(MINIPC_ATYPE_ERROR, int);
*(int *)(&p_out->val) = errno;
} else {
/* Use retval, but fix the length for strings */
if (MINIPC_GET_ATYPE(pd->retval) == MINIPC_ATYPE_STRING) {
int size = strlen((char *)p_out->val) + 1;


size = (size + 3) & ~3; /* align */
p_out->type =
__MINIPC_ARG_ENCODE(MINIPC_ATYPE_STRING, size);
} else {
p_out->type = pd->retval;
}
}


 send_reply:
if (shm) {
shm->nreply++; /* message already in place */
return;
}
/* send a 32-bit value plus the declared return length */
if (send(fd, p_out, sizeof(p_out->type)
    + MINIPC_GET_ASIZE(p_out->type), MSG_NOSIGNAL) < 0)
goto close_client;
return;


 close_client:
if (link->logf)
fprintf(link->logf, "%s: error %i in fd %i, closing\n",
__func__, i < 0 ? errno : 0, fd);
close(fd);
FD_CLR(fd, &link->fdset);
link->fd[pos] = -1;
return;
}

其中这段话:

i = recv(fd, p_in, sizeof(*p_in), 0);

我们将客户端发送过来的数据传入到了p_in结构体*对象 p_in中

for (flist = link->flist; flist; flist = flist->next)
if (!(strcmp(p_in->name, flist->pd->name)))
break;

这段话就是我们将传过来的数据中p_in中name与server全局对象flist中的args存入的name比较

成功获取到了flist对象

于是乎,


i = pd->f(pd, p_in->args, p_out->val);

我们调用Server段函数,取决于pd的值,我们在看pd的值从哪里来的

pd = flist->pd;

我们可以看到pd的值是从flist中来的,

flist从哪里来的呢?

我们知道了从Server数据中与client发送来的数据name匹配,来去Server数据的数据,取得了flist,数据是保存在了Server,有client来发送selector

分析到这里我们知道了这个架构的重要核心

在我们在分析一下,函数参数从哪里来的额呢?

从p_in->args client数据来的, 而此时p_out->val是没有值的,值是通过Server调用的函数来给定的

个人看了很多源码,觉得这个源码的数据理念其实比较常见,我自己虽然只用了半天的时间一边读一边写,但是

个人以后会抽空多研读几遍,这个代码值得学习与借鉴 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值