[apue]作为daemon启动,UnixDomainSocket侦听失败?

编程

前段时间写一个传递文件句柄的小 demo,有 server 端、有 client 端,之间通过 Unix Domain Socket 通讯。

在普通模式下,双方可以正常建立连接,当server端作为daemon启动时,则第一次启动成功,之后再启动, listen 会连接报 ENOTSUPP 错误,导致启动失败。

spipe.c

 1int cli_conn(constchar *name)

2{

3int fd, len, err, rval;

4struct sockaddr_un un;

5

6if ((fd = socket (AF_UNIX, SOCK_STREAM, 0)) < 0) {

7 printf ("create socket failed

");

8return -1;

9 }

10

11 printf ("create socket ok

");

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);

16if (connect (fd, (struct sockaddr *)&un, len) < 0) {

17 err = errno;

18 printf ("connect failed

");

19 rval = -4;

20goto errout;

21 }

22

23 printf ("connect to server ok

");

24return fd;

25errout:

26 close (fd);

27 errno = err;

28return rval;

29}

30

31

32int serv_listen (constchar *name)

33{

34int fd, len, err, rval;

35struct sockaddr_un un;

36

37if ((fd = socket (AF_UNIX, SOCK_STREAM, 0)) < 0) {

38 printf ("socket failed

");

39return -1;

40 }

41

42 printf ("create socket ok

");

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

49if (bind (fd, (struct sockaddr *)&un, len) < 0) {

50 err = errno;

51 printf ("bind failed

");

52 rval = -2;

53goto errout;

54 }

55

56 printf ("bind socket to path ok

");

57if (listen (fd, QLEN) < 0) {

58 err = errno;

59 printf ("listen failed, errno %d

", errno);

60 rval = -3;

61goto errout;

62 }

63

64 printf ("start listen on socket ok

");

65return fd;

66errout:

67 close (fd);

68 errno = err;

69return rval;

70}

71

72int serv_accept (int listenfd, uid_t *uidptr)

73{

74int clifd, err, rval;

75 time_t staletime;

76struct sockaddr_un un;

77struct stat statbuf;

78

79 size_t len = sizeof (un);

80if ((clifd = accept (listenfd, (struct sockaddr *)&un, &len)) < 0) {

81 printf ("accept failed

");

82return -1;

83 }

84

85 len -= offsetof (struct sockaddr_un, sun_path);

86 un.sun_path[len] = 0;

87 printf ("accept %s ok

", un.sun_path);

88

89 unlink (un.sun_path);

90return clifd;

91

92errout:

93 close (clifd);

94 errno = err;

95return 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

 1int main (int argc, char *argv[])

2{

3int c = 0;

4 log_open ("open.serv", LOG_PID, LOG_USER);

5

6 opterr = 0; // don"t want getopt() writting to stderr !

7while ((c = getopt (argc, argv, "d")) != EOF) {

8switch (c) {

9case"d":

10 debug = log_to_stderr = 1;

11break;

12case"?":

13 err_quit ("unrecongnized option: -%c", optopt);

14 }

15 }

16

17if (debug == 0)

18 {

19 log_to_stderr = 0;

20 daemonize ("opend");

21 }

22

23 loop ();

24return0;

25 }

 

不使用 -d 时表示 daemon 运行(与常识相反?),上面标黄的代码就是。

对应的 client 端代码:

csopenc.c

 

一开始怀疑是用于 listen 的本地 socket 文件已经存在,于是去 /tmp 目录看了下,果然有 opend 这个文件,删除之,再运行,不行;

然后怀疑是没有复用端口(?)所致,于是在 listen 之前添加了以下代码段:

1int opt = 1; 

2if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (constvoid *)&opt, sizeof(opt)) < 0) {

3 err = errno;

4 printf ("setsockopt failed

");

5 rval = -3;

6goto 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启动,UnixDomainSocket侦听失败? 的全部内容, 来源链接: utcz.com/z/512830.html

回到顶部