May 14

套接口层(系统网络层)

  • 操作系统提供的网络接口

层对象: socket

网络层(传输层) net

  • 网络连接
  • 网络报文接收发送

层对象: xprt(transport), link, packet

服务层(会话层) svc

  • 用户登录
  • 用户请求接收, 响应发送

层对象: server, client, request

待补充…

Written by benegg at 2009-05-14 10:41:13 | tags:

Apr 16
/* file: net/sunrpc/svc.c */
struct svc_serv *svc_create(struct svc_program *, unsigned int, sa_family_t,
			    void (*shutdown)(struct svc_serv *));

实际上调用的是私有函数 __svc_create(), 分配 RPC 服务(svc_serv)的内存空间. 结构体 svc_server 是整个 RPC 服务(服务器/客户端)的表示. 和 svc_create_pooled 不同, 本函数一般用来创建 RPC 客户端[待求证?].

/* file: net/sunrpc/svc.c */
struct svc_serv *  svc_create_pooled(struct svc_program *, unsigned int,
			sa_family_t, void (*shutdown)(struct svc_serv *),
			svc_thread_fn, struct module *);

与 svc_create 类似, 一般用来创建 RPC 服务器, 因为它创建的是 RPC 服务的线程池. RPC 服务器需要使用线程池, 以便能并发的处理多个客户端的请求.

/* file: net/sunrpc/svc.c */
struct svc_rqst *svc_prepare_thread(struct svc_serv *serv,
					struct svc_pool *pool);

分配 RPC 服务线程所需的内存空间, 包括:

1. RPC 请求 svc_rqst
2. 解码之后的 RPC 请求 argp
3. 编码之前的 RPC 响应 resp,

解析之后的 RPC 请求, 是一个请求的语言相关表示, 在 Linux 源码中就是 C 语言表示. 如果使用 Java, 就可能是一个 Java 类. 所谓的语言相关, 是指在用相关的编程语言来描述的.

svc_rqst 既包含了语言相关的请求/响应表示, 也包含了请求/响应的字节数组表示.

/* file: net/sunrpc/svc.c */
void		   svc_exit_thread(struct svc_rqst *);

结束一个 RPC 服务器线程, 释放通过 svc_prepare_thread() 分配的所有空间, 同时还调用 svc_destroy() 销毁 svc_serv — 我认为应该在 svc_exit_thread 之外调用 svc_destroy(), 因为 svc_serv 不是在 svc_prepare_thread() 里创建的.

/* file: net/sunrpc/svc.c */
void		   svc_destroy(struct svc_serv *);

销毁一个 RPC 服务, 关闭所有 socket 连接, 释放服务的线程池空间和其本身.

/* file: net/sunrpc/svc.c */
int		   svc_process(struct svc_rqst *);

在本函数中解码请求, 处理, 编码响应, 发送响应. 详见: svc_process函数.

TODO: Linux 的 RPC 实现中, svc_serv 分别在服务器和客户端的角色.

Written by benegg at 2009-04-16 16:59:59 | tags: ,

Apr 09

一个RPC程序所要做的工作就是: 读取请求, 处理请求, 返回响应. 以nfsd为例, 其实现代码如下所示. 处理请求和返回响应放在同一个函数svc_process()里.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
/* in fs/nfsd/nfssvc.c: nfsd() */
 
struct svc_rqst *rqstp = (struct svc_rqst *) vrqstp;
...
/*
 * The main request loop
 */
for (;;) {
	/*
	 * Find a socket with data available and call its
	 * recvfrom routine.
	 */
	while ((err = svc_recv(rqstp, 60*60*HZ)) == -EAGAIN)
		;
	if (err == -EINTR)
		break;
	else if (err < 0) {
		if (err != preverr) {
			printk(KERN_WARNING "%s: unexpected error "
				"from svc_recv (%d)\n", __func__, -err);
			preverr = err;
		}
		schedule_timeout_uninterruptible(HZ);
		continue;
	}
 
	update_thread_usage(atomic_read(&nfsd_busy));
	atomic_inc(&nfsd_busy);
 
	/* Lock the export hash tables for reading. */
	exp_readlock();
 
	svc_process(rqstp);
 
	/* Unlock export hash tables */
	exp_readunlock();
	update_thread_usage(atomic_read(&nfsd_busy));
	atomic_dec(&nfsd_busy);
}

svc_recv()接受结构体svc_rqst的指针作为参数, 如果正常返回, svc_rqst包含了RPC请求报文的字节数组. svc_rqst的内存是在svc_recv()进进行分配.

Written by benegg at 2009-04-09 16:50:50 | tags: ,

Apr 08

svc_process函数是一条RPC报文的处理入口. 在该函数被调用之前, RPC报文只是一段字节数组, 被放在结构体svc_rqst中. 结构体还包含了整个RPC服务器的上下文环境, 包括所有的程序和它们的过程处理器.

在svc_process函数中, RPC报文字节数组被解码, 然后交给相应的程序和过程进行处理. svc_process的处理流程大致可以分为如下(但代码中并没有按这个顺序进行处理, 而是交叉在一起, 造成了不必要的混乱):

1. RPC请求报文长度验证.
2. 解码出请求首部.
3. 装配部分响应首部.
4. 身份验证, 并将验证信息装配进首部.
5. 查找RPC程序和过程.
6. 调用过程, 处理请求. 此时响应数据已经被写入响应报文中, 或者出错.
7. 发送响应.

Continue reading »

Written by benegg at 2009-04-08 08:49:48 | tags: ,