首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 其他教程 > 互联网 >

20.匡助数据 和 传输描述字

2012-07-04 
20.辅助数据 和 传输描述字打开一个文件或者一个套接口,如果想把这个已经打开的文件和套接口的描述字传给

20.辅助数据 和 传输描述字

打开一个文件或者一个套接口,如果想把这个已经打开的文件和套接口的描述字传给其他的进程(仅限于本机),可以通过发送unix域的辅助数据来完成。当然如果这2个进程是父子进程,则问题要简单很多,因为子进程继承了父进程打开的描述字。下面的问题是:如何在2个没有关系的进程之间传递描述字。

?

辅助数据又叫做控制信息,在之前介绍sendmsg和recvmsg中,对于数据结构struct msghd中有个字段void * msg_control;没有介绍。这就是辅助数据存储地方以及socklen_t msg_controllen;辅助数据的长度。基于字面意思也就是它可以用来传递一些比较特殊的信息。

?

辅助数据的结构:

struct? cmsghdr {

?? socklen_t cmsg_len;

?? int cmsg_level;

?? int cmsg_type;

?? /* followed by unsigned char cmsg_data[] */

}

?

如果是IPV4协议,则cmsg_level为IPPROTO_IP. cmsg_type值可以为:IP_RECVDSTADDR(接受UDP数据报的目的地址) 或者是IP_RECVIF (接受UDP数据报的接口索引)。

?

如果为IPV6协议,cmsg_level为IPPROTO_IPV6. cmsg_type值可以为:

IPV6_DSTOPTS(指定/接收目标选项)

IPV6_HOPLIMIT(指定/接收跳限)

IPV6_HOPOPTS(指定/接收步跳选项)

IPV6_NEXTHOP(指定下一跳地址)

IPV6_PKTINFO(指定/接收分组信息)

IPV6_RTHDR(指定/接收路由头部)

?

如果UNIX域协议,cmsg_level为SOL_SOCKET。cmsg_type值可以为:

SCM_RIGHTS(发送/接收描述字)

SCM_CREDS(发送/接收用户凭证)。

?

辅助数据有一个或者多个辅助数据对象组成,每个对象由cmsghdr开头,其后跟了数据,在cmsg_type和实际数据之间可能有填充字节,一个数据对象和下一个对象之间也可能有填充字节。之所以要有填充字节是为了使整个数据对象按照cmsg_type结构对齐。因此为了方便操作就定义了以下几种宏操作:

?

CMSG_FIRSTHDR(struct msghdr * msg);//返回第一个cmsghdr结构指针

CMSG_NXTHDR(struct msghdr * msg, struct cmsghdr * cmsgptr);//指向cmsgptr的下一个cmsghdr指针

CMSG_DATA(struct cmsghdr * cmsgptr);//指向cmsgptr相关联的数据的第一个字节指针

CMSG_LEN(unsigned int length); //给定数据量下,存储在cmsg_len中的位置

CMSG_SPACE(unsigned int length); //给定数据量下,一个辅助数据对象的大小

?

相对比较抽象,通过代码及注释来看下:

代码实现的是同机器上2个进程间通过unix域传递打开的文件描述字。

#include "/programe/net/head.h"
#include "sys/un.h"
#include "stdio.h"
#include "stdlib.h"
#include "unistd.h"
#include "string.h"

