当前位置: 首页 > news >正文

Linux rpc_create_client RPC客户端与xprt传输绑定

Linux rpc_create_client RPC客户端与xprt传输绑定

rpc_create_client是SUNRPC层创建RPC客户端实例的核心函数,位于net/sunrpc/clnt.c。它完成struct rpc_clnt的分配与初始化,并将客户端绑定到一个已创建的传输通道(xprt)上。NFS客户端在挂载时通过rpc_create调用间接调用此函数。

函数原型:

```c
struct rpc_clnt *rpc_create(struct rpc_create_args *args)
{
struct rpc_xprt *xprt;
struct rpc_clnt *clnt = ERR_PTR(-EIO);

if (args->protocol == XPRT_TRANSPORT_TCP)
xprt = xprt_create_transport(XPRT_TRANSPORT_TCP, args->address,
args->addrsize, args->servername,
args->xprtsec);
else if (args->protocol == XPRT_TRANSPORT_UDP)
xprt = xprt_create_transport(XPRT_TRANSPORT_UDP, args->address,
args->addrsize, args->servername,
args->xprtsec);
else
return ERR_PTR(-EPROTONOSUPPORT);

if (IS_ERR(xprt))
return ERR_CAST(xprt);

clnt = rpc_create_client(xprt, args->program, args->version,
args->prognumber, args->authflavor);

...
return clnt;
}
```

rpc_create_client的核心实现:

```c
static struct rpc_clnt *rpc_create_client(struct rpc_xprt *xprt,
const struct rpc_program *program,
u32 version, u32 prognumber,
rpc_authflavor_t authflavor)
{
struct rpc_clnt *clnt = NULL;
const struct rpc_version *vers;
int err;

vers = rpc_verify_header(program, version);
if (IS_ERR(vers))
goto out_err;

clnt = kzalloc(sizeof(*clnt), GFP_KERNEL);
if (!clnt)
goto out_err;

clnt->cl_program = program;
clnt->cl_vers = vers;
clnt->cl_prog = prognumber;
clnt->cl_xprt = xprt;
clnt->cl_autobind = 1;
clnt->cl_timeout = xprt->timeout;
clnt->cl_metrics = alloc_percpu(struct rpc_clnt_metrics);
INIT_LIST_HEAD(&clnt->cl_tasks);
spin_lock_init(&clnt->cl_lock);
refcount_set(&clnt->cl_count, 1);
rpc_init_rtt(&clnt->cl_rtt_default, HZ);

err = rpc_register_client(clnt);
if (err)
goto out_err;

if (authflavor != RPC_AUTH_NULL) {
clnt->cl_auth = rpcauth_create(authflavor, clnt);
if (IS_ERR(clnt->cl_auth))
goto out_err;
}

return clnt;

out_err:
if (!IS_ERR_OR_NULL(clnt))
rpc_destroy_client(clnt);
return ERR_PTR(err);
}
```

xprt_create_transport是传输层创建函数,定义在net/sunrpc/xprt.c:

```c
struct rpc_xprt *xprt_create_transport(int xprt_type,
struct sockaddr *addr,
size_t addrlen,
const char *servername,
struct xprtsec_parms *xprtsec)
{
struct rpc_xprt *xprt;
const struct rpc_xprt_ops *ops;
int err;

ops = rpc_xprt_find_transport_owner(xprt_type);
if (!ops)
return ERR_PTR(-EPROTONOSUPPORT);

xprt = ops->alloc_xprt(xprt_sec);
if (!xprt)
return ERR_PTR(-ENOMEM);

xprt->ops = ops;
xprt->addr = *addr;
xprt->addrlen = addrlen;
xprt->servername = kstrdup(servername, GFP_KERNEL);
xprt->max_reqs = RPC_MAX_SLOT_TABLE;
xprt->min_reqs = 0;
xprt->num_reqs = 0;
xprt->cwnd = RPC_INITIAL_CWND;
xprt->timeout = NULL;
xprt->bind_timeout = RPC_BIND_TIMEOUT_DEF;
xprt->reestablish_timeout = RPC_REESTABLISH_TIMEOUT_DEF;
xprt->idle_timeout = RPC_MAX_IDLE_TIMEOUT_DEF;
xprt->cong = 0;

err = xprt->ops->xprt_setup(xprt, addr, addrlen);
if (err)
goto out_destroy;

return xprt;

out_destroy:
xprt->ops->destroy_xprt(xprt);
return ERR_PTR(err);
}
```

对于TCP传输,alloc_xprt指向xs_tcp_alloc_xprt:

