[apue] 作为 daemon, 启动 Unix Domain Socket …
2020-01-17 08:53:09来源:博客园 阅读 ()
[apue] 作为 daemon, 启动 Unix Domain Socket 侦听失败?
前段时间写一个传递文件句柄的小 demo,有 server 端、有 client 端,之间通过 Unix Domain Socket 通讯。
在普通模式下,双方可以正常建立连接,当server端作为daemon启动时,则第一次启动成功,之后再启动, listen 会连接报 ENOTSUPP 错误,导致启动失败。
spipe.c
1 int cli_conn(const char *name) 2 { 3 int fd, len, err, rval; 4 struct sockaddr_un un; 5 6 if ((fd = socket (AF_UNIX, SOCK_STREAM, 0)) < 0) { 7 printf ("create socket failed\n"); 8 return -1; 9 } 10 11 printf ("create socket ok\n"); 12 memset (&un, 0, sizeof (un)); 13 un.sun_family = AF_UNIX; 14 strcpy (un.sun_path, name); 15 len = offsetof (struct sockaddr_un, sun_path) + strlen (name); 16 if (connect (fd, (struct sockaddr *)&un, len) < 0) { 17 err = errno; 18 printf ("connect failed\n"); 19 rval = -4; 20 goto errout; 21 } 22 23 printf ("connect to server ok\n"); 24 return fd; 25 errout: 26 close (fd); 27 errno = err; 28 return rval; 29 } 30 31 32 int serv_listen (const char *name) 33 { 34 int fd, len, err, rval; 35 struct sockaddr_un un; 36 37 if ((fd = socket (AF_UNIX, SOCK_STREAM, 0)) < 0) { 38 printf ("socket failed\n"); 39 return -1; 40 } 41 42 printf ("create socket ok\n"); 43 unlink (name); 44 memset (&un, 0, sizeof(un)); 45 un.sun_family = AF_UNIX; 46 strcpy (un.sun_path, name); 47 len = offsetof (struct sockaddr_un, sun_path) + strlen (name); 48 49 if (bind (fd, (struct sockaddr *)&un, len) < 0) { 50 err = errno; 51 printf ("bind failed\n"); 52 rval = -2; 53 goto errout; 54 } 55 56 printf ("bind socket to path ok\n"); 57 if (listen (fd, QLEN) < 0) { 58 err = errno; 59 printf ("listen failed, errno %d\n", errno); 60 rval = -3; 61 goto errout; 62 } 63 64 printf ("start listen on socket ok\n"); 65 return fd; 66 errout: 67 close (fd); 68 errno = err; 69 return rval; 70 } 71 72 int serv_accept (int listenfd, uid_t *uidptr) 73 { 74 int clifd, err, rval; 75 time_t staletime; 76 struct sockaddr_un un; 77 struct stat statbuf; 78 79 size_t len = sizeof (un); 80 if ((clifd = accept (listenfd, (struct sockaddr *)&un, &len)) < 0) { 81 printf ("accept failed\n"); 82 return -1; 83 } 84 85 len -= offsetof (struct sockaddr_un, sun_path); 86 un.sun_path[len] = 0; 87 printf ("accept %s ok\n", un.sun_path); 88 89 unlink (un.sun_path); 90 return clifd; 91 92 errout: 93 close (clifd); 94 errno = err; 95 return rval; 96 }
出错的位置在 serv_listen (line 57) 处,出错时的 server 端输出为:
Jan 17 00:24:44 localhost opend: create socket ok Jan 17 00:24:44 localhost opend: bind socket to path ok Jan 17 00:24:44 localhost opend: listen failed, errno 95 Jan 17 00:24:44 localhost opend: serv_listen error: Operation not supported
errno 95 为 ENOTSUPP。不以 daemon 运行时正常的输出如下:
create socket ok bind socket to path ok start listen on socket ok accept ok new connection: uid 0, fd 4
可能细心的读者会觉得,以 daemon 方式运行 printf 怎么还可以输出呢,是有以下宏定义做了处理:
1 #ifdef USE_APUE 2 #include "../apue.h" 3 #define printf log_msg 4 #endif
以 daemon 运行时会定义 USE_APUE 宏,从而将 printf 重定义为 log_msg 输出到 syslog。
下面是 server 端的代码:
csopend2.c
1 int main (int argc, char *argv[]) 2 { 3 int c = 0; 4 log_open ("open.serv", LOG_PID, LOG_USER); 5 6 opterr = 0; // don't want getopt() writting to stderr ! 7 while ((c = getopt (argc, argv, "d")) != EOF) { 8 switch (c) { 9 case 'd': 10 debug = log_to_stderr = 1; 11 break; 12 case '?': 13 err_quit ("unrecongnized option: -%c", optopt); 14 } 15 } 16 17 if (debug == 0) 18 { 19 log_to_stderr = 0; 20 daemonize ("opend"); 21 } 22 23 loop (); 24 return 0; 25 }
不使用 -d 时表示 daemon 运行(与常识相反?),上面标黄的代码就是。
对应的 client 端代码:
csopenc.c
一开始怀疑是用于 listen 的本地 socket 文件已经存在,于是去 /tmp 目录看了下,果然有 opend 这个文件,删除之,再运行,不行;
然后怀疑是没有复用端口(?)所致,于是在 listen 之前添加了以下代码段:
1 int opt = 1; 2 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&opt, sizeof(opt)) < 0) { 3 err = errno; 4 printf ("setsockopt failed\n"); 5 rval = -3; 6 goto errout; 7 }
设置端口复用。编译、运行,输出如下:
Jan 17 00:43:11 localhost opend: create socket ok Jan 17 00:43:11 localhost opend: bind socket to path ok Jan 17 00:43:11 localhost opend: set socket option ok Jan 17 00:43:11 localhost opend: listen failed, errno 95 Jan 17 00:43:11 localhost opend: serv_listen error: Operation not supported
设置成功了,但还是不行
难道 daemon 与普通进程使用 Unix 域套接字还有什么区别么?
暂时存疑……
原文链接:https://www.cnblogs.com/goodcitizen/p/12206544.html
如有疑问请与原作者联系
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
- [apue] epoll 的一些不为人所注意的特性 2020-06-05
- [apue] 书中关于打印服务代码的一个错误 2020-05-22
- [apue] apue_db:一个可以充当"注册表"的 2020-04-10
- docker安装后出现Cannot connect to the Docker daemon. 2020-04-03
- Linux 远程登录 2020-02-21
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash