本地进程间通信——Unix域套接字_pf unix_llzhang_fly的博客-程序员宅基地

技术标签: 工作问题  _03_linux应用编程  

本地进程间通信机制

管道

对于本地进程间通信,普通管道提供了相关进程(都有相同的祖先)之间通信的一种方法,但是普通管道存在两种局限性:1)它只能在“相关进程间”(即父子进程)使用; 2)它是半双工的(半双工也就是收发不能同时进行)。

命名管道解决了第一个局限性,他能在不相关的进程之间进行数据通信,但是同样具有第二个局限性,即通常他们是半双工的。

域套接字

消息队列和unix域套接字没有上面所说的局限性的同性方法。

使用套接字除了可以实现网络间不同主机间的通信外,还可以实现同一主机的不同进程间的通信,且建立的通信是双向的通信。这里所指的使用套接字实现进程间通信,是将通信域指定为PF_UNIX来实现的;该函数的形式如下:

int socket(int domain, int type, int protocol);

socket函数中的domain参数用于指定通信域,domain参数取PF_UNIX时,表示创建UNIX域的套接字。使用PF_UNIX域的套接字可以实现同一机器上的不同进程间的通信。

调用bind函数实现了套接字与地址(这里是文件名)的绑定。bind函数的具体信息如下:

int bind(int sockfd, const struct sockaddr *my_addr, socklen_t addrlen);    其参数my_addr为指向结构体sockaddr_un的指针,该结构体的定义如下:

#define UNIX_PATH_MAX 255
struct sockaddr_un {
    sa_family_t sun_family;    /*PF_UNIX或AF_UNIX */
    char sun_path[UNIX_PATH_MAX];    /* 路径名 */
};
在该结构体中,sun_family为AF_UNIX。sun_path是套接字在文件系统中的路径名。

 Unix域套接字是通过套接字API实现的简单的协议族。实际上它并不代表一个网络协议;它只能连接到同一台机器上的套接字。它提供了灵活的IPC机制。它的地址是它所在的文件系统的路径名,创建之后套接字就和路径名绑定在一起。用来表示Unix域地址的套接字文件能够使用stat()但是不能通过open()打开,而且应该使用套接字API对它进行操作。
    Unix域套接字是面向连接的,每个套接字的连接都建立了一个新的通讯信道。服务器可能同时处理许多连接,但对于每个连接都有不同的文件描述符。这个属性使Unix域套接字能够比命名管道更好的适应IPC任务。

 

域套接字实例

在一个终端运行服务器,然后在另一个终端(在相同目录下)运行客户端。当从客户端输入一行时,数据将通过套接字送到服务器;当退出客户端,服务器将等待另外一个连接。

还可以通过客户端程序的重定向输入来传送文件,cat uclient.c | ./uclient  或  ./uclient < uclient.c。

 

socket 服务器、客户端进程间通信—使用库函数

1、编写功能函数:

编写copyData 函数(从from获取输入,打印输出到to 上),并制作一个动态库文件,供其他模块调用;

/* sockutil.c - Utility functions used in socket example programs */
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include "test_common.h"

/* issue an error message via perror() and terminate the program */
void PrintfError(char * message)
{
    perror(message);
    // exit(1);
}

/* 
   Copies data from file descriptor 'from' to file descriptor
   'to' until nothing is left to be copied. Exits if an error
   occurs. This assumes both from and to are set for blocking
   reads and writes. 
*/
void copyData(int from, int to)
{
    char buf[1024];
    int amount;
   
    while ((amount = read(from, buf, sizeof(buf))) > 0) {
        if (write(to, buf, amount) != amount) {
            PrintfError("write");
            return;
        }
    }

    if (amount < 0) {
        PrintfError("read");
	}
}

 test_common.h 的头文件:

[root@llz lib_so]# cat test_common.h 
#ifndef TEST_COMMON_H
#define TEST_COMMON_H

void PrintfError(char * message);
void copyData(int from, int to);

#endif

将功能函数生成动态库文件:

将test_common.c编译为动态库,编译命令:

   

【如上制作动态库文件的命令,不正确,虽然也制作了库文件,但是最后不能使用】

【如下:是正确的命令】(-c 表示生成可执行文件,-fPIC 表示生成的库文件与路径无关)

至此 libtest_common.so 动态库便生成了

 

2、实现socket 服务器、客户端

一个终端运行服务器,然后在另一个终端(在相同目录下)运行客户端。当从客户端输入一行时,数据将通过套接字送到服务器。当退出客户端,服务器将等待另外一个连接。

