首页 > 系统相关 >unix domain 与本地本地回环在进程间通信中的差异

unix domain 与本地本地回环在进程间通信中的差异

时间:2023-04-20 19:48:53浏览次数:40  
标签:domain socket stCmd 间通信 UNIX fd 本地 sin 客户端

前言:

127.0.0.1它是一个私有IP,代表的就是你的本机环回地址,其实本质上是绑定在虚拟网卡loopback上的IP。
在实际应用中,有遇到在使用本地回环做进程间通讯的时候程序阻塞的情况。比如下面代码

(一)本地回环:

客户端数据收发程序:

static int send_recv(char *cmd, int *ret, char* strResult, int nSize)
{
	struct sockaddr_in sin;
	struct sockaddr_in cin;
	int port = PORT_FOR_SYSTEM;
	socklen_t addr_len;
	int s_fd;
	int n;
	ST_CMD_RESULT stCmdResult = {0};
	fd_set rfds;
    ST_CMD stCmd = {0};

    if (0 >= nSize || NULL == strResult)
    	stCmd.bNeedResult = 0;
    else
    	stCmd.bNeedResult = 1;
    strncpy(stCmd.strCmd, cmd, MAX_CMD_LEN);
    
    bzero(&sin, sizeof(sin));
    sin.sin_family = AF_INET;
    inet_pton(AF_INET, "127.0.0.1", &sin.sin_addr);
    sin.sin_port = htons(port);
    
    s_fd = socket(AF_INET, SOCK_DGRAM, 0);
    if(s_fd == -1)
    {
    	printf("create socket failed!\n");
    	return -1;
    }
    
    n = sendto(s_fd, &stCmd, sizeof(stCmd.bNeedResult) + strlen(stCmd.strCmd) + 1, 0, (struct sockaddr *) &sin, sizeof(sin));
    if(n == -1)
    {
    	printf("send failed!\n");
    	close(s_fd);
    	return -1;
    }
    
    FD_ZERO(&rfds);
    FD_SET(s_fd, &rfds);
    
    if(stCmd.bNeedResult)
    {
    	struct timeval tv_out;
    	tv_out.tv_sec = 5;
    	tv_out.tv_usec = 0;
    	n = select(s_fd+1, &rfds, NULL, NULL, &tv_out);    
    }
    else
    {
    	n = select(s_fd+1, &rfds, NULL, NULL, NULL); 
    }
    
    if (n == -1)
    {
    	printf("select error!\n");
    	close(s_fd);
    	return -1;
    }
    else if(n == 0)
    {
    	printf("recvfrom timeout!\n");
    	close(s_fd);
        return -1;
    }
    
    addr_len = sizeof(cin);
    n = recvfrom(s_fd, &stCmdResult, sizeof(stCmdResult), 0, (struct sockaddr *) &cin, &addr_len);
    *ret = stCmdResult.ret;
    strncpy(strResult, stCmdResult.strResult, nSize);
    if(n == -1)
    {
    	printf("recvfrom failed!\n");
    	close(s_fd);
    	return -1;
    }
    
    close(s_fd);
    
    return 0;
}

上面接口主要实现下面几个功能:

  1. 以本地环形地址为目标IP建立一个UDP链接
  2. 往链接中写入数据
  3. 根据是否需要应答设置不同的超时模式
  4. 接收服务端返回的数据

问题现象:

有时候发送数据的时候,该接口会被阻塞

问题解析:

1.当strResult 为空的时候,select 没有设置超时,这里会一直阻塞

根本原因:

为什么在这里select会一直阻塞?

是因为服务端没有返回数据到客户端,所以客户端就被一直阻塞了。

为什么服务端会没有数据返回?

除去服务端软件上的问题,还有一个原因是:因为使用的是本地回环,在一些嵌入式设备中,如果网卡驱动注册太慢,或者是没有注册网卡驱动,本地回环是不能工作的,所以服务端也就是会监听不到客户端的数据

对于这种情况,如果使用Unix domain socket(UDS) 就不会存在这样的问题。

(二)Unix domain socket(UDS)

UNIX Domain Socket是在socket架构上发展起来的用于同一台主机的进程间通讯(IPC),它不需要经过网络协议栈,不需要打包拆包、计算校验和、维护序号和应答等,只是将应用层数据从一个进程拷贝到另一个进程。

UNIX Domain Socket有SOCK_DGRAM或SOCK_STREAM两种工作模式,类似于UDP和TCP,但是面向消息的UNIX Domain Socket也是可靠的,消息既不会丢失也不会顺序错乱。

UNIX Domain Socket可用于两个没有亲缘关系的进程,是全双工的,是目前使用最广泛的IPC机制,比如X Window服务器和GUI程序之间就是通过UNIX Domain Socket通讯的。

工作流程

UNIX Domain socket与网络socket类似,可以与网络socket对比应用。

