关于UNIX Domain Socket 编程

       进程间通信,通讯机制很快会从大脑中跑出一连串方法出来:共享内存、管道、有名管道、信号量、套接字(socket)等。提到socket 大家很快会想到的是 address family 为AF_INET  ,type为SOCK_DGRAM或SOCK_STREAM 。还有一种接触少的没有接触的人很多时候会忽略:UNIX Domain Socket 。解决同样的通信问题,但在效率上与可靠性上它(UNIX Domain Socket)会略胜一筹:不需要经过网络协议栈,不需要打包拆包、计算校验和、维护序号和应答等,只是将应用层数据从一个进程拷贝到另一个进程。 这是因为,IPC机制本质上是可靠的通讯,而网络协议是为不可靠的通讯设计的。UNIX Domain Socket也提供面向流和面向数据包两种API接口,类似于TCP和UDP,但是面向消息的UNIX Domain Socket也是可靠的,消息既不会丢失也不会顺序错乱。

         UNIX Domain Socket 的type同样可以选择SOCK_DGRAM或SOCK_STREAM ,address family 指定为AF_UNIX,protocol参数仍然指定为0即可。UNIX Domain Socket与网络socket编程最明显的不同在于地址格式不同,用结构体sockaddr_un表示,网络编程的socket地址是IP地址加端口 号,而UNIX Domain Socket的地址是一个socket类型的文件在文件系统中的路径,这个socket文件由bind()调用创建,如果调用bind()时该文件已存 在,则bind()错误返回。

int fd_server_listen(const char *filepath)// src >> "/var/fd.socket"
{
    int sockfd;
    struct sockaddr_un unix_addr;

    /* create a Unix domain stream socket */
    if((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
    {
        printf("domain socket server initialized fail!\n");
        return -1;
    }

    /* in case it already exists */
    unlink(filepath);

    /* fill in socket address structure */
    memset(&unix_addr, 0, sizeof(unix_addr));
    unix_addr.sun_family = AF_UNIX;
    strcpy(unix_addr.sun_path, filepath);

    /* bind the name to the descriptor */
    if(bind(sockfd, (struct sockaddr *)&unix_addr, SUN_LEN(&unix_addr)) < 0)
    {
        printf("domain socket server bind fail!\n");
        goto error;
    }

    if(chmod(filepath, S_IRUSR|S_IWUSR) < 0)
    {
        printf("chmod fail:%s\n", filepath);
        goto error;
    }

    /* tell kernel we're a server */
    if(listen(sockfd, 10) < 0)
    {
        printf("domain socket server listen fail!\n");
        goto error;
    }

    return sockfd;

error:
    close(sockfd);
    return -1;
}
int client_fd = accept(sockfd, NULL, NULL);
关于编程客户端,有关小小的细节注意下,就是socket的相应的路径需要相同例如:HYCGI_SERVSOCK_PATH 的路径应该是服务端src一样的。

 int InitSocket(int *cli_sockfd)
{
	struct sockaddr_un address;
	int sockfd;
	int len;
	
	/*创建socket,AF_UNIX通信协议,SOCK_STREAM数据方式*/
	if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) 
	{
		printf("InitSocket ::failed");
		return 1;
	}


	//addr
	address.sun_family = AF_UNIX;
	strcpy (address.sun_path, HYCGI_SERVSOCK_PATH);
	len = OFFSETOF(struct sockaddr_un, sun_path) + strlen(HYCGI_SERVSOCK_PATH);  

	/*向服务器发送连接请求*/
	if (-1 == connect (sockfd, (struct sockaddr *)&address, len) ) 
	{
		close(sockfd);
		char buf[64];
		sprintf(buf,"InitSocket::connect  errno = %d",errno);
		printf("%s"buf);
		return 2;
	}


	*cli_sockfd = sockfd;
	
	return 0;
}
关于UNIX Domain Socket 编程,以上是最基础的过程,个人感觉无论是管道还是这个,还是共享内存,抓住编程的初衷:数据的有效传递。相关的,对于多个线程间如何跟服务端通信,还需要设置相关定制协议即可。

阅读更多
换一批

没有更多推荐了,返回首页