UNIX域协议(命名套接字)

这里主要介绍命名UNIX域套接字

1.什么是UNIX域套接字 Unix域协议并不是一个实际的协议族,而是在单个主机上执行客户/服务通信的一种方式。是进程间通信(IPC)的一种方式。 它提供了两类套接字:字节流套接字(有点像TCP)和数据报套接字(有点像UDP) UNIX域数据报服务是可靠的,不会丢失消息,也不会传递出错。 IP协议标识客户服务器是通过IP地址和端口号实现的,UNIX域协议中用于标识客户机和服务器的协议地址的是普通文件系统中的路径名。 2.UNIX域协议特点 1)UNIX域套接字域TCP套接字相比,在同一台主机的传输速度前者是后者的两倍。UNIX域套接字仅仅复制数据,并不执行协议处理,不需要添加或删除网络报头,无需计算校验和,不产生顺序号,也不需要发送确认报文 2)UNIX域套接字可以在同一台主机上各进程之间传递文件描述符 3)UNIX域套接字域传统套接字的区别是用路径名表示协议族的描述 3.UNIX域地址结构

#define UNIX_PATH_MAX 128 struct sockaddr_un{ sa_family_t sun_family; /* AF_UNIX 或者 AF_LOCAL */ char sun_path[UNIX_PATH_MAX]; /* path name */ };

4.使用实例,编程套路跟TCP很像。 Server:先创建套接字 -> 绑定地址 -> 监听 -> accept 客户端连接 -> 连接成功开始通信 -> 关闭套接字 Client:先创建套接字 -> 连接server -> 开始通信 -> 关闭套接字。 这里实现一个简单的回射服务器。 启动服务器,等待客户端连接,连接上之后,客户端通过标准输入接收数据发送给服务器。服务器接收数据以后,再把数据发送回客户端。 下面上代码:

server:

#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
#include<errno.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <sys/un.h>
//#include<netinet/in.h>
#define ERR_EXIT(m) \
    do \
    { \
        perror(m); \
        exit(EXIT_FAILURE); \
    } while(0)
#define UNIXSOCKETNAME "test_socket"
void echo_cli(int sock)
{
    char buf[1024] = {0};
    int ret = 0;
    while(1)
    {
        ret = read(sock, buf, sizeof(buf));
        if(ret == 0)
        {
            printf("client %d close\n", sock);
            break;
        }
        
        write(sock, buf, strlen(buf));
    }
    close(sock);
}
int main()
{
    int listenfd = socket(PF_UNIX, SOCK_STREAM, 0);
    if(listenfd < 0)
        ERR_EXIT("socket");
    unlink(UNIXSOCKETNAME);
    struct sockaddr_un servaddr;  // 头文件是这个 #include <sys/un.h>
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sun_family = AF_UNIX;
    strcpy(servaddr.sun_path, UNIXSOCKETNAME);
    if(bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)
        ERR_EXIT("bind");
    if(listen(listenfd, SOMAXCONN) < 0)
        ERR_EXIT("listen");
    int conn = 0;
    pid_t pid;
    while(1)
    {
        conn = accept(listenfd, NULL, NULL);
        if(conn == -1)
        {
            if(errno == EINTR)
                continue;
            ERR_EXIT("accept");
        }
        printf("Has new client connected, conn = %d\n", conn);
        pid = fork();
        if(pid < 0)
            ERR_EXIT("fork");
        else if(pid == 0)
        {            
            echo_cli(conn);
            exit(1);
        }
        else
            close(conn);
    }
    return 0;
}

client:

#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
#include<errno.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <sys/un.h>
//#include<netinet/in.h>
#define UNIXSOCKETNAME "test_socket"
#define ERR_EXIT(m) \
    do \
    { \
        perror(m); \
        exit(EXIT_FAILURE); \
    } while(0)
void echo_cli(int sock)
{
    char buf1[1024] = {0};
    char buf2[1024] = {0};
    int ret = 0;
    while(fgets(buf1, sizeof(buf1), stdin) != NULL)
    {
        write(sock, buf1, strlen(buf1));
        ret = read(sock, buf2, sizeof(buf2));
        if(ret == 0)
        {
            printf("server %d close\n", sock);
            break;
        }
        printf("%s", buf2);
        memset(buf1, 0, sizeof(buf1));
        memset(buf2, 0, sizeof(buf2));
    }
    close(sock);
}
int main()
{
    int sock = socket(PF_UNIX, SOCK_STREAM, 0);
    if(sock < 0)
        ERR_EXIT("socket");
    struct sockaddr_un servaddr;
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sun_family = AF_UNIX;
    strcpy(servaddr.sun_path, UNIXSOCKETNAME);
    if(connect(sock, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)
        ERR_EXIT("connect");
    echo_cli(sock);
    return 0;
}

 运行: 直接gcc编译,就可以运行了。先启动server,再启动client。 注意: 1)启动server后,bind后会在对应目录创建一个文件(权限是0777&~umask)。这文件的类型是s。表示是套接口文件。可以通过ls -al查看。

srwxrwxr-x  1 xcy xcy     0  1月  3 10:29 test_socket

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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏雪胖纸的玩蛇日常

python3+django2 开发易语言网络验证(下)

2753
来自专栏我的博客

TP入门第四天

1、URL大小写 默认配置:’URL_CASE_INSENSITIVE’  => false,   // URL地址是否不区分大小写 这样默认情况下是区分大小写...

3115
来自专栏软件开发 -- 分享 互助 成长

IP地址分类及私网IP

5类IP地址: IP地址共有32位字节,其中A~C类IP地址由类标识号、网络地址和主机地址组成,A类标识最高位为0,网络地址为1字节,主机地址为3字节, B类标...

2917
来自专栏JMCui

Linux 日常使用小记.

一、Oracle VirtualBox安装Linux7.0全屏设置 1. 点击菜单栏 设备 –> 分配光驱 –> 选择一个虚拟光盘,找到VirtualBox安装...

4316
来自专栏云计算教程系列

如何在Debian 9上使用Apt安装Java

Java和JVM(Java的虚拟机)是许多软件所必需的,包括Tomcat,Jetty,Glassfish,Cassandra和Jenkins。

7642
来自专栏PHP在线

php socket用法你知道吗?

本篇文章分享一个简单的socket示例,用php。实现一个接收输入字符串,处理并返回这个字符串到客户端的TCP服务。 产生一个 socket 服务端 <?php...

3924
来自专栏哎_小羊

Java Maven项目之Nexus私服搭建和版本管理应用

目录: Nexus介绍 环境、软件准备 Nexus服务搭建 Java Maven项目版本管理应用 FAQ 1、Nexus介绍 Nexus是一个强大的Mave...

5738
来自专栏Jed的技术阶梯

Redis 3.x 单节点和伪分布式安装

安装的时候指定端口号和命令执行路径,其余保持默认即可,这里演示另一个服务的安装并省略部分重复内容

1533
来自专栏散尽浮华

rsync+inotify实时同步环境部署记录

随着应用系统规模的不断扩大,对数据的安全性和可靠性也提出的更好的要求,rsync在高端业务系统中也逐渐暴露出了很多不足。 首先,rsync在同步数据时,需要扫描...

3277
来自专栏bboysoul

kali工具-DNSenmum

首先下载 git clone https://github.com/fwaeytens/dnsenum.git 根据里面的INSTALL.txt来安装 首...

1221

扫码关注云+社区

领取腾讯云代金券