前段时间写一个传递文件句柄的小 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 域套接字还有什么区别么?

暂时存疑……

[apue] 作为 daemon 启动, Unix Domain Socket 侦听失败?的更多相关文章

  1. [apue] 作为 daemon, 启动 Unix Domain Socket 侦听失败?

    前段时间写一个传递文件句柄的小 demo,有 server 端.有 client 端,之间通过 Unix Domain Socket 通讯. 在普通模式下,双方可以正常建立连接,当server端作为d ...

  2. 由一个简单需求到Linux环境下的syslog、unix domain socket

    本文记录了因为一个简单的日志需求,继而对linux环境下syslog.rsyslog.unix domain socket的学习.本文关注使用层面,并不涉及rsyslog的实现原理,感兴趣的读者可以参 ...

  3. 问题解决: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 ...

  4. Unix domain socket 简介

    Unix domain socket 又叫 IPC(inter-process communication 进程间通信) socket,用于实现同一主机上的进程间通信.socket 原本是为网络通讯设 ...

  5. linux一切皆文件之Unix domain socket描述符(二)

    一.知识准备 1.在linux中,一切皆为文件,所有不同种类的类型都被抽象成文件(比如:块设备,socket套接字,pipe队列) 2.操作这些不同的类型就像操作文件一样,比如增删改查等 3.主要用于 ...

  6. php, hhvm与odp & Unix domain Socket方式

    接上一篇,复习一下 启动php或hhvm: php/sbin/php-fpm start hhvm/bin/hhvm_control start 启动nginx或lighttpd: webserver ...

  7. 问题解决: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 ...

  8. monitor a local unix domain socket like tcpdump

    Can I monitor a local unix domain socket like tcpdump? - Super User https://superuser.com/questions/ ...

  9. ndk学习16: unix domain socket

    一.UNIX Domain Socket 概念: UNIX Domain Socket是在socket架构上发展起来的用于同一台主机的进程间通讯(IPC) 特点: 1. 它不需要经过网络协议栈,不需要 ...

  10. Unix Domain Socket 域套接字实现

    主要注意流程: STREAM SOCKET: Server :  socket() --->  bind() ---> listen()  ---> accept() Client: ...

随机推荐

  1. 用ELK分析每天4亿多条腾讯云MySQL审计日志(2)--EQL

    上一篇介绍了用ELK分析4亿多条审计日志过程,现在介绍如何用Python3分析ES的程序 需要分析的核心库审计数据: 1,950多张表,几十个账号, 2,5种操作类型(select,update,in ...

  2. 解决:EXP-00003: 未找到段 (0,0) 的存储定义报错

    问题说明 DB服务器oracle版本:11.2.0.4.0 最近在客户端用exp命令导出部分表时报错,如题.搜索了一下,找到以下解决方案: 问题原因 Oracle 11g 有一个参数deferred_ ...

  3. qt基础知识总结

    qt基础知识总结 1.ctrl+r:快速运行 2.两种模式的区别: 一个是提供菜单栏的,一个不提供菜单栏 3.界面讲解 layouts:布局=水平布局+垂直布局+网格布局+表单布局 spacers:垫 ...

  4. pikachu sql inject header 注入

    使用admin登录 显示以下内容 朋友,你好,你的信息已经被记录了:点击退出 你的ip地址:172.17.0.1 你的user agent:Mozilla/5.0 (X11; Ubuntu; Linu ...

  5. Centos8上安装Redis5.X

    一.下载Redis 下载地址:wget http://download.redis.io/releases/redis-5.0.7.tar.gz 解压:tar -xzvf redis-5.0.7.ta ...

  6. 【Azure 应用服务】Python Function App重新部署后,出现 Azure Functions runtime is unreachable 错误

    问题描述 Python Function App重新部署后,出现 Azure Functions runtime is unreachable 错误 问题解答 在Function App的门户页面中, ...

  7. 【Azure 应用服务】如何从App Service for Linux 的环境中下载Container中非Home目录下的文件呢?

    问题描述 在App Service for Linux的环境中,我们能通过SSH进入到Container的环境中,并且可以通过在kudu站点的URL后面添加 /newui 打开一个适用于Linux环境 ...

  8. 【Azure 存储服务】关于Azure Storage Account(存储服务) 基于AAD用户的权限设定以及SAS key的管理问题

    问题描述 如何查到一个Storage Account曾经创建过多少SAS key,这些Key是否可以回收和限定?能否基于AAD身份对 Container / Folder 进行权限的设定和管理? 问题 ...

  9. 从实测出发,掌握 NebulaGraph Exchange 性能最大化的秘密

    自从开发完 NebulaGraph Exchange,混迹在各个 NebulaGraph 微信群的我经常会看到一类提问是:NebulaGraph Exchange 的性能如何?哪些参数调整下可以有更好 ...

  10. Java 手动抛异常

    1 package com.bytezero.throwable; 2 3 import java.io.File; 4 import java.io.FileInputStream; 5 impor ...