上述二者编程的不同如下:

  1. address family为AF_UNIX
  2. 因为应用于IPC,所以UNIXDomain socket不需要IP和端口,取而代之的是文件路径来表示“网络地址”。这点体现在下面两个方面。
  3. 地址格式不同,UNIXDomain socket用结构体sockaddr_un表示,是一个socket类型的文件在文件系统中的路径,这个socket文件由bind()调用创建,如果调用bind()时该文件已存在,则bind()错误返回。
  4. UNIX Domain Socket客户端一般要显式调用bind函数,而不象网络socket一样依赖系统自动分配的地址。客户端bind的socket文件名可以包含客户端的pid,这样服务器就可以区分不同的客户端。

---------------------------End---------------------------

长按识别二维码
关注 liwen01 公众号

标签:domain,socket,stCmd,间通信,UNIX,fd,本地,sin,客户端
From: https://www.cnblogs.com/liwen01/p/17337857.html

相关文章

  • 一种基于Unix Domain和TCP连接的跨设备多进程间通信的方法
    ​前言:在linux系统进程间通信的方式有消息,消息队列,管道,内存映射,套接字等多种方式。在Android系统上进行进程间通信主要是使用Binder,其它的还有共享内存,管道,RPC和UnixDomain等方式。但是,在linux中常用的消息队列,在Android等系统上并不能直接的使用,Android上常用的Binder,在其他......
  • (IDEA)spring项目导入本地jar包方法和项目打包时找不到引入本地jar包的问题解决方案
    转:(IDEA)spring项目导入本地jar包方法和项目打包时找不到引入本地jar包的问题解决方案 【Maven】理解maven的6大内置属性   ......
  • 【git】git批量删除本地分支
    删除分支命令gitbranch-DbranchName删除当前分支外的所有分支gitbranch|xargsgitbranch-d删除分支名包含指定字符的分支gitbranch|grep'upstream*'|xargsgitbranch-d该例将会删除分支名包含’dev’字符的分支。命令解释|管道命令,用于将一串命令串......
  • BOM-本地存储和会话存储
    1、介绍本地存储和会话存储,分别指window.localStorage和window.sessionStorage。两者具有基本相同的语法,都可以存储数据到浏览器中,区别在于localStorage是永久存储,而sessionStorage是会话存储。2、语法storage表示window.localStorage和window.sessionStorage。(1)写入或保存/......
  • Qt编写推流综合应用示例(文件推流/桌面推流/本地摄像头/网络摄像头/转发推流/视频分发)
    一、功能特点1.1文件推流指定网卡和监听端口,接收网络请求推送音视频等各种文件。实时统计显示每个文件对应的访问数量、总访问数量、不同IP地址访问数量。可指定多种模式,0-直接播放、1-下载播放。实时打印显示各种收发请求和应答数据。每个文件对应MD5加密的唯一标识符,用......
  • 大佬们,这个导包怎么写呀?本地执行可以,Linux执行报错
    大家好,我是皮皮。一、前言前几天在Python最强白银交流群【喜靓仔】问了一个Python路径处理的问题,这里拿出来给大家分享下。下图是他的代码:二、实现过程这里【小王子】给了一个答案,如下所示:代码如下:fromsysimportpathpath.insert(1,'../app/')importtesttest.test()顺利地......
  • 保姆级本地maven安装配置步骤【Windows】
    一、前期准备1、首先需要安装并配置好本地JDK(WIN+R输入cmd,输入java-version如下图)2、下载maven到本地(链接Maven–DownloadApacheMaven)其他历史版本在这里找:Indexof/maven/maven-3(apache.org)二、解压缩并配置环境变量1、解压maven压缩包到一个不包含空格以及中文的路径下......
  • “未在本地计算机上注册“Microsoft.ACE.OLEDB.12.0”提供程序
    不论是连接Access数据库或是SQLServer数据库,“未在本地计算机上注册“Microsoft.ACE.OLEDB.12.0”提供程序。”这个问题从Office2016开始,困扰了我好多年。我的软件版本:Win10(x64)版本系统+Office2019(x64)版本软件+VisualStudio2019今天终于得到解决。解决方法:(就两步,都......
  • linux Irq domain
    文章引用:https://blog.csdn.net/longwang155069/article/details/105812097为什么会引入IRQ_domain?早期中断数量较少,所以可以分布在一个interrupt_controler,中断映射也很简单,每个中断号对应一个interrupt_controler。 而当一个系统中有多个interrupt-controller的时候,而且中......
  • 本地升級stable-diffusion diffuser docker CUDA11.7 RTX2060
    1.0前言本地搭建stable-diffusiondiffuserdockerCUDA10.2RTX2060上次安裝的cuda10.2太舊了,升級cuda11.7順便填一下漏了的點。2.0卸載sudoapt-getremove--purge'^nvidia-.*'sudoapt-getremove--purge'^libnvidia-.*'sudoapt-getremove--purge'^cuda-.*&......