UNIX域套接字

Posted illfuckingkyzb

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UNIX域套接字相关的知识,希望对你有一定的参考价值。

以下大部分来自:https://www.cnblogs.com/xcywt/p/8185597.html

——————————————————————————————

 

 

 

 

1.什么是UNIX域套接字
Unix域协议并不是一个实际的协议族,而是在单个主机上执行客户/服务通信的一种方式。是进程间通信(IPC)的一种方式。
它提供了两类套接字:字节流套接字(有点像TCP)和数据报套接字(有点像UDP)
UNIX域数据报服务是可靠的,不会丢失消息,也不会传递出错。

IP协议标识客户服务器是通过IP地址和端口号实现的,UNIX域协议中用于标识客户机和服务器的协议地址的是普通文件系统中的路径名。

2.UNIX域协议特点
1)UNIX域套接字域TCP套接字相比,在同一台主机的传输速度前者是后者的两倍。UNIX域套接字仅仅复制数据,并不执行协议处理,不需要添加或删除网络报头,无需计算校验和,不产生顺序号,也不需要发送确认报文
2)UNIX域套接字可以在同一台主机上各进程之间传递文件描述符
3)UNIX域套接字域传统套接字的区别是用路径名表示协议族的描述

下面是我的代码:

技术分享图片
#include<stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include<iostream>
#include<sys/un.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include<sys/select.h>
#include<errno.h>
#include<sys/signal.h>
using namespace std;
void handler(int sig){
     cout<<sig<<endl;
}
int main()
{   signal(SIGPIPE,SIG_IGN);
    //signal(SIGPIPE,handler);
    int sockfd = socket(PF_UNIX, SOCK_STREAM, 0);
    unlink("test_socket");
    if (sockfd == -1)
    {
        perror("socket() err");
        return -1;
    }
    int on = 1;
    if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1)
    {
        perror("setsockopt() err");
        return -1;}
    int conn;
    struct sockaddr_un addr;
    memset(&addr,0,sizeof(addr));
    addr.sun_family=AF_UNIX;
    strcpy(addr.sun_path,"test_socket");
    if (bind(sockfd, (struct sockaddr *) &addr, sizeof(addr)) == -1)
    {
        perror("bind() err");
        return -1;
    }
    if (listen(sockfd, SOMAXCONN) == -1)
    {
        perror("bind() err");
        return -1;
    }
    pid_t pid;
    while (1)
    {   conn=accept(sockfd,NULL,NULL);
        pid=fork();
        if(pid==0){
            close(sockfd);
            char recvbuf[1024];
            while(1){
        int rc = read(conn, recvbuf, sizeof(recvbuf));
        if (rc == 0)
        {
            printf("client is closed !
");
            break;
        } 
        else if (rc < 0)
        {
            printf("read() failed ! error message:%s
", strerror(errno));
            break;
        }
        printf("recv message:%s
", recvbuf);
        write(conn, recvbuf, rc);
                memset(recvbuf, 0, sizeof(recvbuf));
    }
            close(conn);
            exit(EXIT_SUCCESS);//记得退出子进程,否则子进程将会无限循环read错误
        }
        close(conn);
    }
    return 0;
}
server.cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include<sys/select.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include<iostream>
#include<sys/un.h>
using namespace std;
int main(){
int sockfd = socket(PF_UNIX, SOCK_STREAM, 0);
    if (sockfd == -1)
    {
        perror("socket() err");
        return -1;
    }
    struct sockaddr_un addr;
    addr.sun_family = AF_UNIX;
    strcpy(addr.sun_path,"test_socket");
    if (connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)) == -1)
    {
        perror("socket() err");
        return -1;
    }
    char sendbuf[1024]={0};
    char recvbuf[1024]={0};
                
   while(fgets(sendbuf,sizeof(sendbuf),stdin)!=NULL)
    {
        //send
        write(sockfd,sendbuf,sizeof(sendbuf));
        //recv
        int rc=read(sockfd,recvbuf,sizeof(recvbuf));
        if(rc<0)
        {
            perror("read() error");
            break;
        }else if(rc==0)
        {
            printf("connect is cloesd !
");
            break;
        }
        printf("recv message:%s
",recvbuf);
        memset(sendbuf,0,sizeof(sendbuf));
        memset(recvbuf,0,sizeof(recvbuf));
    }
   close(sockfd);
    return 0;
}

 

技术分享图片

技术分享图片

 

技术分享图片

在Linux中第一个字符代表这个文件是目录、文件或链接文件等等。

  • 当为[ d ]则是目录
  • 当为[ - ]则是文件;
  • 若是[ l ]则表示为链接文档(link file);
  • 若是[ b ]则表示为装置文件里面的可供储存的接口设备(可随机存取装置);
  • 若是[ c ]则表示为装置文件里面的串行端口设备,例如键盘、鼠标(一次性读取装置)。

 

1)启动server后,bind后会在对应目录创建一个文件(权限是0777&~umask)。这文件的类型是s。表示是套接口文件。可以通过ls -al查看。

2)若套接口文件存在,则bind会出错。为此可以先把该文件删掉。(server中的unlink就干这个的)
3)创建的套接口文件最好为绝对路径。建议指定在/tmp目录下。比如把上面的目录改成/tmp/test_socket
3)UNIX域流式套接字connect发现监听队列满时,会立刻返回一个ECONNREFUSED,这和TCP不同,如果监听队列满了,会忽略到来的SYN,这会导致对方重传SYN。











以上是关于UNIX域套接字的主要内容,如果未能解决你的问题,请参考以下文章

如何确定打开的套接字是 TCP 还是 unix 域套接字?

如何给UNIX域Socket套接字抓包?

《Unix 网络编程》15:Unix 域协议

unix进程间通信方式(下)-unix域套接字(转)

UNIX域套接字

UNIX域协议(命名套接字)