您的位置:首页 > 其它

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

2017-09-04 14:46 381 查看
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     */
...
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