[apue] 作为 daemon 启动, Unix Domain Socket 侦听失败?
前段时间写一个传递文件句柄的小 demo,有 server 端、有 client 端,之间通过 Unix Domain Socket 通讯。
在普通模式下,双方可以正常建立连接,当server端作为daemon启动时,则第一次启动成功,之后再启动, listen 会连接报 ENOTSUPP 错误,导致启动失败。
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 端的代码:
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 端代码:
一开始怀疑是用于 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 域套接字还有什么区别么?
暂时存疑……
[apue] 作为 daemon 启动, Unix Domain Socket 侦听失败?的更多相关文章
- [apue] 作为 daemon, 启动 Unix Domain Socket 侦听失败?
前段时间写一个传递文件句柄的小 demo,有 server 端.有 client 端,之间通过 Unix Domain Socket 通讯. 在普通模式下,双方可以正常建立连接,当server端作为d ...
- 由一个简单需求到Linux环境下的syslog、unix domain socket
本文记录了因为一个简单的日志需求,继而对linux环境下syslog.rsyslog.unix domain socket的学习.本文关注使用层面,并不涉及rsyslog的实现原理,感兴趣的读者可以参 ...
- 问题解决:psql: could not connect to server: No such file or directory Is the server running locally and accepting connections on Unix domain socket "/var/run/postgresql/.s.PGSQL.5432"?
错误提示: psql: could not connect to server: No such file or directory Is the server running locally and ...
- Unix domain socket 简介
Unix domain socket 又叫 IPC(inter-process communication 进程间通信) socket,用于实现同一主机上的进程间通信.socket 原本是为网络通讯设 ...
- linux一切皆文件之Unix domain socket描述符(二)
一.知识准备 1.在linux中,一切皆为文件,所有不同种类的类型都被抽象成文件(比如:块设备,socket套接字,pipe队列) 2.操作这些不同的类型就像操作文件一样,比如增删改查等 3.主要用于 ...
- php, hhvm与odp & Unix domain Socket方式
接上一篇,复习一下 启动php或hhvm: php/sbin/php-fpm start hhvm/bin/hhvm_control start 启动nginx或lighttpd: webserver ...
- 问题解决:psql: could not connect to server: No such file or directory Is the server running locally and accepting connections on Unix domain socket "/var/run/postgresql/.s.PGSQL.5432"?
错误提示: psql: could not connect to server: No such file or directory Is the server running locally and ...
- monitor a local unix domain socket like tcpdump
Can I monitor a local unix domain socket like tcpdump? - Super User https://superuser.com/questions/ ...
- ndk学习16: unix domain socket
一.UNIX Domain Socket 概念: UNIX Domain Socket是在socket架构上发展起来的用于同一台主机的进程间通讯(IPC) 特点: 1. 它不需要经过网络协议栈,不需要 ...
- Unix Domain Socket 域套接字实现
主要注意流程: STREAM SOCKET: Server : socket() ---> bind() ---> listen() ---> accept() Client: ...
随机推荐
- virtualbox中给redhat安装增强功能
关于虚拟机中安装redhat请参考其他教程: 1.点击虚拟机菜单:设备--安装增强功能.... 2.ssh连接到redhat,执行以下操作: [root@rhel-server ~]# mount / ...
- 系统环境变量中 HTTPS_PROXY 的误区
前段时间在测试一个连麦 demo,demo 简要说可以在内网环境中运行时,输入频道号就可以模拟连麦 但是在加入连麦时,一直返回错误 -2 EOF,询问得知,该错误的解释信息是"Service ...
- 项目实战:Qt+iMax6生命探测仪(探测障碍物、静止目标、动态目标、生命目标、探测半径、探测前方雷达显示、动态目标轨迹显示、探测热力图、探测过程存储与回放)
若该文为原创文章,转载请注明原文出处本文章博客地址:https://blog.csdn.net/qq21497936/article/details/110994486长期持续带来更多项目与技术分享, ...
- 推导式,集合推导式,生成器表达式及生成器函数day13
1.推导式 用一行循环判断遍历处一系列数据的方式 推导式在使用时,只能用for循环和判断,而且判断只能是单项判断 基本语法: lst = [i for i in range(1,51)] print( ...
- 【Azure Redis 缓存】Azure Reids是否可以开启慢日志(slowlog)和执行config指令
问题描述 使用Azure Redis,是否可以开启慢日志来查看最近时间中执行比较耗时的指令呢? 同时,如何执行Redis的Config只能来修改配置呢? 根本原因 一:Azure Reids通过Red ...
- Springboot 撞上 NebulaGraph——NGbatis 初体验
本文首发于 NebulaGraph 公众号 https://mp.weixin.qq.com/s/z56o6AEz1Z4RmS8Zdx6dTA 大家好,我是开源项目 NGbatis 的发起人大叶(Co ...
- Lua学习笔记3
Lua学习笔记3 IO读写 Lua中读写使用自带的I/O库处理文件. 分为简单模式和完全模式. 简单模式(simple model)拥有一个当前输入文件和一个当前输出文件,并且提供针对这些文件相关的操 ...
- php编写日历类
<?php /** * 日历类 * Class Calendar * @author fengzi * @date 2022-05-05 15:42 */ class Calendar{ pro ...
- 快速带你入门css
css复习笔记 1. css样式值 1.1 文字样式 1 p{ 2 font-size: 30px;/*设置文字大小*/ 3 font-weight: bold;/*文字加粗*/ 4 font-sty ...
- Jetpack Compose(3) —— 状态管理
上一篇文章拿 TextField 组件举例时,提到了 State,即状态.本篇文章,即讲解 State 的相关改概念. 一.什么是状态 与其它声明式 UI 框架一样,Compose 的职责非常单纯,仅 ...