`
东边日出西边雨
  • 浏览: 258118 次
  • 性别: 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传递描述符

    NULL 博文链接:https://songpengfei.iteye.com/blog/1498087

    异步文件传输工具libafdt.zip

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

    linux网络编程学习笔记

    sockfd:是由socket调用返回的文件描述符. addrlen:是 sockaddr结构的长度. my_addr:是一个指向 sockaddr的指针. 在&lt;linux/socket.h&gt;;中有 sockaddr的定义 struct sockaddr{ unisgned short as_family; char ...

    TCP-IP详解卷3:TCP事务协议,HTTP,NNTP和UNIX域协议

    第18章 Unix域协议:I/O和描述符的传递 210 18.1 概述 210 18.2 PRU_SEND和PRU_RCVD请求 210 18.3 描述符的传递 214 18.4 unp_internalize函数 218 18.5 unp_externalize函数 220 18.6 unp_discard函数 221 18.7 unp...

    TCP/IP详解 卷3:TCP事务协议、HTTP、NNTP和UNIX域协议

    第18章 Unix域协议:I/O和描述符的传递 18.1 概述 18.2 PRU_SEND和PRU_RCVD请求 18.3 描述符的传递 18.4 unp_internalize函数 18.5 unp_externalize函数 18.6 unp_discard函数 18.7 unp_dispose函数 18.8 unp_scan...

    TCP-IP详解卷三:TCP事务协议,HTTP,NNTP和UNIX域协议

    第18章 Unix域协议:I/O和描述符的传递 210 18.1 概述 210 18.2 PRU_SEND和PRU_RCVD请求 210 18.3 描述符的传递 214 18.4 unp_internalize函数 218 18.5 unp_externalize函数 220 18.6 unp_discard函数 221 18.7 unp...

    TCP-IP详解卷3:TCP事务协议,HTTP,NNTP和UNIX域协议.rar

    第18章 Unix域协议:I/O和描述符的传递 210 18.1 概述 210 18.2 PRU_SEND和PRU_RCVD请求 210 18.3 描述符的传递 214 18.4 unp_internalize函数 218 18.5 unp_externalize函数 220 18.6 unp_discard函数 221 18.7 unp...

    TCP-IP详解卷三:TCP事务协议,HTTP,NNTP和UNIX域协议——高清文字(china-pub经典系列)

    第18章 Unix域协议:I/O和描述符的传递 210 18.1 概述 210 18.2 PRU_SEND和PRU_RCVD请求 210 18.3 描述符的传递 214 18.4 unp_internalize函数 218 18.5 unp_externalize函数 220 18.6 unp_discard函数 221 18.7 unp...

    TCP-IP详解卷三

    第18章 Unix域协议:I/O和描述符的传递 210 18.1 概述 210 18.2 PRU_SEND和PRU_RCVD请求 210 18.3 描述符的传递 214 18.4 unp_internalize函数 218 18.5 unp_externalize函数 220 18.6 unp_discard函数 221 18.7 unp...

    TCP-IP详解卷3:TCP事务协议

    第18章 Unix域协议:I/O和描述符的传递 210 18.1 概述 210 18.2 PRU_SEND和PRU_RCVD请求 210 18.3 描述符的传递 214 18.4 unp_internalize函数 218 18.5 unp_externalize函数 220 18.6 unp_discard函数 221 18.7 unp...

    TCPIP协议详解卷三.rar

    第18章 Unix域协议:I/O和描述符的传递 210 18.1 概述 210 18.2 PRU_SEND和PRU_RCVD请求 210 18.3 描述符的传递 214 18.4 unp_internalize函数 218 18.5 unp_externalize函数 220 18.6 unp_discard函数 221 18.7 unp...

    TCPIP协议详解卷二:实现

    第18章 Unix域协议:I/O和描述符的传递 210 18.1 概述 210 18.2 PRU_SEND和PRU_RCVD请求 210 18.3 描述符的传递 214 18.4 unp_internalize函数 218 18.5 unp_externalize函数 220 18.6 unp_discard函数 221 18.7 unp...

    TCPIP协议详解卷3-事务协议

    第18章 Unix域协议:I/O和描述符的传递 210 18.1 概述 210 18.2 PRU_SEND和PRU_RCVD请求 210 18.3 描述符的传递 214 18.4 unp_internalize函数 218 18.5 unp_externalize函数 220 18.6 unp_discard函数 221 18.7 unp...

    TCP-IP详解卷3.rar

    第18章 Unix域协议:I/O和描述符的传递 210 18.1 概述 210 18.2 PRU_SEND和PRU_RCVD请求 210 18.3 描述符的传递 214 18.4 unp_internalize函数 218 18.5 unp_externalize函数 220 18.6 unp_discard函数 221 18.7 unp...

    TCPIP详解--共三卷

    27.3.4 异常中止一个文件的传输: Telnet同步信号 326 27.3.5 匿名FTP 329 27.3.6 来自一个未知IP地址的匿名FTP 330 27.4 小结 331 第28章 SMTP:简单邮件传送协议 332 28.1 引言 332 28.2 SMTP协议 332 28.2.1 简单...

    TCP_IP详解卷1

    27.3.4 异常中止一个文件的传输: Telnet同步信号 326 27.3.5 匿名FTP 329 27.3.6 来自一个未知IP地址的匿名FTP 330 27.4 小结 331 第28章 SMTP:简单邮件传送协议 332 28.1 引言 332 28.2 SMTP协议 332 28.2.1 简单...

    TCPIP详解卷[1].part04

    27.3.4 异常中止一个文件的传输: Telnet同步信号 326 27.3.5 匿名FTP 329 27.3.6 来自一个未知IP地址的匿名FTP 330 27.4 小结 331 第28章 SMTP:简单邮件传送协议 332 28.1 引言 332 28.2 SMTP协议 332 28.2.1 简单...

    TCPIP详解卷[1].part09

    27.3.4 异常中止一个文件的传输: Telnet同步信号 326 27.3.5 匿名FTP 329 27.3.6 来自一个未知IP地址的匿名FTP 330 27.4 小结 331 第28章 SMTP:简单邮件传送协议 332 28.1 引言 332 28.2 SMTP协议 332 28.2.1 简单...

    TCPIP详解卷[1].part05

    27.3.4 异常中止一个文件的传输: Telnet同步信号 326 27.3.5 匿名FTP 329 27.3.6 来自一个未知IP地址的匿名FTP 330 27.4 小结 331 第28章 SMTP:简单邮件传送协议 332 28.1 引言 332 28.2 SMTP协议 332 28.2.1 简单...

Global site tag (gtag.js) - Google Analytics