Comparison of using Nim language and C language to call POSIX interface to transfer file descriptors

Time:2019-11-8

Transferring file descriptors between process groups is a common way for multi process servers to share sockets. Based on this way, round robin can be provided to make each server obtain a balanced load

Nim and C call the same POSIX interface in the following way. (in fact, Nim is the C POSIX interface called.)

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 = ['
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)
'] 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 = ['
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)
'] 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);
}

Recommended Today

Details of multi-path and large capacity hard disk mount under CentOS

I. application environment and requirementsBlade servers connect HP storage through fiber switches, forming a 2×2 link The storage capacity of the operating system for CentOS 6.4 64 bit mount is 2.5t Based on this application environment, two problems need to be solved: In order to ensure the stability and transmission performance of the link, multi-path […]