Mac OSX下SO_NOSIGPIPE的怪异表现(二)
3 月.05, 2015 in
编程小记
为了测试进程间通讯的多种方式,尝试了使用unix domain。其使用很简单,等价于传统的tcp/udp通讯,不同之处在于使用了本地文件节点而不占用本地端口号。
下面是一个使用ipc unix domain通讯的server例子。
#include <stdlib.h> #include <stdio.h> #include <sys/socket.h> #include <sys/un.h> #include <string.h> #include <unistd.h> #include <sys/ioctl.h> #include <sys/types.h> #define UNIX_DOMAIN "/var/tmp/LinuxLessons.domain" int main(int argc, const char *argv[]) { int iret; unsigned long ul = 1; unsigned int ui = 1; struct sockaddr_un address; int hsocket = socket(PF_UNIX, SOCK_STREAM, 0); if (hsocket == -1) { perror("socket PF_UNIX create failure:"); return EXIT_FAILURE; } unlink(UNIX_DOMAIN); address.sun_family = AF_UNIX; strncpy(address.sun_path, UNIX_DOMAIN, sizeof(address.sun_path)-1); iret = bind(hsocket, (const struct sockaddr *)&address, (socklen_t)sizeof(address)); if(iret) { perror("socket PF_UNIX bind failure:"); close(hsocket); } ioctl(hsocket, FIONBIO, &ul); iret = listen(hsocket, 255); if (iret==-1) { perror("listen socket %d error:"); unlink(UNIX_DOMAIN); return EXIT_FAILURE; } for (;;) { fd_set set; struct timeval timeout; FD_ZERO(&set); FD_SET(hsocket, &set); memset(&timeout, 0x00, sizeof(timeout)); timeout.tv_usec = 500000; iret = select(hsocket+1, &set, NULL, NULL, &timeout); switch(iret) { case -1: perror("Select error"); break; case 0: printf("."); fflush(stdout); continue; default: if(FD_ISSET(hsocket, &set)) { struct sockaddr_un in_address; socklen_t len; int hclientsocket = accept(hsocket, (struct sockaddr *) &in_address, &len); if(hclientsocket<0) { perror("accept client connect error:"); break; } #ifdef __APPLE__ iret = setsockopt(hclientsocket, SOL_SOCKET, SO_NOSIGPIPE, &ui, (socklen_t)sizeof(int)); if(iret==-1) { perror("setsockopt SO_NOSIGPIPE:"); }else{ printf("setsockopt SO_NOSIGPIPE ok!\n"); } #endif iret = send(hclientsocket, "hello unix domain!", sizeof("hello unix domain!") - 1, MSG_DONTWAIT | #ifdef __APPLE__ SO_NOSIGPIPE #else MSG_NOSIGNAL #endif ); if(iret==-1) { perror("send data error"); }else if(iret==0){ printf("connection maybe down!\n"); }else{ printf("welcome msg sent, %d bytes!\n", iret); } }else{ printf("fd is not in set!\n"); } } } unlink(UNIX_DOMAIN); close(hsocket); return EXIT_SUCCESS; } |
大致的运行目的是启动后,向通过unix domain连接过来的客户端发送一个欢迎信息。遇到的奇诡之处在于:
1)鉴于mac os是基于freeBSD内核,遵守POSIX标准,我直接在macbook上编写并且运行了这个程序,且mac下send函数MSG_NOSIGNAL对应为SO_NOSIGPIPE,目的是不接收由于Client异常断开造成的Broken pipe信号。
2)实际测试SO_NOSIGPIPE在mac下(OS X Yosemite 10.10.2)send中无效;
3)使用setsockopt后有效。
即,在mac下总会提示”Broken pipe: 13″,然后程序退出。同期:
1)Linux下程序运行正常,pipe信号成功被屏蔽
2)mac下tcp socket程序正常,pipe信号成功被屏蔽。
结论:
mac(OS X)下对于unix domain,只支持setsockopt对SO_NOSIGPIPE的设置,算是OSX的BUG么?
Leave a Reply
You must be logged in to post a comment.