还可以通过客户端程序的重定向输入来传送文件,cat uclient.c | ./uclient 或 ./uclient < uclient.c。

2.1、编写功能函数:socket 服务器

zll@zll-Lenovo:~/Pro_Soft$ cat 06_linux_uinx_server.c
/* userver.c - Simple Unix Domain Socket server */

/* Waits for a connection on the ./sample-socket Unix domain
   socket. Once a connection has been established, copy data
   from the socket to stdout until the other end closes the
   connection, and then wait for another connection to the
   socket.
*/

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>

#include "test_common.h"          /* some public functions */

int main(void) {
    struct sockaddr_un address;	// #include <sys/un.h>
    int sock, conn;
    socklen_t addrLength;

	// AF 表示ADDRESS FAMILY 地址族 
	// PF 表示PROTOCL FAMILY 协议族
    if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
        PrintfError("socket");
	}

    /* Remove any preexisting socket (or other file) */
    unlink("./sample-socket");

    address.sun_family = AF_UNIX;       /* Unix domain socket */
    strcpy(address.sun_path, "./sample-socket");

    /* The total length of the address includes the sun_family element */
    addrLength = sizeof(address.sun_family) + strlen(address.sun_path);

    if (bind(sock, (struct sockaddr *)&address, addrLength)) {
        PrintfError("bind");
	}

    if (listen(sock, 5)) {
        PrintfError("listen");
	}

	/// 如何监听多个客户端的链接???
    while ((conn = accept(sock, (struct sockaddr *)&address, &addrLength)) >= 0) {
        printf("---- getting data, conn:%d\n", conn);
        copyData(conn, 1);
        printf("---- done\n");
        close(conn);
    }

    if (conn < 0) {
        PrintfError("accept");
	}
   
    close(sock);
    return 0;
}
zll@zll-Lenovo:~/Pro_Soft$ 

编译服务器程序:

注意:编译时需要指定编译路径(-L),以及需要的库名称(-l)。

如上所示:没有找到 lib,gcc 编译命令不正确:

正确的是:gcc  xxx.c  -o  xxx  -L  .  -l  动态库名称

如下图:提示PrintfError、copyData 没有定义,即 libtest_common.so 库文件制作的不对

重新制作动态库文件后,服务器可执行文件编译OK 了。

 

2.2、编写功能函数:socket 客户端

zll@zll-Lenovo:~/Pro_Soft$ cat 06_linux_uinx_client.c
/* uclient.c - Simple Unix Domain Socket client */

/* 
	Connect to the ./sample-socket Unix domain socket, copy stdin
	into the socket, and then exit.
*/

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>

#include "test_common.h" /* some public functions */

int main(void)
{
    struct sockaddr_un address;
    int sock;
    size_t addrLength;

    if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
        PrintfError("socket");
	}

    address.sun_family = AF_UNIX;	/* Unix domain socket */
    strcpy(address.sun_path, "./sample-socket");

    /* The total length of the address includes the sun_family element */
    addrLength = sizeof(address.sun_family) + strlen(address.sun_path);

    if (connect(sock, (struct sockaddr *) &address, addrLength)) {
        PrintfError("connect");
	}
	// 0 ==> std_input
    copyData(0, sock);
    close(sock);
    return 0;
}
zll@zll-Lenovo:~/Pro_Soft$ 

编译客户端程序:

2.3、socket 服务器、客户端执行结果:

客户端重定向发送数据给服务器: cat test_common.h | ./06_linux_uinx_client

 

不能同时启动多个客户端,待进一步优化。

 

 

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/llzhang_fly/article/details/108698885

智能推荐

【MQTT从入门到提高系列 | 04】MQTT应用协议之CONNECT与CONNACK_mqtt.connect_机器未来的博客-程序员宅基地

本文描述了MQTT应用协议中的Connect和ConnAck命令的细节。_mqtt.connect

UiPath PDF数据提取_uipath提取pdf文件中的附件_Mlxg2234的博客-程序员宅基地

UiPath PDF数据提取Uipath自动化工作中经常会遇到要PDF中的数据,Uipath通过使用Read PDF Text 或 Read PDF withOCR读取PDF文件,包名UiPath.PDF.Activities,UIpath默认时没有安装PDF包的,需要手动安装。安装PDF包打开Manage Packages选择All Packages输入UiPath.PDF,选择安装UiPath.PDF.Activities读取PDF文件新建Sequence,..._uipath提取pdf文件中的附件

