C 语言_REENTRANT 这个宏

2020-05-11 23:20:06 +08:00
 salamanderMH

问题

看了下这个库的源码,一个 FTP 的库,然后我看了下FtpConnect方法的实现,看到用到了_REENTRANT,不太清楚为什么要用这个宏,似乎是多线程有用

GLOBALDEF int FtpConnect(const char *host, netbuf **nControl)
{
    int sControl;
    struct sockaddr_in sin;
    int on=1;
    netbuf *ctrl;
    char *lhost;
    char *pnum;

    memset(&sin,0,sizeof(sin));
    sin.sin_family = AF_INET;
    lhost = strdup(host);
    pnum = strchr(lhost,':');
    if (pnum == NULL)
	pnum = "ftp";
    else
	*pnum++ = '\0';
    if (isdigit(*pnum))
	sin.sin_port = htons(atoi(pnum));
    else
    {
	struct servent *pse;
#if _REENTRANT
	struct servent se;
	char tmpbuf[TMP_BUFSIZ];
	int i;
	if ( ( i = getservbyname_r(pnum,"tcp",&se,tmpbuf,TMP_BUFSIZ,&pse) ) != 0 )
	{
	    errno = i;
	    if ( ftplib_debug )
		perror("getservbyname_r");
	    free(lhost);
	    return 0;
	}
#else
	if ((pse = getservbyname(pnum,"tcp") ) == NULL )
	{
	    if ( ftplib_debug )
		perror("getservbyname");
	    free(lhost);
	    return 0;
	}
#endif
	sin.sin_port = pse->s_port;
    }
    if ((sin.sin_addr.s_addr = inet_addr(lhost)) == INADDR_NONE)
    {
	struct hostent *phe;
#ifdef _REENTRANT
	struct hostent he;
	char tmpbuf[TMP_BUFSIZ];
	int i, herr;
	if ( ( ( i = gethostbyname_r( lhost, &he, tmpbuf, TMP_BUFSIZ, &phe, &herr ) ) != 0 ) ||
	     ( phe == NULL ) )
	{
	    if ( ftplib_debug )
		fprintf(stderr, "gethostbyname: %s\n", hstrerror(herr));
	    free(lhost);
	    return 0;
	}
#else
    	if ((phe = gethostbyname(lhost)) == NULL)
    	{
	    if (ftplib_debug)
		fprintf(stderr, "gethostbyname: %s\n", hstrerror(h_errno));
	    free(lhost);
	    return 0;
    	}
#endif
    	memcpy((char *)&sin.sin_addr, phe->h_addr, phe->h_length);
    }
    free(lhost);
    sControl = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (sControl == -1)
    {
	if (ftplib_debug)
	    perror("socket");
	return 0;
    }
    if (setsockopt(sControl,SOL_SOCKET,SO_REUSEADDR,
		   SETSOCKOPT_OPTVAL_TYPE &on, sizeof(on)) == -1)
    {
	if (ftplib_debug)
	    perror("setsockopt");
	net_close(sControl);
	return 0;
    }
    if (connect(sControl, (struct sockaddr *)&sin, sizeof(sin)) == -1)
    {
	if (ftplib_debug)
	    perror("connect");
	net_close(sControl);
	return 0;
    }
    ctrl = calloc(1,sizeof(netbuf));
    if (ctrl == NULL)
    {
	if (ftplib_debug)
	    perror("calloc");
	net_close(sControl);
	return 0;
    }
    ctrl->buf = malloc(FTPLIB_BUFSIZ);
    if (ctrl->buf == NULL)
    {
	if (ftplib_debug)
	    perror("calloc");
	net_close(sControl);
	free(ctrl);
	return 0;
    }
    ctrl->handle = sControl;
    ctrl->dir = FTPLIB_CONTROL;
    ctrl->ctrl = NULL;
    ctrl->data = NULL;
    ctrl->cmode = FTPLIB_DEFMODE;
    ctrl->idlecb = NULL;
    ctrl->idletime.tv_sec = ctrl->idletime.tv_usec = 0;
    ctrl->idlearg = NULL;
    ctrl->xfered = 0;
    ctrl->xfered1 = 0;
    ctrl->cbbytes = 0;
    if (readresp('2', ctrl) == 0)
    {
	net_close(sControl);
	free(ctrl->buf);
	free(ctrl);
	return 0;
    }
    *nControl = ctrl;
    return 1;
}
1148 次点击
所在节点    问与答
4 条回复
codehz
2020-05-11 23:30:44 +08:00
只是用作特性开关吧,某个地方定义之后就用可重入的那块,不然就普通的
shiny2017
2020-05-11 23:44:38 +08:00
主要是区分比如: getservbyname_r 与 gethostbyname 之类的接口, 不带_r 后缀的就是不可重入的, 比如 gethostbyname 使用了全局变量或者静态变量, 如果进程的多个线程同时调用又不加锁的情况下, 都更新相同的全局变量会产生问题的.
salamanderMH
2020-05-12 09:53:05 +08:00
@shiny2017 谢谢,那看起来`gethostbyname`和`getservbyname`有线程安全问题。
salamanderMH
2020-05-12 09:55:15 +08:00

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/670739

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX