16.unix域协议

来源:互联网 发布:韩国三角饭团淘宝 编辑:程序博客网 时间:2024/05/17 07:36

一.Unix域协议

Uinx域套接字有几个理由:

         UNIX域套接字用于在同一台机器上运行的进程之间的通信。虽然因特网域套接字也可以达到同一目的,但UNIX域套接字的效率更高

         UNIX域套接字仅仅复制数据;它们并不执行协议处理,不需要添加或删除网络报头,无需计算检验和,不要产生顺序号,无需发送确认报文。

         UNIX域套接字提供流和数据报两种接口。

         UNIX域数据报服务是可靠的,既不会丢失消息也不会传递出错。

         UNIX域套接字是套接字和管道之间的混合物。为了创建一对非命名的、相互连接的UNIX域套接字,用户可以使用它们面向网络的域套接字接口,也可使用socketpair函数

         UNIX域套接字可用在同一个主机上的不同进程之间传递描述符.

在<sys/un.h>中有定义Unix域套接字地址结构,在ubuntu中的路径为:/usr/include/linux/un.h

struct sockaddr_un {
    __kernel_sa_family_t   sun_family; /* AF_UNIX */
    char   sun_path[UNIX_PATH_MAX];    /* pathname */
};

二.利用Unix域协议实现回射C/S服务器

echoser.c

#include <unistd.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <signal.h>#include <sys/un.h>#include <stdlib.h>#include <stdio.h>#include <errno.h>#include <string.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){bzero(recvbuf,sizeof(recvbuf));n = read(conn,recvbuf,sizeof(recvbuf));if(n==-1){if(n == EINTR) // 由于信号中断,没读到任何数据。continue;ERR_EXIT("read err");}else if(n == 0){printf("client close\n");break;}fputs(recvbuf,stdout);write(conn,recvbuf,strlen(recvbuf));}close(conn);}      int main(){int listenfd;if( (listenfd = socket(AF_UNIX,SOCK_STREAM,0)) < 0)ERR_EXIT("socket err");unlink("/tmp/test_socket"); // 删除文件struct sockaddr_un servaddr;bzero(&servaddr,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 err");if( listen(listenfd,SOMAXCONN) < 0)ERR_EXIT("listen err");int conn;pid_t pid;while(1){conn = accept(listenfd,NULL,NULL);if(conn == -1){if(conn == EINTR)continue;ERR_EXIT("accept err");}pid = fork();if(pid == -1)ERR_EXIT("fork err");if(pid == 0) // 子进程,不需要处理监听{close(listenfd);echo_ser(conn);exit(EXIT_SUCCESS);}// 父进程close(conn); // 父进程不需要已连接套接字}}



echocli.c

#include <unistd.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <signal.h>#include <sys/un.h>#include <stdlib.h>#include <stdio.h>#include <errno.h>#include <string.h>#define ERR_EXIT(m) \        do \        { \                perror(m); \                exit(EXIT_FAILURE); \        } while(0)        void echo_cli(int sock){char sendbuf[1024] = {0};char recvbuf[1024] = {0};while(fgets(sendbuf,sizeof(sendbuf),stdin) != NULL){// 发送数据write(sock,sendbuf,strlen(sendbuf));//接收数据read(sock,recvbuf,sizeof(recvbuf));// 打印接收缓冲区的数据fputs(recvbuf,stdout);// 缓冲区清空bzero(sendbuf,sizeof(sendbuf));bzero(recvbuf,sizeof(recvbuf)); }}                int main(){int sock;if ((sock = socket(AF_UNIX,SOCK_STREAM,0))<0)ERR_EXIT("socket err");struct sockaddr_un servaddr;bzero(&servaddr,sizeof(servaddr));servaddr.sun_family = AF_UNIX;strcpy(servaddr.sun_path,"/tmp/test_socket");if(connect(sock,(struct sockaddr*)&servaddr,sizeof(servaddr)) < 0)ERR_EXIT("connect err"); echo_cli(sock);return 0;}

三.Unix域协议编程要点

        (1)bind 成功时将创建一个文件,权限为0777 & ~umask
        (2)sun_path 最好用一个绝对路径
        (3)UNIX域协议支持流式套接字与报文套接字
        (4)UNIX域流式套接字connect发现监听队列满时立刻返回一个ECONNREFUSED,这和TPC不同,如果监听队列满,会忽略到来的SYN,这导致对方重传SYN


1 0