网络通信- 父子进程的通信(本地通信)

本地套接字使用 struct sockaddr_un ;
这里写图片描述
bind的时候仍然需要强转

创建套接字需要使用 AF_UNIX ,AF_UNIX, AF_LOCAL

创建套接字的type可以选择TCP,也可以选择UDP,但是如果选择TCP,那么必须按照TCP的流程进行通信,如果选择UDP,必须按照UDP的流程进行通信。

一, client

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/un.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <netinet/udp.h>



#define SERV_NAME "sock.c"
#define SERV_NAMES "sock.s"

int main(int argc, char *argv[]) {

	int listenfd;
	struct sockaddr_un servaddr, cliaddr;
	socklen_t len = sizeof(cliaddr);
	char buf[256] = { 0 };
	int ret, i = 0;

	//创建socket
	listenfd = socket(AF_UNIX, SOCK_DGRAM, 0);

	//绑定ip
	unlink(SERV_NAME);
	bzero(&servaddr, sizeof(servaddr));
	servaddr.sun_family = AF_UNIX;
	strcpy(servaddr.sun_path, SERV_NAME);
	if (bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {
		perror("bind error");
		return -1;
	} 
	bzero(&cliaddr, sizeof(cliaddr));
	servaddr.sun_family = AF_UNIX;
	strcpy(servaddr.sun_path, SERV_NAMES);

	while (1) {
	
		//发送数据
		sprintf(buf, "陈丽 %d\n", i++);
		sendto(listenfd, buf, strlen(buf), 0, (struct sockaddr *)&servaddr, sizeof(servaddr));

		//接收数据
		memset(buf, 0x00, sizeof(buf));
		int ret = recvfrom(listenfd, buf, sizeof(buf), 0, (struct sockaddr *)&cliaddr, &len);
		if (ret > 0) {
			printf("client 接收消息:%s\n", buf);
		}
		sleep(1);

	}


	close(listenfd);
	return 0;
}

二,server

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


#define SERV_PORT 8888
#define SERV_NAME "sock.s"

int main(int argc, char *argv[]) 
{
	int listenfd;
	struct sockaddr_un servaddr, cliaddr;
	socklen_t len = sizeof(cliaddr);
	char buf[256] = { 0 };
	int i, ret;

	//创建socket 
	listenfd = socket(AF_UNIX, SOCK_DGRAM, 0);

	//绑定本地套接字
	unlink(SERV_NAME); //删除绑定套接字
	bzero(&servaddr, sizeof(servaddr));
	servaddr.sun_family = AF_UNIX;
	strcpy(servaddr.sun_path, SERV_NAME);
	if (bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {
		perror("bind error");
		return -1;
	}

	while (1) {

		//接收数据
		ret = recvfrom(listenfd, buf, sizeof(buf), 0, (struct sockaddr *)&cliaddr, &len);
		if (ret > 0) {
			printf("server :%s\n", cliaddr.sun_path);
			sendto(listenfd, buf, strlen(buf), 0, (struct sockaddr *)&cliaddr, sizeof(cliaddr));
		}

	}

	close(listenfd);
	return 0;
}

三 , getsockname 函数

man 查看

SYNOPSIS
      #include <sys/socket.h>

      int getsockname(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

DESCRIPTION
      getsockname()  returns  the  current address to which the socket sockfd is bound, in the buffer pointed to by addr.  The addrlen argument should be ini‐
      tialized to indicate the amount of space (in bytes) pointed to by addr.  On return it contains the actual size of the socket address.

      The returned address is truncated if the buffer provided is too small; in this case, addrlen will return a value greater than was supplied to the call.

RETURN VALUE
      On success, zero is returned.  On error, -1 is returned, and errno is set appropriately.

ERRORS
      EBADF  The argument sockfd is not a valid descriptor.

      EFAULT The addr argument points to memory not in a valid part of the process address space.

      EINVAL addrlen is invalid (e.g., is negative).

      ENOBUFS
             Insufficient resources were available in the system to perform the operation.

      ENOTSOCK
             The file descriptor sockfd does not refer to a socket.

得到已经连接sockIP长度

//gcc -o getsocket getsocketname.c
//得到socket连接 IP地址长度
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include	<netinet/in.h>	/* sockaddr_in{} and other Internet defns */
#include	<arpa/inet.h>	/* inet(3) functions */
#include	<errno.h>
#include	<fcntl.h>		/* for nonblocking */
#include	<sys/un.h>		/* for Unix domain sockets */
#include <unistd.h>   /* unlink */

// cmd -> ./getsocket chenli 
// screen -> bound name = chenli, returned len = 9
int main(int argc, char *argv[])
{
	int					sockfd;
	socklen_t			len;
	struct sockaddr_un	addr1, addr2;

	if (argc != 2)
	{
		printf("usage: unixbind <pathname>");
	}

	sockfd = socket(AF_LOCAL, SOCK_STREAM, 0);

	unlink(argv[1]);		/* OK if this fails */

	bzero(&addr1, sizeof(addr1));
	addr1.sun_family = AF_LOCAL;
	strncpy(addr1.sun_path, argv[1], sizeof(addr1.sun_path)-1);
	bind(sockfd, (struct sockaddr *) &addr1, SUN_LEN(&addr1));

	len = sizeof(addr2);
	getsockname(sockfd, (struct sockaddr *) &addr2, &len);
	printf("bound name = %s, returned len = %d\n", addr2.sun_path, len);
	
	//exit(0);
	return 0;
}


在这里插入图片描述

四, sockepair 父子进程通信

socketpair 是父子进程通信的一种:nginx使用master与worker进程之间的通信就是基于socketpair通信的

  1. 其实socketpair是基于pipe的通信的全双工的
  2. 父子进程之间的 “描述符传递”
  3. 流程- open, pipe,mkfifio, socket, accept

在这里插入图片描述

1, msghdr结构体

不幸,对于4.3BSD以及在其基础上构造的SunOS和Ultrix,以及从4.3BSD Reno开始的后续版本我们必须提供不同的实现。
为了交换文件描述符,调用sendmsg(2)和recvmsg(2)函数。这两个函数的参数中都
有一个指向msghdr的指针,该结构包含了所有关于要发送和接收消息的信息。该结
构定义在〈sys/socket.h〉 头文件中,在BSD4.3之下,其样式是:

strcut msghdr {  
caddr_t  msg_name;    可选的地址  
int   msg_namelen;    地址长度  
struct iovec  msg_iov;     散布/聚集数组  
int    msg_iovlen;    在msg_iov数组中的元素数  
caddr_t  msg_accrights;    存取权发送/接收到  
int    msg-accrightslen;   存取权缓存的长度  
}  

从4.3BSD Reno开始,更改了msghdr结构的定义。在以前版本中被称之为"存取权"
的最后两个元素改称为"辅助数据"。另外,在该结构结束处增加了一个新成员msg
_flags。

strcut msghdr {  
caddr_t  msg_name;    可选的地址  
int   msg_namelen;    地址长度  
struct iovec  msg_iov;     散布/聚集数组  
int    msg_iovlen;    在msg_iov数组中的元素数  
caddr_t  msg_control;    辅助数据  
int    msg-controllen;   辅助数据的长度  
int    msg_flags;    接收到消息的标志  
}

我的内核查看

 killer@localhost:~/socket$ uname -r
4.4.0-131-generic

实例程序

// gcc -o socketpair socketpair.c

#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include	<netinet/in.h>	/* sockaddr_in{} and other Internet defns */
#include	<arpa/inet.h>	/* inet(3) functions */
#include	<errno.h>
#include	<fcntl.h>		/* for nonblocking */
#include	<sys/un.h>		/* for Unix domain sockets */
#include <unistd.h>   /* unlink */
#include <string.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <errno.h>
#define	BUFFSIZE	8192	/* buffer size for reads and writes */
/* define if struct msghdr contains the msg_control member */

#define HAVE_MSGHDR_MSG_CONTROL 1



ssize_t read_fd(int fd, void *ptr, size_t nbytes, int *recvfd)
{
	struct msghdr	msg;
	struct iovec	iov[1];
	ssize_t			n;

#ifdef	HAVE_MSGHDR_MSG_CONTROL
	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);
#else
	int				newfd;

	msg.msg_accrights = (caddr_t) &newfd;
	msg.msg_accrightslen = sizeof(int);
#endif

	msg.msg_name = NULL;
	msg.msg_namelen = 0;

	iov[0].iov_base = ptr;
	iov[0].iov_len = nbytes;
	msg.msg_iov = iov;
	msg.msg_iovlen = 1;

	if ( (n = recvmsg(fd, &msg, 0)) <= 0)
		return(n);

#ifdef	HAVE_MSGHDR_MSG_CONTROL
	if ( (cmptr = CMSG_FIRSTHDR(&msg)) != NULL &&
	    cmptr->cmsg_len == CMSG_LEN(sizeof(int))) {
		if (cmptr->cmsg_level != SOL_SOCKET)
			err_quit("control level != SOL_SOCKET");
		if (cmptr->cmsg_type != SCM_RIGHTS)
			err_quit("control type != SCM_RIGHTS");
		*recvfd = *((int *) CMSG_DATA(cmptr));
	} else
		*recvfd = -1;		/* descriptor was not passed */
#else
/* *INDENT-OFF* */
	if (msg.msg_accrightslen == sizeof(int))
		*recvfd = newfd;
	else
		*recvfd = -1;		/* descriptor was not passed */
/* *INDENT-ON* */
#endif

	return(n);
}
/* end read_fd */

ssize_t Read_fd(int fd, void *ptr, size_t nbytes, int *recvfd)
{
	ssize_t		n;

	if ( (n = read_fd(fd, ptr, nbytes, recvfd)) < 0)
		printf("read_fd error");

	return(n);
}


int my_open(const char *pathname, int mode)
{
	int			fd, sockfd[2], status;
	pid_t		childpid;
	char		c, argsockfd[10], argmode[10];

	socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd);

	if ( (childpid = fork()) == 0) /* child process */
	{		
		close(sockfd[0]);
		snprintf(argsockfd, sizeof(argsockfd), "%d", sockfd[1]);
		snprintf(argmode, sizeof(argmode), "%d", mode);
		execl("./openfile", "openfile", argsockfd, pathname, argmode,
			  (char *) NULL);
		printf("execl error");
	}

	/* parent process - wait for the child to terminate */
	close(sockfd[1]);			/* close the end we don't use */

	waitpid(childpid, &status, 0);
	if (WIFEXITED(status) == 0)
	{
		printf("child did not terminate");
	}
	if ( (status = WEXITSTATUS(status)) == 0)
	{
		Read_fd(sockfd[0], &c, 1, &fd);
	}
	else 
	{
		errno = status;		/* set errno value from child's status */
		fd = -1;
	}

	close(sockfd[0]);
	return(fd);
}




int main(int argc, char **argv)
{
	int		fd, n;
	char	buff[BUFFSIZE];

	if (argc != 2)
	{
		printf("usage: mycat <pathname>");
	}
	//O_RDONLY 只读取
	if ( (fd = my_open(argv[1], O_RDONLY)) < 0)
	{
		printf("cannot open %s", argv[1]);
	}

	while ( (n = read(fd, buff, BUFFSIZE)) > 0)
	{
		write(STDOUT_FILENO, buff, n);
	}

	//exit(0);
	return 0;
}

socketpair父子进程描述符传递

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值