使用 Nim 语言和使用 C 语言, 调用系统 POSIX 接口传递文件描述符的对比

news/2024/7/3 13:52:06

进程组之间传递文件描述符, 是多进程服务器共享套接字常用的方式. 基于此方式, 可以提供 round-robin , 使每个服务器获得平衡的负载.

Nim 和 C 语言调用相同的 POSIX 接口的编程方式如下, (事实上, Nim 是调用的 C POSIX 接口)

Nim

import posix

proc CMSG_LEN(length: cuint): cint {.importc, header: "<sys/socket.h>".}

proc socketpair(fds: var array[0..1, cint]): int {.inline.} =
    result = socketpair(AF_UNIX, SOCK_STREAM, 0, fds)

var 
    pipeFds: array[0 .. 1, cint]
    sockFds: array[0 .. 1, cint]

assert socketpair(pipeFds) == 0
assert socketpair(sockFds) == 0

####################### send model ###########################

var 
    sfd = pipeFds[0].SocketHandle()
    sDataBuff = ['\0']
    sIov = [TIOVec(iov_base: sDataBuff[0].addr(), iov_len: 1)]
    sCmsglen = CMSG_LEN(sizeof(SocketHandle).cuint())       # 20
    sCmsg = createU(Tcmsghdr, sCmsglen)
    sMsg = Tmsghdr(msg_name: nil, 
                   msg_namelen: 0,
                   msg_iov: sIov[0].addr(),
                   msg_iovlen: 1,
                   msg_control: sCmsg,
                   msg_controllen: sCmsglen.Socklen())

sCmsg.cmsg_len  = sCmsglen.Socklen()
sCmsg.cmsg_level = SOL_SOCKET
sCmsg.cmsg_type = SCM_RIGHTS
(cast[ptr int](CMSG_DATA(sCmsg)))[] = sockFds[0]

assert sfd.sendmsg(sMsg.addr(), 0) == 1
free(sCmsg)

####################### recv model ###########################

var 
    rfd = pipeFds[1].SocketHandle()
    rDataBuff = ['\0']
    rIov = [TIOVec(iov_base: rDataBuff[0].addr(), iov_len: 1)]
    rCmsglen = CMSG_LEN(sizeof(SocketHandle).cuint())       # 20
    rCmsg = createU(Tcmsghdr, rCmsglen)
    rMsg = Tmsghdr(msg_name: nil, 
                   msg_namelen: 0,
                   msg_iov: rIov[0].addr(),
                   msg_iovlen: 1,
                   msg_control: rCmsg,
                   msg_controllen: rCmsglen.Socklen())

assert rfd.recvmsg(rMsg.addr(), 0) == 1
assert rCmsg.cmsg_len == rCmsglen.Socklen()
assert rCmsg.cmsg_level == SOL_SOCKET
assert rCmsg.cmsg_type == SCM_RIGHTS
echo((cast[ptr int](CMSG_DATA(rCmsg)))[]) 

free(rCmsg)

C

#include <sys/socket.h>
#include <stdio.h>
#include <assert.h>
#include <malloc.h>

int main(int argc, char **argv) {
    int pipeFds[1];
    int sockFds[1];

    assert(socketpair(AF_UNIX, SOCK_STREAM, 0, pipeFds) == 0);
    assert(socketpair(AF_UNIX, SOCK_STREAM, 0, sockFds) == 0);

    /********************* send model *********************/

    struct msghdr sMsg;
    struct iovec sIov[1];
    char sDataBuff[1] = "";
    int sCmsglen = CMSG_LEN(sizeof(int));              // 20
    struct cmsghdr *sCmsg = malloc(sCmsglen);

    sIov[0].iov_base = sDataBuff;
    sIov[0].iov_len  = 1;

    sMsg.msg_name = NULL; 
    sMsg.msg_namelen = 0;
    sMsg.msg_iov = sIov;
    sMsg.msg_iovlen = 1;
    sMsg.msg_control = sCmsg;
    sMsg.msg_controllen = sCmsglen;                     // 20

    sCmsg->cmsg_len = sCmsglen;                         // 20
    sCmsg->cmsg_level = SOL_SOCKET;
    sCmsg->cmsg_type  = SCM_RIGHTS;
    *((int *)(CMSG_DATA(sCmsg))) = sockFds[0];

    assert(sendmsg(pipeFds[0], &sMsg, 0) == 1);
    free(sCmsg);

    /********************* recv model *********************/
    
    struct msghdr rMsg;
    struct iovec rIov[1];
    char rDataBuff[1] = "";
    int rCmsglen = CMSG_LEN(sizeof(int));               // 20
    struct cmsghdr *rCmsg = malloc(rCmsglen);

    rIov[0].iov_base = rDataBuff;
    rIov[0].iov_len  = 1;

    rMsg.msg_name = NULL; 
    rMsg.msg_namelen = 0;
    rMsg.msg_iov = rIov;
    rMsg.msg_iovlen = 1;
    rMsg.msg_control = rCmsg;
    rMsg.msg_controllen = rCmsglen;                     // 20

    assert(recvmsg(pipeFds[1], &rMsg, 0) == 1);
    
    assert(rCmsg->cmsg_len == rCmsglen);
    assert(rCmsg->cmsg_level == SOL_SOCKET);
    assert(rCmsg->cmsg_type == SCM_RIGHTS);
    printf("%d\n", *((int *)(CMSG_DATA(rCmsg))));       // 7

    free(rCmsg);
}