//打开监听套接字,等待从另一个进程传递过来打开的文件描述字信息
int main(int argc, char ** argv) {
??????? char buf[100];
??????? int sockfd;
??????? struct sockaddr_un addr;

??????? sockfd = socket(AF_LOCAL, SOCK_STREAM, 0);
??????? bzero(&addr, sizeof(addr));
??????? addr.sun_family = AF_LOCAL;
??????? strncpy(addr.sun_path, argv[1], sizeof(addr.sun_path) - 1);
??????? unlink(argv[1]);
??????? int flag = bind(sockfd, (struct sockaddr *)&addr, SUN_LEN(&addr));//unix域,之前见过
??????? if(flag == -1) {
??????????????? printf("bind error\n");
??????????????? exit(1);
??????? }

??????? listen(sockfd, 10);

??????? int connfd = accept(sockfd, NULL, NULL);

??????? struct msghdr msg;
??????? struct iovec io;

??????? msg.msg_name = NULL;
??????? msg.msg_namelen = 0;
??????? io.iov_base = buf;
??????? io.iov_len = 100;
??????? msg.msg_iov = &io;
??????? msg.msg_iovlen = 1; //msg普通数据的定义,在sendmsg与recvmsg里面见过.

??????? union {
??????????????? struct cmsghdr cmsg;
??????????????? char control[CMSG_SPACE(sizeof(int))];
??????? } control_un; //为了使整个数据结构对齐,所以定义了union对象,当然也可以使用malloc
??????? struct cmsghdr * cmptr;
??????? msg.msg_control = control_un.control;
??????? msg.msg_controllen = sizeof(control_un.control); //因为只有一个数据对象传送

??????? ssize_t size = recvmsg(connfd, &msg, 0);
??????? buf[size] = '\0';
??????? printf("get message:%s\n", buf);

??????? cmptr = CMSG_FIRSTHDR(&msg);//在接受到返回结果后,得到第一个控制信息对象
??????? if(!cmptr) {
??????????????? printf("some thing error!!!\n");
??????? } else {
??????????????? int recvfd = *((int *)CMSG_DATA(cmptr));//获取文件描述字信息
??????????????? char my[100];
??????????????? int length = read(recvfd, my, 100);
??????????????? my[length] = '\0';
??????????????? printf("%s\n", my);
??????????????? close(recvfd);
??????? }
??????? close(connfd);
??????? close(sockfd);
??????? exit(0);
}

?

?

#include "stdio.h"
#include "stdlib.h"
#include "/programe/net/head.h"
#include "string.h"
#include "sys/un.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "fcntl.h"
//打开一个文件,并将描述字传递给另一个进程
int main(int argc, char ** argv) {
??????? int sockfd;
??????? char buf[] = "hello world";
??????? int file = open("/programe/net/temp.txt", O_RDONLY);//打开文件,file就是即将要传输的描述字

??????? sockfd = socket(AF_LOCAL, SOCK_STREAM, 0);
??????? struct sockaddr_un addr;
??????? bzero(&addr, sizeof(addr));
??????? addr.sun_family = AF_LOCAL;
??????? strncpy(addr.sun_path, argv[1], sizeof(addr.sun_path) - 1);

??????? connect(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr_un));

??????? struct msghdr msg;
??????? struct iovec io;

??????? union {
??????????????? struct cmsghdr cm;
??????????????? char control[CMSG_SPACE(sizeof(int))];
??????? } control_un; //同上

??????? struct cmsghdr * cmptr;
??????? msg.msg_control = control_un.control;
??????? msg.msg_controllen = sizeof(control_un.control);

??????? cmptr = CMSG_FIRSTHDR(&msg);
??????? cmptr->cmsg_len = CMSG_LEN(sizeof(int));
??????? cmptr->cmsg_level = SOL_SOCKET;
??????? cmptr->cmsg_type = SCM_RIGHTS;//说明要传递的是描述字

??????? *((int *)CMSG_DATA(cmptr)) = file;//将描述字放入传输对象中

??????? msg.msg_name = NULL;
??????? msg.msg_namelen = 0;
??????? io.iov_base = buf;
??????? io.iov_len = sizeof(buf);
??????? msg.msg_iov = &io;
??????? msg.msg_iovlen = 1;

??????? ssize_t flag = sendmsg(sockfd, &msg, 0);
??????? printf("flag = %d\n", flag);
??????? close(sockfd);
??????? exit(0);

}

?

热点排行