阅读 UNIX 网络编程卷一,有一道课后题不会,求大佬指点

2018-05-01 16:00:58 +08:00
 chashao
题目:11.11 如果找不到给定 IP 地址对应的主机名,gethostbyaddr 可能就得花很长时间(最长 80s)才能返回一个错误.编写一个新的名为 getnameinfo_timeo 的函数,它有一个额外的整数参数用于指定等待应答的最大秒数.如果发生超时并且没有设置 NI_NAMEREQD 标志,那就调用 inet_ntop 返回一个地址串.

我的问题是如何实现 timeout 功能?
1244 次点击
所在节点    问与答
5 条回复
seaswalker
2018-05-01 16:06:15 +08:00
猜一下,定时器?
XiaoxiaoPu
2018-05-01 16:07:32 +08:00
简单的方法就是多线程呗,起一个线程去调用 gethostbyaddr,主线程等待 timeout,超时了就把子线程杀掉,然后返回
geelaw
2018-05-01 16:24:13 +08:00
如果你用纯粹的 UNIX,似乎只有比较低效的方式,而且很容易受其他正在运行的子进程的干扰。

思路是这样的:fork 两个子进程,一个等待 timeout 那么多秒,另一个调用 gethostbyaddr,并尝试把结果告诉主进程(共享内存或者匿名管道),主进程用 wait,在其中一个子进程结束的时候就可以返回,所以是 whichever comes first,接下来可以杀掉另一个子进程并根据结果返回。

问题:如果调用这个东西之前 fork 出来了子进程,那么 wait 可能会拿到不是你控制(创建)的子进程的结果。

如果你的环境支持比 POSIX 更多的 API set,你可以尝试使用 WaitForMultipleObjectsEx 的等价物。
chashao
2018-05-01 16:39:29 +08:00
@geelaw 我看书 301 页对于 connect 的设置超时代码,能不能换成 gethostbyaddr
```c
static void getnameinfo_alarm(int signo) {
return;
}
int getnameinfo_timeo(const struct sockaddr *sockaddr, socklen_t addrlen,
char *host, socklen_t hostlen, char *serv, socklen_t servlen, int flag, int timeout){
Sigfunc *sigfunc;
sigfunc = Signal(SIGALRM, getnameinfo_alarm);
if (alarm(timeout) != 0) {
err_msg("alarm is aready set!");
}
int ret;
if ((ret = getnameinfo(sockaddr, addrlen, host, hostlen, serv, servlen, flag)) != 0) {
printf("getnameinfo error:%s", gai_strerror(ret));
}
alarm(0);
Signal(SIGALRM, sigfunc);
return ret;
}
```
geelaw
2018-05-01 16:44:02 +08:00
重新翻了一下 - - 发现有 waitpid,那一个土鳖的方法是循环 waitpid WNOHANG + sleep 直到超时到了。并没想过用 signal/alarm。

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

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

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

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

© 2021 V2EX