UNIX域协议(无名套接字)
2018-01-04 22:10
495 查看
关于什么是UNIX域套接字可以参考:http://www.cnblogs.com/xcywt/p/8185597.html
这里主要介绍非命名的UNIX域套接字的用法。
1.socketpair函数
先看man手册:
SYNOPSIS
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int socketpair(int domain, int type, int protocol, int sv[2]);
DESCRIPTION
The socketpair() call creates an unnamed pair of connected sockets in
the specified domain, of the specified type, and using the optionally
specified protocol. For further details of these arguments, see
socket(2).
The descriptors used in referencing the new sockets are returned in
sv[0] and sv[1]. The two sockets are indistinguishable.
RETURN VALUE
On success, zero is returned. On error, -1 is returned, and errno is
set appropriately.
功能:创建一个全双工的流管道
参数:
domain:协议家族,为AF_LOCAL或AF_UNIX
type:套接字类型。可以是SOCK_STREAM或者SOCK_DGRAM。这两种都是可靠的
protocol:协议类型。为0
sv:返回套接字对,这个是输出参数。返回的两个描述符都是可读可写的。
返回值:成功返回0,失败返回-1.
补充:pipe创建的匿名管道的半双工的,pipefd[0]用于读,pipefd[1]用于写。
注意:由于创建的每个套接字都是没有名字的,这就意味着无关进程不能使用它们。
2.一个简单的例子:
父进程给子进程发送一个数据给子进程,子进程收到数据后最数据进行加一操作,再发回给父进程。
先上自己的一个头文件:
comm.h
再上主程序:
运行:
3.UNIX域传递文件描述符
需要用到sendmsg和recvmsg函数:
#include <sys/types.h>
#include <sys/socket.h>
ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
主要封装了两个函数,recv_fd和send_fd。
直接上代码:
分析:子进程中打开一个文件描述符,然后通过send_fd发送给主进程,主进程通过recv_fd接收这个文件描述符。再通过这个文件描述符读取文件的内容。
运行,需要先创建一个test.txt文件,再运行:
补充:
1)虽然文件描述符是一个整形数字,但是单纯发一个数字过去是没有用的。
2)普通的TCP UDP套接字是不能传递文件描述符的
这里主要介绍非命名的UNIX域套接字的用法。
1.socketpair函数
先看man手册:
SYNOPSIS
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int socketpair(int domain, int type, int protocol, int sv[2]);
DESCRIPTION
The socketpair() call creates an unnamed pair of connected sockets in
the specified domain, of the specified type, and using the optionally
specified protocol. For further details of these arguments, see
socket(2).
The descriptors used in referencing the new sockets are returned in
sv[0] and sv[1]. The two sockets are indistinguishable.
RETURN VALUE
On success, zero is returned. On error, -1 is returned, and errno is
set appropriately.
功能:创建一个全双工的流管道
参数:
domain:协议家族,为AF_LOCAL或AF_UNIX
type:套接字类型。可以是SOCK_STREAM或者SOCK_DGRAM。这两种都是可靠的
protocol:协议类型。为0
sv:返回套接字对,这个是输出参数。返回的两个描述符都是可读可写的。
返回值:成功返回0,失败返回-1.
补充:pipe创建的匿名管道的半双工的,pipefd[0]用于读,pipefd[1]用于写。
注意:由于创建的每个套接字都是没有名字的,这就意味着无关进程不能使用它们。
2.一个简单的例子:
父进程给子进程发送一个数据给子进程,子进程收到数据后最数据进行加一操作,再发回给父进程。
先上自己的一个头文件:
comm.h
#ifndef __COMM_H__ #define __COMM_H__ #include<errno.h> #include<stdlib.h> #define ERR_EXIT(m) \ do \ { \ perror(m); \ exit(EXIT_FAILURE); \ } while(0) #endif // __COMM_H__
再上主程序:
#include<stdio.h> #include<unistd.h> #include <sys/types.h> /* See NOTES */ #include <sys/socket.h> #include"comm.h" int main() { int sockfds[2]; if(socketpair(PF_UNIX, SOCK_STREAM, 0, sockfds) < 0) ERR_EXIT("sockerpair"); pid_t pid; pid = fork(); if(pid < 0) ERR_EXIT("fork"); else if(pid > 0) { int val = 0; close(sockfds[1]); while(1) { ++val; printf("Sending data: %d\n", val); write(sockfds[0], &val, sizeof(val)); read(sockfds[0], &val, sizeof(val)); printf(" Recv data: %d\n", val); sleep(1); } } else { close(sockfds[0]); int val; while(1) { read(sockfds[1], &val, sizeof(val)); ++val; write(sockfds[1], &val, sizeof(val)); } } return 0; }
运行:
xcy@xcy-virtual-machine:~/test/sock14_socketpair$ ./sockpair Sending data: 1 Recv data: 2 Sending data: 3 Recv data: 4 Sending data: 5 Recv data: 6 Sending data: 7 Recv data: 8 Sending data: 9 Recv data: 10 Sending data: 11 Recv data: 12 Sending data: 13 Recv data: 14
3.UNIX域传递文件描述符
需要用到sendmsg和recvmsg函数:
#include <sys/types.h>
#include <sys/socket.h>
ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
主要封装了两个函数,recv_fd和send_fd。
直接上代码:
#include<stdio.h> #include<unistd.h> #include<fcntl.h> #include<sys/types.h> #include<sys/socket.h> #include"comm.h" // 这个文件见上面的例子有 void send_fd(int sock_fd, int send_fd) { int ret = 0; struct msghdr msg; struct cmsghdr *p_cmsg; struct iovec vec; char cmsgbuf[CMSG_SPACE(sizeof(send_fd))]; int *p_fds; char sendchar = 0; msg.msg_control = cmsgbuf; msg.msg_controllen = sizeof(cmsgbuf); p_cmsg = CMSG_FIRSTHDR(&msg); p_cmsg->cmsg_level = SOL_SOCKET; p_cmsg->cmsg_type = SCM_RIGHTS; p_cmsg->cmsg_len = CMSG_LEN(sizeof(send_fd)); p_fds = (int*)CMSG_DATA(p_cmsg); *p_fds = send_fd; msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_iov = &vec; msg.msg_iovlen = 1; msg.msg_flags = 0; vec.iov_base = &sendchar; vec.iov_len = sizeof(sendchar); ret = sendmsg(sock_fd, &msg, 0); if(ret < 0) ERR_EXIT("sendmsg"); } int recv_fd(const int sock_fd) { int ret = 0; struct msghdr msg; char recvchar; struct iovec vec; int recv_fd; char cmsgbuf[CMSG_SPACE(sizeof(recv_fd))]; struct cmsghdr *p_cmsg; int *p_fd = NULL; vec.iov_base = &recvchar; vec.iov_len = sizeof(recvchar); msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_iov = &vec; msg.msg_iovlen = 1; msg.msg_control = cmsgbuf; msg.msg_controllen = sizeof(cmsgbuf); msg.msg_flags = 0; p_fd = (int *)CMSG_DATA(CMSG_FIRSTHDR(&msg)); *p_fd = -1; ret = recvmsg(sock_fd, &msg, 0); if(ret < 0) ERR_EXIT("recvmsg"); p_cmsg = CMSG_FIRSTHDR(&msg); if(p_cmsg == NULL) ERR_EXIT("no passed fd"); p_fd = (int*)CMSG_DATA(p_cmsg); recv_fd = *p_fd; if(recv_fd == -1) ERR_EXIT("no passed fd"); return recv_fd; } #define OPEN_FILE "test.txt" int main() { int sockfds[2]; if(socketpair(PF_UNIX, SOCK_STREAM, 0, sockfds) < 0) ERR_EXIT("socketpair"); pid_t pid = fork(); if(pid < 0) ERR_EXIT("fork"); else if(pid > 0) { close(sockfds[1]); char buf[1024] = {0}; int fd = recv_fd(sockfds[0]); read(fd, buf, sizeof(buf)); printf("Get Data:\n%s", buf); } else { close(sockfds[0]); int fd = open(OPEN_FILE, O_RDONLY); if(fd < 0) ERR_EXIT("open"); send_fd(sockfds[1], fd); } return 0; }
分析:子进程中打开一个文件描述符,然后通过send_fd发送给主进程,主进程通过recv_fd接收这个文件描述符。再通过这个文件描述符读取文件的内容。
运行,需要先创建一个test.txt文件,再运行:
xcy@xcy-virtual-machine:~/test/sock14_socketpair$ ./sendfd Get Data: I am xiaochongyong How are you? I'm fine. And you! xcy@xcy-virtual-machine:~/test/sock14_socketpair$
补充:
1)虽然文件描述符是一个整形数字,但是单纯发一个数字过去是没有用的。
2)普通的TCP UDP套接字是不能传递文件描述符的
相关文章推荐
- 利用ADB 协议建立PC与手机端本地unix套接字的连接
- Linux Socket学习 -- 无名套接字 AF_UNIX
- Unix域套接字(Unix Domain Socket)
- 网络七层协议 五层模型 TCP连接 HTTP连接 socket套接字
- 【Unix 网络编程】说说 socket 套接字
- UNIX学习之路 一步一个脚印之TCP协议
- UNIX域协议(命名套接字)
- linux网络编程之socket(十五):UNIX域套接字编程和socketpair 函数
- UNIX环境学习笔记------原始套接字-----IP头部定义
- UNIX环境编程--------原始套接字学习笔记-----Linux原始套接字实现分析
- (十三) [终篇] 一起学 Unix 环境高级编程 (APUE) 之 网络 IPC:套接字
- Linux网络编程之原始套接字-ping协议实现
- Unix域协议简介
- UNIX环境高级编程学习之第十六章网络IPC:套接字 - 简单TCP Socket 通信
- 通常每个套接字地址(协议/网络地址/端口)只允许使用一次 apache24安装443端口占用
- (OS 10048)通常每个套接字地址(协议/网络地址/端口)只允许使用一次。 : AH00072: mak e_sock: could not bind to address [::]:443
- 解决通常每个套接字地址(协议/网络地址/端口)只允许使用一次
- 套接字编程 --- UDP协议
- 无法连接到服务器。 帐户: 'mail.bb.cn', 服务器: '*******', 协议: SMTP, 端口: 25, 安全(SSL): 否, 套接字错误: 10061, 错误号: 0x800CCC0E
- UNIX环境高级编程笔记——高级IO,进程间通信,套接字,高级进程间通信