`
东边日出西边雨
  • 浏览: 262293 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

UNIX domain socket传递文件描述符

    博客分类:
  • c
 
阅读更多

c版本(UNIX高级编程中的例子):

 

// sendmsg.h
#ifndef SENDMSG_H
#define SENDMSG_H

#include <sys/types.h>

int send_fd(int fd, int fd_to_send);
int recv_fd(int fd, ssize_t (*userfunc)(int, const void*, size_t));

#endif

 

 

// semdmsg.c
#include "sendmsg.h"

#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>

static struct cmsghdr* cmptr = NULL;
static int CONTROLLEN = sizeof(struct cmsghdr) + sizeof(int);
static int MAXLINE = 100;


int send_fd(int fd, int fd_to_send)
{
	struct iovec iov[1];
	struct msghdr msg;
	char buf[2];

	iov[0].iov_base = buf;
	iov[0].iov_len = 2;
	msg.msg_iov = iov;
	msg.msg_iovlen = 1;
	msg.msg_name = NULL;
	msg.msg_namelen = 0;

	if (fd_to_send <= 0)
	{
		return -1;
	}

	if (cmptr == NULL && (cmptr = (struct cmsghdr*)malloc(CONTROLLEN)) == NULL)
		return -1;
	cmptr->cmsg_level = SOL_SOCKET;
	cmptr->cmsg_type = SCM_RIGHTS;
	cmptr->cmsg_len = CONTROLLEN;
	msg.msg_control = cmptr;
	msg.msg_controllen = CONTROLLEN;
	*(int*)CMSG_DATA(cmptr) = fd_to_send;
	buf[1] = 0;
	buf[0] = 0;
	if (sendmsg(fd, &msg, 0) != 2)
		return -1;
	return 0;
}


int recv_fd(int fd, ssize_t (*userfunc)(int, const void*, size_t))
{
	int newfd, nr, status;
	char *ptr;
	char buf[MAXLINE];
	struct iovec iov[1];
	struct msghdr msg;

	status = -1;
	for ( ; ; )
	{
		iov[0].iov_base = buf;
		iov[0].iov_len = sizeof(buf);
		msg.msg_iov = iov;
		msg.msg_iovlen = 1;
		msg.msg_name = NULL;
		msg.msg_namelen = 0;

		if (cmptr == NULL & (cmptr = (struct cmsghdr*)malloc(CONTROLLEN)) == NULL)
		{
			return -1;
		}

		msg.msg_control = cmptr;
		msg.msg_controllen = CONTROLLEN;
		if ((nr = recvmsg(fd, &msg, 0)) < 0)
		{
//			err_sys("recvmsg error");
		}
		else if (nr == 0)
		{
//			err_ret("connection closed by server");
			return -1;
		}

		for (ptr = buf; ptr < &buf[nr]; )
		{
			if (*ptr++ == 0)
			{
				if (ptr != &buf[nr-1])
				{
//					err_dump("message format error");
				}
				status = *ptr & 0xFF;
				if (status == 0)
				{
					if (msg.msg_controllen != CONTROLLEN)
					{
//						err_dump("status = 0but no fd");
					}
					newfd = *(int*)CMSG_DATA(cmptr);
				}
				else
				{
					newfd = -status;
				}
				nr -= 2;
			}
		}

//		if (nr > 0 && (&userfunc)(STDERR_FILENO, buf, nr) != nr)
//		{
//			return -1;
//		}
		if (status >= 0)
			return newfd;
	}
}

 

 

c++版本,自己封装的:

 

//domainsocket.h
/*
 * domainsocket.h
 *
 *  Created on: Apr 13, 2012
 *      Author: song
 */

#ifndef DOMAINSOCKET_H_
#define DOMAINSOCKET_H_

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>


class DomainSocket
{
	// the exact name of this class may be "DomainSocketListener"
	// but we call it "DomainSocket" temporary

public:
	DomainSocket();
	virtual ~DomainSocket();

	int Bind(const char* path);
	int Listen(int n);
	int Accept();
	int Connect(const char* path);

	// client call this to send data
	int Send(const void* buf, size_t len, int flags);

	// server call this to send data
	int Send(int sockfd, const void* buf, size_t len, int flags);

	// client receive
	int Recv(void *buf, size_t len, int flags);

	// server receive
	int Recv(int sockfd, void *buf, size_t len, int flags);

	/*
	 * the four methods below used to send and receive file descriptor.
	 * if you are server, you have one more argument than client whatever
	 * send or receive.
	 *
	 */

	// send file descriptor

	// domain socket client send fd need call this.
	int Sendfd(int fdToSend);

	// domain socket server send fd need call this.
	int Sendfd(int sockfd, int fdToSend);

	// received file descriptor as return value
	// return :
	//              > 0 all right!
	//              = 0 receive fail
	int Recvfd();

	// received file descriptor as return value
	// ... ... ... ...
	int Recvfd(int sockfd);


protected:
	void DelDSocketFilePath();


private:
	int m_fd;
	struct sockaddr_un m_addr;
	const char* m_path;
	struct cmsghdr* cmptr;
	int CONTROLLEN;
	int MAXLINE;

	int _Sendfd(int sockfd, int fdToSend);
	int _Recvfd(int sockfd);

};

#endif /* DOMAINSOCKET_H_ */

 

 

//domainsocket.cpp
#include "domainsocket.h"

using namespace std;


DomainSocket::DomainSocket()
{
	m_fd = 0;
	m_path = NULL;
	cmptr = NULL;
	CONTROLLEN = sizeof(struct cmsghdr) + sizeof(int);
	MAXLINE = 100;
	//////////////////////////////////

	int len;
	memset(&m_addr, 0, sizeof(m_addr));

	if ((m_fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
	{
		cout<<"create domain socket fail!"<<endl;
//		return -1;
	}

	cout<<"create domain socket ... , fd is '"<<m_fd<<"'"<<endl;
}


DomainSocket::~DomainSocket()
{
	close(m_fd);
	DelDSocketFilePath();
}


int DomainSocket::Bind(const char* path)
{
	m_path = path;

	// if file exist delete it
	DelDSocketFilePath();

	m_addr.sun_family = AF_UNIX;
	strcpy(m_addr.sun_path, (char*)m_path);

	// bind
	if (bind(m_fd, (struct sockaddr*)&m_addr, sizeof(m_addr)) < 0)
	{
		cout<<"domain bind fail!, errno is '"<<errno<<"' [reason:"
											<<strerror(errno)<<"]"<<endl;

		close(m_fd);
		DelDSocketFilePath();
		return -1;
	}

	cout<<"domain bind (socket and sockaddr) ..."<<endl;
	return 0;
}


int DomainSocket::Listen(int n)
{
	if (listen(m_fd, n) < 0)
	{
		cout<<"domain listen fail!, errno is '"<<errno<<"' [reason:"
											<<strerror(errno)<<"]"<<endl;

		close(m_fd);
		DelDSocketFilePath();
		return -1;
	}

	cout<<"domain listen ..."<<endl;
	return 0;
}


int DomainSocket::Accept()
{
	struct sockaddr cli_addr;
	int new_fd;

	int len = sizeof(cli_addr);


	if ((new_fd = accept(m_fd, (struct sockaddr*)&cli_addr, (socklen_t*)&len)) < 0)
	{
		cout<<"domain accept fail!, errno is '"<<errno<<"' [reason:"<<strerror(errno)<<"]"<<endl;
		close(m_fd);
		DelDSocketFilePath();
		return -1;
	}
	cout<<"  domain accept a new fd '"<<new_fd<<"'"<<endl;

	return new_fd;

}


int DomainSocket::Connect(const char* path)
{
	sockaddr_un server_addr;
	server_addr.sun_family = AF_UNIX;
	strcpy(server_addr.sun_path, path);

	if (connect(m_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0)
	{
		cout<<"connect fail, err msg: "<<strerror(errno)<<endl;
		close(m_fd);
		return -1;
	}
}


int DomainSocket::Send(const void *buf, size_t len, int flags)
{
	return send(m_fd, buf, len, flags);
}


int DomainSocket::Send(int sockfd, const void *buf, size_t len, int flags)
{
	return send(sockfd, buf, len, flags);
}


int DomainSocket::Recv(void *buf, size_t len, int flags)
{
	return recv(m_fd, buf, len, flags);
}


int DomainSocket::Recv(int sockfd, void *buf, size_t len, int flags)
{
	return recv(sockfd, buf, len, flags);
}


int DomainSocket::Sendfd(int fdToSend)
{
	return _Sendfd(m_fd, fdToSend);
}


int DomainSocket::Sendfd(int sockfd, int fdToSend)
{
	return _Sendfd(sockfd, fdToSend);
}


int DomainSocket::Recvfd()
{
	return _Recvfd(m_fd);
}


int DomainSocket::Recvfd(int sockfd)
{
	return _Recvfd(sockfd);
}


int DomainSocket::_Sendfd(int sockfd, int fdToSend)
{
		struct iovec iov[1];
		struct msghdr msg;
		char buf[2];

		iov[0].iov_base = buf;
		iov[0].iov_len = 2;
		msg.msg_iov = iov;
		msg.msg_iovlen = 1;
		msg.msg_name = NULL;
		msg.msg_namelen = 0;

		if (fdToSend <= 0)
		{
			return -1;
		}

		if (cmptr == NULL && (cmptr = (struct cmsghdr*)malloc(CONTROLLEN)) == NULL)
			return -1;
		cmptr->cmsg_level = SOL_SOCKET;
		cmptr->cmsg_type = SCM_RIGHTS;
		cmptr->cmsg_len = CONTROLLEN;
		msg.msg_control = cmptr;
		msg.msg_controllen = CONTROLLEN;
		*(int*)CMSG_DATA(cmptr) = fdToSend;
		buf[1] = 0;
		buf[0] = 0;
		if (sendmsg(sockfd, &msg, 0) != 2)
			return -1;
		return 0;
}


int DomainSocket::_Recvfd(int sockfd)
{
	int newfd, nr, status;
	char *ptr;
	char buf[MAXLINE];
	struct iovec iov[1];
	struct msghdr msg;

	status = -1;
	for ( ; ; )
	{
		iov[0].iov_base = buf;
		iov[0].iov_len = sizeof(buf);
		msg.msg_iov = iov;
		msg.msg_iovlen = 1;
		msg.msg_name = NULL;
		msg.msg_namelen = 0;

		if (cmptr == NULL & (cmptr = (struct cmsghdr*)malloc(CONTROLLEN)) == NULL)
		{
			return -1;
		}

		msg.msg_control = cmptr;
		msg.msg_controllen = CONTROLLEN;
		if ((nr = recvmsg(sockfd, &msg, 0)) < 0)
		{
//			err_sys("recvmsg error");
		}
		else if (nr == 0)
		{
//			err_ret("connection closed by server");
			return -1;
		}

		for (ptr = buf; ptr < &buf[nr]; )
		{
			if (*ptr++ == 0)
			{
				if (ptr != &buf[nr-1])
				{
//					err_dump("message format error");
				}
				status = *ptr & 0xFF;
				if (status == 0)
				{
					if (msg.msg_controllen != CONTROLLEN)
					{
//						err_dump("status = 0but no fd");
					}
					newfd = *(int*)CMSG_DATA(cmptr);
				}
				else
				{
					newfd = -status;
				}
				nr -= 2;
			}
		}

//		if (nr > 0 && (&userfunc)(STDERR_FILENO, buf, nr) != nr)
//		{
//			return -1;
//		}
		if (status >= 0)
			return newfd;
	}
}


void DomainSocket::DelDSocketFilePath()
{
	if (!m_path)
		return;

	unlink(m_path);
}

 

分享到:
评论

相关推荐

    unix domain socket传递描述符

    “工具”可能是指一些利用Unix域套接字和描述符传递的实用工具或库,例如libsocketcan用于CAN总线通信,或者某些进程间通信框架如ZeroMQ,它们可能在内部使用了Unix域套接字来高效地传递文件描述符。 总的来说,...

    unix domain socket

    2. **文件描述符传递**:当一个进程通过 `recvmsg()` 接收到另一个进程发送过来的文件描述符后,它必须负责关闭这个文件描述符,否则会导致资源泄露。 3. **权限验证**:Unix Domain Socket 通过文件系统的权限...

    linux domain socket编程

    每次成功接受连接后都会返回一个新的Socket文件描述符,用于后续的数据交换。 5. **发送和接收数据**:一旦连接建立,就可以使用`send()`和`recv()`函数来发送和接收数据。 6. **断开连接**:使用`close()`函数...

    unix 域 socket服务端客户端stream方式代码

    Unix域Socket分为两种类型:文件描述符类型(SOCK_STREAM)和数据报类型(SOCK_DGRAM)。文件描述符类型类似于TCP Socket,提供面向连接、可靠的字节流服务;而数据报类型则类似UDP Socket,是无连接的,数据报会被...

    经由UNIX域套接字传送文件描述符所涉及的相关知识(自己整理)

    在进程间通信(IPC)中,能够直接传输文件描述符是非常实用的功能。这种能力使得服务器进程能够执行所有与文件相关的操作,如网络名称解析、调制解调器拨号、文件锁定协商等,并最终向请求方返回一个可用于后续I/O操作...

    Unix环境下的socket编程.doc

    Socket也具有一个类似于打开文件的函数调用Socket(),该函数返回一个整型的Socket描述符,随后的连接建立、数据传输等操作都是通过该Socket实现的。常用的Socket类型有两种:流式Socket(SOCK_STREAM)和数据报式...

    ipc_socket-2

    在Linux IPC中,socket通信主要分为两种类型:基于文件描述符的Unix Domain Socket(UDS)和基于网络协议的Inet Domain Socket。 **一、Unix Domain Socket** Unix Domain Socket,也称为本地域socket或文件域...

    LINUX进程间传递描述符.pdf

    3. 在描述符传递期间,内核会将其标记为"在飞行中",即使发送方尝试关闭,内核也会保持其在接收进程中的打开状态,增加引用计数。 4. 描述符通过`msg_control`字段发送,通常伴随着至少1字节的数据,以区分“无数据...

    UNIX Socket编程

    2. 文件描述符:UNIX Socket是基于文件系统的,每个套接字都有一个唯一的文件描述符,用于读写操作。 3. 地址:UNIX Socket的地址是路径名,位于文件系统中。连接时,客户端查找这个路径来找到服务器端的套接字。 ...

    LINUX进程间传递描述符[收集].pdf

    总的来说,Linux下的进程间描述符传递利用了Unix域套接字和内核的特殊处理,通过`sendmsg`和`recvmsg`函数实现了描述符的安全转移。这种方法允许进程间共享文件描述符,极大地扩展了进程通信的能力,尤其是在需要...

    cocos2d-x socket网络连接

    2. **创建Socket**: 使用`socket()`函数创建一个Socket描述符,指定协议类型(如TCP或UDP)和地址族(如AF_INET用于IPv4)。 3. **绑定地址**: 使用`bind()`函数将Socket与特定的IP地址和端口号关联,以便其他设备...

    异步文件传输工具libafdt.zip

    它提供了一个简单的页面来建立 Unix domain socket 来接收来自 libafdt 服务器中的文件描述请求或者是传输文件描述信息到客户端。通过底层和同步接口传输数据报的时候需要使用 libevent。libafdt 有两个高层接口:...

    unix_socket_socket编程_Unix域套接字_udpclient_tunedaa_网络编程_源码.zip

    Unix域套接字提供了类似文件系统的接口,使得进程可以通过文件描述符进行通信。它们有两种主要类型:流式(SOCK_STREAM)和数据报(SOCK_DGRAM),分别对应于TCP和UDP的特性。流式Unix域套接字提供可靠的、面向连接...

    socket库函数

    sockfd是Socket描述符,buf是接收数据缓冲区指针,len是最大接收数据长度,flags表示额外选项。 - **`close(sockfd)`**:关闭Socket。sockfd是Socket描述符。 #### 七、非阻塞选项 在某些情况下,可能需要Socket在...

    Unix Domain Sokcet

    - **资源管理**:Unix域套接字可以实现文件描述符的传递,这在网络套接字中是不可行的。 Unix域套接字的使用场景包括: - 进程间通信:如守护进程与用户界面的通信。 - 服务替换:在开发和测试环境中,可以用Unix域...

    网络socket编程指南.pdf

    - **Socket创建**: 通过系统调用`socket()`来创建一个Socket,并返回一个Socket描述符。之后可以通过该描述符进行`send()`和`recv()`操作来发送和接收数据。 - **Socket调用**: 虽然可以使用`read()`和`write()`函数...

    Linux下Socket编程

    程序员可以通过socket()函数创建Socket,并获取一个整型的Socket描述符,后续的所有操作都将通过该描述符进行。Socket类型主要有两种,分别是流式Socket(SOCK_STREAM)和数据报式Socket(SOCK_DGRAM)。流式Socket...

    UnixSocket编程[收集].pdf

    其中,`sockfd`是`socket()`函数返回的Socket描述符,`my_addr`是一个指向包含本地地址信息的`sockaddr`结构的指针,`addrlen`则是结构的大小。 `sockaddr`是一个通用的地址结构,通常我们会使用更具体的结构,如`...

    c语言Socket编程(专业排版0积分)

    Socket编程的核心是创建、配置和使用Socket描述符。 1. **Socket的创建** 创建Socket的过程始于`socket()`函数调用。这个函数的参数包括协议族(domain)、Socket类型(type)和协议(protocol)。通常,对于TCP/...

Global site tag (gtag.js) - Google Analytics