Spring Boot的使用(一)_.requestmappinghandlermapping' that could not be f-程序员宅基地

目录一,spring boot简述二,spring boot项目的搭建2.1 pom文件2.2 主配置类2.3 @SpringBootApplication三,总结一,spring boot简述springboot是什么?简单地理解它是一个工具箱。它不是重复的造轮子,底层用的还是spring的那一套,不同的是它让spring的使用更为简单,让开发者真正的做到..._.requestmappinghandlermapping' that could not be found.

DRDB-程序员宅基地

DRDB1、主服务器配置:[root@master ~]# setup[root@master ~]# service network restart2、修改hosts文件:[root@manage ~]# echo "192.168.2.2 master ">>/etc/hosts[root@manage ~]# echo "192...

分享|2021行业数字化转型洞察系列报告之智能制造白皮书(附PDF)-程序员宅基地

数字经济浪潮席卷全球,随着德国“工业4.0” 、美国先进制造、英国工业2050、中国制造2025、等全球国家级战略部署,驱动传统产业加快推动新一轮产业革命,“智能制造” 已成为新的战略制高点,以智能制造为主攻方向,推动制造业数字化转型已成时代发展趋势。中国“十四五”规划纲要为制造业指明了方向:要加快补齐基础零部件及元器件、基础软件等瓶颈短板,推进制造业补链强链,改造提升传统产业,加快重点行业企业改造升级,深入实施智能制造与绿色制造工程,建设智能制造示范工厂,完善智能制造标准体系,培育先进制造业集群,推动集

【Django】同时部署Daphne,uWSGI并由Nginx服务器反向代理转发_uwsgis daphne同一端口-程序员宅基地

进入/etc/nginx/conf.d/*.confnginx的*.conf配置如下:upstream daphne{ # nginx通过socket在环回接口地址的9000端口与本地的daphne进程通信 # 支持ip:port模式以及socket file模式 server 127.0.0.1:9000;}upstream uwsgi{ # nginx通过socket在环回接口地址的9001端口与本地的uWSGI进程通信 # 支持ip:port模式以及socket _uwsgis daphne同一端口

随便推点

C语言考试题及答案(一)-程序员宅基地

C语言(一)一 选择题(7分,每小题0.5分)1.C语言源程序的基本单位是( )。A 过程 B 函数 C 子程序 D 标识符2.下列程序的输出结果是( c)。main( ){ int a=7,b=5;printf("%d\n",b=b/a);}A 5 B 1 C 0 D不确定值3.假设变量a,b均为整型,表达式(a=5,b=2,a>b?a++:b++,a+b)的值是(b )。A 7 B 8 C 9 D 24.设

nginx解决不支持path_info模式方案-程序员宅基地

nginx web服务器在默认情况下是不支持path_info模式的,那么这个时候需要我们自己手动的去配置配置文件即可,只需要在nginx配置文件中添加如下代码即可,如图备注:https://blog.csdn.net/tracywxh/article/details/42393247...

C# string与ASCII码相互转换及包含中文字符的转换方法_c# encoding.ascii.getbytes 中文-程序员宅基地

此文章分别转载自C#字符串转换为Acsii码,Ascii转化为字符串和ASP.NET 或C# 中ASCII码含中文字符的编解码处理 /// <summary> /// C# 字符转ASCII码 /// </summary> /// <param name="character"></param> /// <returns></returns> _c# encoding.ascii.getbytes 中文

python可视化调试工具_Python可视化调试_liansang99的博客-程序员宅基地

当前的pdb.set_trace()调用是在定义类时进行的,而不是在调用init之后。如果将pdb.set_trace()调用移到init中import pdbclass Coordinate(object):def __init__(self, x, y):pdb.set_trace()self.x = xself.y = ydef __repr__(self):return "Coord: "..._python 可视化 调式

项目管理工具选项评测指标-程序员宅基地

目 录 1. 概述...................................................................................................................... 42. 需求概述...................................................................................

Python+Appium+UIautomator之元素等待_uiautomator2 等待元素出现-程序员宅基地

一、隐式等待隐式等待,且方法如下:driver.implicitly_wait(20)隐式等待的解释:设置一个超时时间,在这个时间内会去不断寻找元素,超时找不到时就会报错;二、显示等待显示等待,方法如下:WebDriverWait(driver,20,2).until(lambda x:x.find_element_by_xpath("//*[@resource-id='com.tcl.live:id/tv_download']"))显示等待的解释:设置一个超时时间和一个元素查找条件,在_uiautomator2 等待元素出现