首页 > 系统相关 >Sword 进程间传递打开的文件描述符(API介绍)

Sword 进程间传递打开的文件描述符(API介绍)

时间:2023-02-25 13:44:06浏览次数:33  
标签:socket 缓冲区 描述符 API flags Sword msg 数据 CMSG

头文件

#include <sys/socket.h>

函数

int socketpair(int domain, int type, int protocol, int socket_vector[2]);

​函数建立一对匿名的已经连接的套接字,其特性由协议族domain、类型type、协议protocol决定,建立的两个套接字描述符会放在socket_vector[0]和socket_vector[1]中。

参数说明
domain:         表示协议族,只能为 ​AF_LOCAL ​或者​ AF_UNIX ​;
type:           表示协议,可以是​SOCK_STREAM、SOCK_DGRAM、SOCK_SEQPACKET;
protocol:       表示类型,一般为0;
socket_vector:  socket_vector[2]是接收代表两个套接口的整数数组。每一个文件描述符代表一个套接口,并且与另一个并没有区别。

返回值说明
成功执行时,返回0。失败返回-1,errno被设为以下的某个值

备注
socketpair接口设计的思考
原来我认为父进程通过 socket_vector[0] 写数据,子进程在 socket_vector[0] 读数据,这个理解是错误的,实际上是父进程通过socket_vector[0] 写数据A,而子进程在 socket_vector[1] 读数据A
这产生第一个问题,socket是如何通信的呢?
当建立一个socket的时候,服务端会accept一个fd1,客户端会connect一个fd2,fd1和fd2之间进行通信,fd1写数据只能在fd2去读数据,fd2写数据只能在fd1去读数据。
那么fd1写数据是否可以在fd1去读呢?
实践证明不行,fd1无法读自己写的数据。那么我们通常写文件,只有一个fd,写文件或者网络通信写数据都可以通过write函数来实现,
猜测write函数中对于文件fd和网络fd的处理是不同的,文件fd写可能是向磁盘发送命令,网络fd可能是向网卡发送命令。
Linux只是对一些操作抽象为文件,但是各个文件应该还是有类型的。
头文件

#include <sys/socket.h>

函数

ssize_t sendmsg(int socket, const struct msghdr *message, int flags);

用于通过socket发送数据

参数说明
socket:   套接字
message:  数据
flags:    默认值0即可

返回值说明
成功返回发送的字节数;失败返回-1
头文件

#include <sys/socket.h>

函数

ssize_t recvmsg(int socket, struct msghdr *message, int flags);

用于通过socket发送数据

参数说明
socket:   套接字
message:  数据
flags:    默认值0即可

返回值说明
成功返回接收的字节数;失败返回-1
struct msghdr {
    void         *msg_name;      
    socklen_t     msg_namelen;   
    struct iovec *msg_iov;       
    size_t        msg_iovlen;    
    void         *msg_control;   
    size_t        msg_controllen;
    int           msg_flags;     
};

msg_name,msg_namelen

如果套接字是在未连接的场合进行传输数据(例如未连接UDP套接字),
sendmsg函数: msg_name成员设置的是数据的接受者的地址,msg_namelen代表地址的长度
recvmsg函数: msg_name成员存放的是数据的发送者的地址,msg_namelen代表地址的长度
如果套接字是在已连接的场合进行传输数据(例如TCP通信/已连接UDP套接字),msg_name值为空指针,msg_namelen为0

msg_iov,msg_iovlen

struct iovec {
    void * iov_base; 
    size_t iov_len;  
};

msg_iov:用于发送/接受数据的缓冲区数组,可以用于发送/接受多组数据。每个成员是一个struct iovec类型的结构体
msg_iovlen:缓冲区数组元素个数
强调: 缓冲区是为msg_control准备的内存空间,不允许在CMSG_DATA操作之后对msg_iov[n]赋值,这会破坏已经存储的文件描述符


msg_control,msg_controllen

msg_control:用于设置/存放辅助数据。辅助数据的数据类型为struct cmsghdr。以struct cmsghdr结构体指针开头,可以为多组
msg_controllen:辅助数据的总大小/长度


msg_flags
只有recvmsg函数才使用msg_flags成员。当调用recvmsg函数时,recvmsg函数的flags参数被复制到msg_flags上,并由内核使用其值驱动接受处理过程
sendmsg函数不设置此参数。因为它直接使用sendmsg函数的flags参数驱动发送处理过程。(如果msg_flags设置了值,则被sendmsg函数忽略。例如flags设置了MSG_DONTWAIT,msg_flags也设置了该值,则msg_flags的被忽略)
struct cmsghdr 
{
   size_t cmsg_len;       辅助数据的总长度,由 CMSG_LEN 宏直接获取
   int    cmsg_level;     表示通道使用的的原始协议级别,与 setsockopt 函数的 level 参数相同
   int    cmsg_type;      控制信息类型,例如,SCM_RIGHTS,辅助数据是文件描述符;SCM_CREDENTIALS,辅助数据是一个包含证书信息的结构
    /* followed by unsigned char cmsg_data[]; */被注释的 cmsg_data 指明了物理内存中真正辅助数据的位置,帮助理解
};

#include <sys/socket.h>
#include <sys/param.h>
#include <sys/socket.h>
size_t CMSG_LEN(size_t length);
void* CMSG_DATA(struct cmsghdr *cmsg);

CMSG_FIRSTHDR() 宏:
返回一个指针,该指针指向与传递的msghdr关联的辅助数据缓冲区中的第一个cmsghdr。如果缓冲区中没有足够的空间可容纳cmsghdr,则返回NULL。

