为了测试进程间通讯的多种方式,尝试了使用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么?