[LWIP学习]--SylixOS AF_UNIX socket套接字分析

来源:互联网 发布:银天下交易软件 编辑:程序博客网 时间:2024/06/08 11:18

UNIX 域套接字是一种高级的 IPC 机制,这种形式的 IPC 可以在同一计算机系统上运行的两个进程之间进行通信。虽然因特网域套接字可用于同一目的,但 UNIX 域套接字的效率更高。 UNIX 域套接字仅仅复制数据,并不执行协议处理,因此,无需添加或者删除网络报头,无需计算校验和,无需产生序列号,无需发送确认报文等。
SylixOS 中的 UNIX 域套接字提供流( SOCK_STREAM)、数据报( SOCK_DGRAM)和连续数据报( SOCK_SEQPACKET)三种接口。
UNIX 域数据报服务是可靠的,既不会丢失报文也不会传递出错。 UNIX 域套接字就像是套接字和管道的混合,可以使用它们面向网络的域套接字接口或者使用 socketpair 函数来创建一对无命名的、相互连接的UNIX 域套接字。


下面分析一下UNIX 域套接字的源码。
1.首先分析socket函数:
socket函数中首先会对参数进行分析,UNIX套接字指支持AF_UNIX、SOCK_STREAM、SOCK_DGRAM、SOCK_SEQPACKET等参数。

AF_UNIX_T  *unix_socket (INT  iDomain, INT  iType, INT  iProtocol){    if (iDomain != AF_UNIX) {        return  (LW_NULL);    }    if ((iType != SOCK_STREAM) &&         (iType != SOCK_DGRAM)  &&        (iType != SOCK_SEQPACKET)) {        return  (LW_NULL);    }    pafunix = __unixCreate(iType);    if (pafunix == LW_NULL) {        _ErrorHandle(ENOMEM);    }...}

确认传入的参数无误后,创建af_unix控制块(其中创建了各自的二进制信号量),最后将af_unix控制块加入全局_G_plineAfUnix链表。(所有创建的UNIX 域套接字控制块都在该链表中)

static AF_UNIX_T  *__unixCreate (INT  iType){    ...    pafunix = (AF_UNIX_T *)__SHEAP_ALLOC(sizeof(AF_UNIX_T));    ...    pafunix->UNIX_hCanRead = API_SemaphoreBCreate("unix_rlock", LW_FALSE,                                                   LW_OPTION_OBJECT_GLOBAL, LW_NULL);    ...    _List_Line_Add_Ahead(&pafunix->UNIX_lineManage, &_G_plineAfUnix);    ...}

2.接着分析一下bind函数。因为应用于IPC,所以UNIX 域套接字不需要IP和端口,取而代之的是文件路径来表示“网络地址”。
在bind函数中会检索各个节点的文件路径,若文件路径已存在,bind失败。

INT  unix_bind (AF_UNIX_T  *pafunix, const struct sockaddr *name, socklen_t namelen){    ...    lib_strncpy(cPath, paddrun->sun_path, iPathLen);    ...    /*  创建 socket 文件            */    iFd = open(cPath, O_CREAT | O_RDWR, __AF_UNIX_DEF_FLAG | S_IFSOCK);     ....    /*  获得完整路径                 */    API_IosFdGetName(iFd, cPath, MAX_FILENAME_LENGTH);                      ...    /*  查询各节点是否存在该路径       */    pafunixFind = __unixFind(cPath, iSockType,                              (iSockType == SOCK_DGRAM) ?                             LW_FALSE : LW_TRUE);    ...    /*  若路径不存在,添加             */    lib_strcpy(pafunix->UNIX_cFile, cPath);    ...    close(iFd);}

3.UNIX 域套接字发送函数。
通过__AF_UNIX_WWRITE宏,阻塞等待二进制信号量,直到读端执行__unixUpdateWriter函数。

static ssize_t  unix_sendto2 (AF_UNIX_T  *pafunix, const void *data, size_t size,                               const void *data_ex, socklen_t size_ex, int flags,                              const struct sockaddr *to, socklen_t tolen){    ...    INT         i       = 0;                               /*  总发送次数              */    UINT        uiTimes = size >> __AF_UNIX_PIPE_BUF_SHIFT;/*  循环次数                */    UINT        uiLeft  = size & (__AF_UNIX_PIPE_BUF - 1); /*  最后一次数量             */    ...    do {          ...__try_send:        if (__unixCanWrite(pafunixRecver)) {                /*  可以发送               */            if (i < uiTimes) {                /*  可以发送               */                sstWriteNum = __unixSendtoMsg(pafunix, pafunixRecver,                                               pcSendMem, __AF_UNIX_PIPE_BUF,                                               data_ex, size_ex, flags);                ...                i++;                                        /*  发送次数++            */                bNeedUpdateReader = LW_TRUE;                /*  需要通知读端           */                goto    __try_send;                         /*  重新尝试发送数据        */            } else {                /*  最后一次发送                */                sstWriteNum = __unixSendtoMsg(pafunix, pafunixRecver,                                               pcSendMem, uiLeft,                                                   data_ex, size_ex, flags);                 ...                break;                                      /*  发送完毕             */            }        }        if (bNeedUpdateReader) {            bNeedUpdateReader = LW_FALSE;            __unixUpdateReader(pafunixRecver, ERROR_NONE);  /*  update remote reader */        }        ...            ulError = __AF_UNIX_WWRITE(pafunixRecver);      /*  等待可写              */        ...    } while (1);    if (bNeedUpdateReader) {        __unixUpdateReader(pafunixRecver, ERROR_NONE);      /*  update remote reader */    }    ...}

4.UNIX 域套接字接收函数
通过__AF_UNIX_WREAD宏,阻塞等待二进制信号量,直到写端执行__unixUpdateReader函数。

static ssize_t  unix_recvfrom2 (AF_UNIX_T  *pafunix,                                 void *mem, size_t len,                                 void *mem_ex, socklen_t *plen_ex, int flags,                                struct sockaddr *from, socklen_t *fromlen){    ...    do {        ...        if (__unixCanRead(pafunix, flags, len)) {            /*  可以接收             */     __recv_more:            /*  从缓冲区取一个消息          */            sstReadNum = __unixRecvfromMsg(pafunix,                                           (PVOID)pcRecvMem,                                            (size_t)(len - sstTotal),                                            mem_ex, plen_ex, flags,                                            (struct sockaddr_un *)from,                                            fromlen);                                pcRecvMem += sstReadNum;            sstTotal  += sstReadNum;            ...            break;                                           /*  跳出接收循环         */        } else if ((__AF_UNIX_TYPE(pafunix) == SOCK_STREAM) ||                   (__AF_UNIX_TYPE(pafunix) == SOCK_SEQPACKET)) {            return  (PX_ERROR);        }        ...        ulError = __AF_UNIX_WREAD(pafunix);                   /*  等待数据           */    } while (1);    ...        __unixUpdateWriter(pafunix, ERROR_NONE);              /*  update writer     */    ...}