```c
static struct rpc_xprt *xs_tcp_alloc_xprt(struct xprt_sec *xprtsec)
{
struct rpc_xprt *xprt = kzalloc(sizeof(*xprt), GFP_KERNEL);
if (!xprt)
return NULL;

xprt->ops = &xs_tcp_ops;
xprt->xprtsec = *xprtsec;
return xprt;
}
```

xprt_setup对应xs_tcp_setup_xprt,它创建内核socket并设置连接参数:

```c
static int xs_tcp_setup_xprt(struct rpc_xprt *xprt,
struct sockaddr *addr, size_t addrlen)
{
struct socket *sock;
int err, type = SOCK_STREAM;

err = __sock_create(xprt->xprt_net, addr->sa_family, type, IPPROTO_TCP,
&sock, 1);
if (err < 0)
return err;

sock->sk->sk_allocation = GFP_NOIO;
sock->sk->sk_use_task_frag = false;
xprt->inet = sock->sk;

err = kernel_connect(sock, addr, addrlen, O_NONBLOCK);
if (err < 0 && err != -EINPROGRESS)
goto out;

xprt->sock = sock;
xs_set_memalloc(xprt);
return 0;

out:
sock_release(sock);
return err;
}
```

客户端创建完成后,xprt与clnt之间的绑定通过cl_xprt字段维系。当RPC任务通过rpc_run_task启动时,任务通过task->tk_client->cl_xprt找到传输通道,调用xprt->ops->send_request发送RPC消息。接收路径则通过xprt->recv函数(对于TCP为xs_tcp_data_ready)完成,数据到达后调用xprt_complete_rqst完成请求-响应匹配。

绑定后的auth创建过程通过rpcauth_create初始化认证机制,常用的有RPC_AUTH_UNIX(AUTH_SYS)和RPC_AUTH_GSS(Kerberos)。认证句柄保存在cl_auth中,在每次RPC调用时通过rpcauth_refreshcred更新凭证。

http://www.jsqmd.com/news/1052830/

相关文章:

  • TWR-S08MM128开发板全解析:从8位MCU入门到医疗AFE应用实战
  • Microchip嵌入式开发:高效利用官方资源与构建代码保护体系
  • 防静电干燥剂特色定制厂家实力风云榜,综合实力推荐,价格透明不踩坑 - myqiye
  • OpenAI Agent Builder生产级部署:自建服务层实战指南
  • 终极指南:3步免费解锁Wand专业版完整功能,获得完美游戏修改体验
  • 大模型金鱼脑原理:看懂Messages数组与提示词缓存
  • PyInstaller与Amplpy的完美结合:打包优化程序的实战经验
  • emWin GUI控件深度定制:从BUTTON到CHECKBOX的自定义绘制实战
  • UV喷墨打印机批发价格透明榜单,2026实力测评避坑指南,高精度机型优选 - myqiye
  • Flink 代码跑在 IDEA 里,尝试连接 Kafka?Kafaka 装在 WSL2 中,怎么连接?
  • ARM7 LPC213x PLL配置与电源管理实战指南
  • AI助手内容安全规范与技术合规实践指南
  • OpenClaw工作流落地指南:4个核心Skills+5种部署+三层API配置
  • Windows本地部署Qwen3-14B:Ollama+Open WebUI极简实战
  • AI Skills实战指南:用GLM-4.7自动生成n8n工作流
  • 木马病毒防御实战:从原理剖析到企业级立体防护体系构建
  • EldenRingSaveCopier终极指南:3步解决艾尔登法环存档迁移难题
  • 吴文俊-李特特征列方法在Lean 4中的形式化验证实践
  • 2026汕头漏水检测维修本地口碑防水商家榜单:厨卫/阳台/屋面/地下室渗漏水维修,持证施工+明码实价,防水补漏公司TOP5推荐 - 即刻修防水
  • Agentic RAG实战:用AI Agent重构企业级知识服务
  • 2026河池漏水检测维修本地口碑防水商家榜单:厨卫/阳台/屋面/地下室渗漏水维修,持证施工+明码实价,防水补漏公司TOP5推荐 - 即刻修防水
  • 亮铁激光加工靠谱商家真实横评 2026选定再拍不交智商税 - myqiye
  • 5步实战指南:快速掌握Blender MMD Tools插件的高效配置
  • DeepSeek V3 API生产级接入:HTTP/2、字节级Token与结构化错误处理
  • 设备端RAG技术解析:ECG模型如何统一检索与压缩表征
  • 嵌入式GUI开发实战:深入解析emWin的TEXT与TREEVIEW控件应用
  • NXP i.MX与LS1028A平台TSN特性配置与测试实战指南
  • OpenClaw 2.6.4:零代码智能体工作流引擎实战指南
  • 信息物理系统韧性构建:从系统级属性到人机协同的实践解析
  • IPXWrapper终极指南:Windows 11玩转经典游戏的完整解决方案