CMSG_NXTHDR() 宏:
返回传递的cmsghdr之后的下一个有效cmsghdr。当缓冲区中没有足够的空间时,它将返回NULL。
初始化将包含一系列cmsghdr结构的缓冲区时(例如,将通过sendmsg(2)发送),该缓冲区应首先初始化为零以确保CMSG_NXTHDR()的正确操作。

CMSG_ALIGN() 宏:
给定长度,CMSG_ALIGN()将返回它,包括所需的对齐方式。这是一个常量表达式。

CMSG_SPACE() 宏:
CMSG_SPACE()返回带有已传递数据长度的有效负载的辅助元素的字节数。这是一个常量表达式。

CMSG_DATA() 宏:
CMSG_DATA()返回一个指向cmsghdr的数据部分的指针。返回的指针不能被假定为适当对齐以访问任意有效载荷数据类型。应用程序不应将其强制转换为与有效负载匹配的指针类型,而应使用memcpy(3)将数据复制到适当声明的对象或从适当声明的对象复制数据。
CMSG_LEN() 宏:
CMSG_LEN()返回值,该值将存储在cmsghdr结构的cmsg_len成员中,同时考虑到任何必要的对齐方式。它以数据长度为参数。这是一个常量表达式。

图中被 recvmsg 修改过的字段标上了阴影。从第一幅图到第二幅图的变动包括以下几点:
a.由 msg_name 成员指向的缓冲区被填以一个网际网套接字地址结构,其中有所收到数据报的源 IP 地址和源 UPD 端口号。
b.msg_namelen 成员(一个值-结果参数)被更新为存放在 msg_name 所指缓冲区中的数据量。本成员并无变化,因为 recvmsg 调用前和返回后其值均为 16.
c.所收取数据报的前 100 个字节数据存放在第一个缓冲区,中 60 字节数据存放在第二个缓冲区,后 10 字节数据存放在第三个缓冲区。最后那个缓冲区的后 70 字节没有改动。recvmsg 函数的返回值(即 170)就是该数据报的大小。
d.由 msg_control 成员指向的缓冲区被填以一个 cmsghdr 结构。该 cmsghdr 结构中,cmsg_len 成员值为 16,cmsg_level 成员值为 IPPROTO_IP,cmsg_type 成员值为 IP_RECVDSTADDR,随后 4 个字节存放所收到 UDP 数据报的目的 IP 地址。这个 20 字节缓冲区的后 4 个字节没有改动。
e.msg_controllen 成员被更新为所存放辅助数据的实际数据量。本成员也是一个值-结果参数,recvmsg 返回时其结果为 16。
f.msg_flags 成员同样被 recvmsg 更新,不过没有标志返回给进程。

 

标签:socket,缓冲区,描述符,API,flags,Sword,msg,数据,CMSG
From: https://www.cnblogs.com/zhanggaofeng/p/17154262.html

相关文章

  • 【windows】测试获取进程资源占用的API的性能消耗
    背景一次性获取所有进程信息的API:NtQuerySystemInformation分别获取进程的cpu、mem、io的API:GetProcessTimes、GetProcessMemoryInfo、GetProcessIoCounters如果关注......
  • The bean ‘api‘, defined in class path resource [com/common/swagger/SwaggerAuto
    Thebean‘api‘,definedinclasspathresource[com/common/swagger/SwaggerAutoConf1.解决办法-1将重复的bean覆盖掉加一个这个注解spring.main.allow-bean-definit......
  • c# 调用chatgpt api
    前提:要有chatgpt账号,不会注册的关注抖音:21402780125,有免费教程!!在C#中调用ChatGPTAPI,您可以使用.NET内置的HTTPClient类或第三方的RestSharp类库。以下是使用.......
  • c语言调用chatgpt api
    前提:要有chatgpt账号,不会注册的关注抖音:21402780125,有免费教程!!在C语言中调用ChatGPTAPI,您需要使用C的网络编程库(例如libcurl)发送HTTP请求。以下是使用libcurl......
  • go语音 调用chatgpt api
    前提:要有chatgpt账号,不会注册的关注抖音:21402780125,有免费教程!!要在Go中调用ChatGPTAPI,您可以使用Go的net/http包或其他HTTP客户端库来发送HTTP请求。以下是......
  • php 调用chatgpt api
    前提:要有chatgpt账号,不会注册的关注抖音:21402780125,有免费教程!!要在PHP中调用ChatGPTAPI,您可以使用以下步骤:使用curl函数或其他HTTP客户端库发送HTTP请求。......
  • Python调用chatgpt api
    前提:要有chatgpt账号,不会注册的关注抖音:21402780125,有免费教程!! 要在Python中调用ChatGPTAPI,您可以使用以下步骤:首先,安装Python的HTTP客户端库,例如requests......
  • java调用chatgpt api
    前提:要有chatgpt账号,不会注册的关注抖音:21402780125,有免费教程!!要在Java中调用ChatGPTAPI,您可以使用以下步骤:首先,在您的Java项目中添加相关的HTTP客户端库,例如......
  • chatgpt api文档
    前提:要有chatgpt账号,不会注册的关注抖音:21402780125,有免费教程!!以下是OpenAIAPI中ChatGPT的主要文档内容:认证和授权您需要注册OpenAIAPI的账号并获得访问密钥......
  • .net 调用chatgpt api
    前提:要有chatgpt账号,不会注册的关注抖音:21402780125,有免费教程!!要在.NET中调用ChatGPTAPI,您可以使用以下步骤:安装System.Net.HttpNuGet包。创建一个HttpClie......