http://www.niftyadmin.cn/n/2015592.html

相关文章

Python模块导入时全局变量__all__的作用

Python中一个py文件就是一个模块&#xff0c;“__all__”变量是一个特殊的变量&#xff0c;可以在py文件中&#xff0c;也可以在包的__init__.py中出现。 1、在普通模块中使用时&#xff0c;表示一个模块中允许哪些属性可以被导入到别的模块中&#xff0c;如&#xff1a;全局变…

准备充分了嘛就想学函数式编程?(Part 2)

本文讲的是准备充分了嘛就想学函数式编程&#xff1f;(Part 2)&#xff0c;想要理解函数式编程&#xff0c;第一步总是最重要&#xff0c;也是最困难的。但是只要有了正确的思维&#xff0c;其实也不是太难。 之前的部分: 第一部分 友情提示 请读仔细读代码&#xff0c;确保继续…

Python浅拷贝和深拷贝的思考

简而言之&#xff0c;浅拷贝就是只是复制了引用&#xff0c;并没有复制引用指向地址的内容&#xff0c;可以看做是同一个对象&#xff0c;使用is操作符时返回true&#xff0c;而深拷贝刚好相反&#xff0c;不管变量或者对象包含多少其他的引用都原模原样复制一份&#xff0c;即…

Mysql创建多列唯一索引Sql

ALTER TABLE t_city_combo ADD UNIQUE INDEX t_city_combo_index (combo_id, combo_name, city_id) USING BTREE 语法 ALTER TABLE 表名英文 ADD UNIQUE INDEX 索引名英文 (列1英文, 列2英文, 列3) USING BTREE Navicat 创建索引&#xff0c;需要如下步骤 在表右键-->设计…

Python对象的命名和私有化

在Python中常见的变量和方法等命名通常是这样的&#xff1a;name&#xff1a;一般变量&#xff0c;在类中&#xff0c;类外都可以使用&#xff0c;对象直接可以访问__name:双下划线私有变量&#xff0c;在类中可以访问&#xff0c;类外不能直接访问_name:单下划线的变量&#x…

在Jmeter中使用自定义编写的Java测试代码

分类&#xff1a; 测试工具 2007-01-19 15:02 8204人阅读 评论(3) 收藏 举报 测试javaloadrunner编译器importtemplates我们在做性能测试时,有时需要自己编写测试脚本,很多测试工具都支持自定义编写测试脚本,比如LoadRunner就有很多自定义脚本的协议,比如"C Vuser",&…

Phtots框架简介

2019独角兽企业重金招聘Python工程师标准>>> Reference: http://www.jianshu.com/p/cc85282fac5e Phtots框架: 1.PHAsset:包含具体的每个照片的资源信息. 看看些常用的 api (1).资源的原信息. mediaType:PHAssetMediaType类型的枚举值:PHAssetMediaTypeUnknown 不知…

什么是零代码开发平台,为什么企业IT应该重视?

文/明道云创始人任向晖 零代码软件开发并非一个全新的概念。早在1992年&#xff0c;最早的零代码企业软件构建工具就出现在了微软的Office套件中&#xff0c;很多企业极客都记得那个叫做Access的数据库应用。只不过&#xff0c;当年的Access只是一个单机版的应用&#xff0c;数…