linux网络编程之socket(十五) UNIX域套接字编程和socketpair 函数
一、UNIX Domain Socket IPC
socket API原本是为网络通讯设计的,但后来在socket的框架上发展出一种IPC机 制,就是UNIX Domain Socket。虽然网络socket也可用于同一台主机的进程间通讯(通过loopback地址127.0.0.1),但是 UNIX Domain Socket用于IPC更有效率:不需要经过网络协议栈,不需要打包拆包、计算校验和、维护序号和应答等,只是 将应用层数据从一个进程拷贝到另一个进程。UNIX域套接字与TCP套接字相比较,在同一台主机的传输速度前者是后者的两 倍。这是因为,IPC机制本质上是可靠的通讯,而网络协议是为不可靠的通讯设计的。UNIX Domain Socket也提供面向流和 面向数据包两种API接口,类似于TCP和UDP,但是面向消息的UNIXDomain Socket也是可靠的,消息既不会丢失也不会顺序错 乱。 使用UNIX Domain Socket的过程和网络socket十分相似,也要先调用socket()创建一个socket文件描述符, address family指定为AF_UNIX,type可以选择SOCK_DGRAM或SOCK_STREAM,protocol参数仍然指定为0即可。 UNIX Domain Socket与网络socket编程最明显的不同在于地址格式不同,用结构体sockaddr_un表示,网络编程的socket地址是IP 地址加端口号,而UNIX Domain Socket的地址是一个socket类型的文件在文件系统中的路径,这个socket文件由bind()调用 创建,如果调用bind()时该文件已存在,则bind()错误返回。 #define UNIX_PATH_MAX 108 struct sockaddr_un { sa_family_tsun_family; /* AF_UNIX */ charsun_path[UNIX_PATH_MAX]; /* pathname */ }; 二、回射/客户服务器程序 通信的流程跟 前面说过的tcp/udp 是类似的,下面直接来看程序: /************************************************************************* > File Name: echoser_tcp.c > Author: Simba > Mail: dameng34@163.com > Created Time: Sun 03 Mar 2013 06:13:55 PM CST ************************************************************************/ #include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<errno.h> #include<sys/types.h> #include<sys/socket.h> #include<netinet/in.h> #include<string.h> #include<sys/un.h> #define ERR_EXIT(m) do { perror(m); exit(EXIT_FAILURE); } while (0) void echo_ser(int conn) { char recvbuf[1024]; int n; while (1) { memset(recvbuf, 0, sizeof(recvbuf)); n = read(conn, recvbuf, sizeof(recvbuf)); if (n == -1) { if (n == EINTR) continue; ERR_EXIT("read error"); } else if (n == 0) { printf("client closen"); break; } fputs(recvbuf, stdout); write(conn, recvbuf, strlen(recvbuf)); } close(conn); } /* unix domain socket与TCP套接字相比较,在同一台主机的传输速度前者是后者的两倍。*/ int main(void) { int listenfd; if ((listenfd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) ERR_EXIT("socket error"); unlink("/tmp/test socket"); //地址复用 struct sockaddr_un servaddr; memset(&servaddr, 0, sizeof(servaddr)); servaddr.sun_family = AF_UNIX; strcpy(servaddr.sun_path, "/tmp/test socket"); if (bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) ERR_EXIT("bind error"); if (listen(listenfd, SOMAXCONN) < 0) ERR_EXIT("listen error"); int conn; pid_t pid; while (1) { conn = accept(listenfd, NULL, NULL); if (conn == -1) { if (conn == EINTR) continue; ERR_EXIT("accept error"); } pid = fork(); if (pid == -1) ERR_EXIT("fork error"); if (pid == 0) { close(listenfd); echo_ser(conn); exit(EXIT_SUCCESS); } close(conn); } return 0; }
(编辑:佛山站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |