前言介绍:
1。UNIX域套接字与TCP套接字相比较,在同一台主机的传输四度前者是后者的两倍
2.UNIX域套接字可以在同一台主机上各进程间传递描述符
3.UNIX域套接字与传统套接字的区别是用路径名来表示协议族的描述。
UNIX域地址结构
#define UNIX_PATH_MAX 108 struct sockaddr_un{ sa_family_t sun_family; /* AF_UNIX*/ char sun_path[UNIX_PATH_MAX]; /*pathname*/ }
下面 我们写一个简单的回射服务器来练习一下
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/un.h> #define ERR_EXIT(m) do { perror(m); exit(EXIT_FAILURE); }while(0) void echo_srv(int conn) { char recvbuf[1024]; int ret; while(1) { memset(recvbuf, 0, sizeof(recvbuf)); ret = read(conn, recvbuf, 1024); if(ret ==-1) { if(errno == EINTR) continue; ERR_EXIT("read"); }else if(ret == 0) { close(conn); printf("client close "); } fputs(recvbuf, stdout); write(conn, recvbuf, ret); } int main(int argc, const char *argv[]) { //使用UNIX域套接字,在申请套接字时就与TCP不同 // 需要使用一个PF_UNIX的宏,而不是pf_inet int listenfd = socket(PF_UNIX, SOCK_STREAM, 0); if(listenfd < 0) ERR_EXIT("SoCKET"); struct sockaddr_un servaddr; memset(&servaddr, 0, sizeof(servaddr)); servaddr.sun_family = AF_UNIX; strcpy(servaddr.sun_path, "test_socket"); if(bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0) ERR_EXIT("bind"); if(listen(listenfd, SOMAXCONN) < 0) ERR_EXIT("listen"); int conn; pid_t pid; while(1) { conn = accpet(listenfd, NULL, NULl); if(conn == -1) { if(errno == EINTR) continue; ERR_EXIT("accept"); } pid = fork(); if(pid == -1) ERR_EXIT("fork"); if(pid == 0) { close(listenfd); echo_srv(conn); exit(EXIT_SUCCESS); }else if(pid > 0) { close(conn); } } return 0 }
注意:
1.bind成功将会创建一个文件, 权限为0777, & umask = 755
2.sun_path最好用一个绝对路径
3.UNIX域协议支持流式套接字与报式套接口
4.UNIX与流式套接字connect发现监听队列满时,会立刻返回一个ECONNREFUSED, 这和TCP不同
如果监听队列满, 会忽略到来的SYN, 这导致对方重传SYN;