Unix域套接字主要用于本机进程间的通信,传输速度是TCP的两倍。
1 Unix域地址结构
#define UNIX_PATH_MAX 108struct sockaddr_un{sa_family_t sun_family; //AF_UNIX或AF_LOCALchar sun_path[UNIX_PATH_MAX]; //pathname, unix域用路径名表示地址};
2 Unix域套接字注意
- sun_path最好使用绝对路径
- unix域协议支持流式和数据报式套接口
- unix域协议connect发现监听队列满里,会立刻返回ECONNREFUSED, 和TCP不同。
3 代码示例
server
#include <unistd.h>#include <sys/un.h>#include <stdlib.h>#include <stdio.h>#include <errno.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <string.h>#define ERR_EXIT(m)\do\{\perror(m);\exit(EXIT_FAILURE);\}while(0)void handle_subprocess(int conn){char buf[1024];int ret;while(1){memset(buf, 0, sizeof(buf));ret = read(conn, buf, sizeof(buf));if (ret == -1){if (ret == EINTR)continue;ERR_EXIT("read failed");}if (ret == 0){printf("client closed\r\n");break;}printf("%s\r\n", buf);write(conn, buf, strlen(buf));}close(conn);}int main(){int sock;//仍然使用socket函数创建socket,协议族指定为PF_UNIXif ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)ERR_EXIT("create unix socket failed");unlink("test socket");//先删除之前留下的socket文件sockaddr_un servaddr;servaddr.sun_family = AF_UNIX; //这里指定unix域协议strcpy(servaddr.sun_path, "test socket"); //指定socket文件,会再目录下生成该名称的文件//bindif (bind(sock, (sockaddr*)&servaddr, sizeof(servaddr)) < 0)ERR_EXIT("bind failed");//listenif (listen(sock, SOMAXCONN) < 0)ERR_EXIT("listen failed");int conn;pid_t pid;while(1){conn = accept(sock, NULL, NULL);if (conn == -1){if (conn == EINTR)continue;ERR_EXIT("accept failed");}pid = fork();if (pid == -1)ERR_EXIT("fork failed");if (pid == 0)//子进程{close(sock);handle_subprocess(conn);exit(EXIT_SUCCESS);}else{close(conn);}}close(sock);return 0;}
client
#include <unistd.h>#include <sys/un.h>#include <stdlib.h>#include <stdio.h>#include <errno.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <string.h>#define ERR_EXIT(m)\do\{\perror(m);\exit(EXIT_FAILURE);\}while(0)int main(){int sock;if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)ERR_EXIT("create unix socket failed");sockaddr_un servaddr;servaddr.sun_family = AF_UNIX; //这里指定unix域协议strcpy(servaddr.sun_path, "test socket");//start connect to the serverif (connect(sock, (sockaddr*)&servaddr, sizeof(servaddr)) < 0)ERR_EXIT("connect failed");char buf[1024];while (fgets(buf, sizeof(buf), stdin) != NULL){write(sock, buf, strlen(buf));read(sock, buf, sizeof(buf));//read reply from serverprintf("received from server: %s\r\n", buf);memset(buf, 0, sizeof(buf));}close(sock);}
4 socketpair全双工流通道
头文件: <sys/socket.h>
函数定义: int socketpair(int domain, int type, int protocol, int sv[2]);
功能: 创建一个全双工的流管道,用于父子进程间通信; 返回值为0,失败返回-1
参数:
- domain: 协议家族,指定为PF_UNIX
- type: 套接字类型,SOCK_STREAM流式套接字
- protocol: 协议类型
- sv: 返回的套接字对
socketpair不同与普通的pipe,是全双工的,两端可以同时发送和接收数据。代码示例如下:
#include "common.h"int main(){int socks[2];if(socketpair(PF_UNIX, SOCK_STREAM, 0, socks) < 0)ERR_EXIT("socketpair failed");pid_t pid;pid = fork();if (pid > 0){//父进程int val = 0;close(socks[1]);//只需要保留一个socket在该进程,另一个在另一进程while(1){++val;printf("send data: %d\r\n", val);write(socks[0], &val, sizeof(val));read(socks[0], &val, sizeof(val));printf("receive data: %d\r\n", val);sleep(1);}}else if (pid == 0){int val;close(socks[0]);while(1){read(socks[1], &val, sizeof(val));++val;write(socks[1], &val, sizeof(val));}}return 0;}
