前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >socketpair函数用法[通俗易懂]

socketpair函数用法[通俗易懂]

作者头像
全栈程序员站长
发布2022-11-19 13:29:27
2.2K0
发布2022-11-19 13:29:27
举报
文章被收录于专栏:全栈程序员必看

大家好,又见面了,我是你们的朋友全栈君。

Unix套接字好像是套接字和管道的混合,socketpair()可以创建一对无命名的、相互连接的Unix域套接字。

管道历史上,它们是半双工的(数据只能在一个方向上流动),但是现在也有全双工管道。管道只能在具有共同祖先的两个进程之间使用,通常一个管道由一个进程创建,在进程调用fork之后,这个管道就你能在父进程和子进程之间使用了。

socketpair()函数的声明:

#include <sys/types.h> #include <sys/socket.h> int socketpair(int domain, int type, int protocol, int sockfd[2]); socketpair()函数用于创建一对无名的、相互连接的套接字。 如果函数成功,则返回0,创建好的套接字分别是sv[0]和sv[1];否则返回-1,错误码保存于errno中。

基本用法: 1. 这对套接字可以用于全双工通信,每一个套接字既可以读也可以写。例如,可以往sockfd[0]中写,从sockfd[1]中读;或者从sockfd[1]中写,从sockfd[0]中读; 2. 如果往一个套接字(如sockfd[0])中写入后,再从该套接字读时会阻塞,只能在另一个套接字中(sockfd[1])上读成功; 3. 读、写操作可以位于同一个进程,也可以分别位于不同的进程,如父子进程。如果是父子进程时,一般会功能分离,一个进程用来读,一个用来写。因为文件描述符sockfd[0]和sockfd[1]是进程共享的,所以读的进程要关闭写描述符, 反之,写的进程关闭读描述符。 举例: 一、读写操作位于同一进程

#include <stdio.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <error.h> #include <errno.h> #include <sys/socket.h> #include <stdlib.h> const char* str = “SOCKET PAIR TEST.”; int main(int argc, char* argv[]){ char buf[128] = {0}; int socket_pair[2]; pid_t pid; if(socketpair(AF_UNIX, SOCK_STREAM, 0, socket_pair) == -1 ) { printf(“Error, socketpair create failed, errno(%d): %s\n”, errno, strerror(errno)); return EXIT_FAILURE; } int size = write(socket_pair[0], str, strlen(str)); //可以读取成功; read(socket_pair[1], buf, size); printf(“Read result: %s\n”,buf); return EXIT_SUCCESS; } 二、读写操作位于不同进程

#include <stdio.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <error.h> #include <errno.h> #include <sys/socket.h> #include <stdlib.h> const char* str = “SOCKET PAIR TEST.”; int main(int argc, char* argv[]){ char buf[128] = {0}; int socket_pair[2]; pid_t pid; if(socketpair(AF_UNIX, SOCK_STREAM, 0, socket_pair) == -1 ) { printf(“Error, socketpair create failed, errno(%d): %s\n”, errno, strerror(errno)); return EXIT_FAILURE; } pid = fork(); if(pid < 0) { printf(“Error, fork failed, errno(%d): %s\n”, errno, strerror(errno)); return EXIT_FAILURE; } else if(pid > 0) { //关闭另外一个套接字 close(socket_pair[1]); int size = write(socket_pair[0], str, strlen(str)); printf(“Write success, pid: %d\n”, getpid()); } else if(pid == 0) { //关闭另外一个套接字 close(socket_pair[0]); read(socket_pair[1], buf, sizeof(buf)); printf(“Read result: %s, pid: %d\n”,buf, getpid()); } for(;;) { sleep(1); } return EXIT_SUCCESS; } sendmsg, recvmsg , send函数的使用 sendmsg, recvmsg , send三个函数的头文件:

#include <sys/types.h> #include <sys/socket.h> sendmsg函数 定义函数

int sendmsg(int s, const strcut msghdr *msg, unsigned int flags);

函数说明:sendmsg()用来将数据由指定的socket传给对方主机. 参数s:为已建立好连线的socket, 如果利用UDP协议则不需经过连线操作. 参数msg:指向欲连线的数据结构内容, 参数flags 一般默认为0, 详细描述请参考send(). 返回值:成功返回发送的字节数,出错返回-1

recvmsg函数 定义函数

int recvmsg(int s, struct msghdr *msg, unsigned int flags); 函数说明:recvmsg()用来接收远程主机经指定的socket 传来的数据. 参数s 为已建立好连线的socket, 如果利用UDP 协议则不需经过连线操作. 参数msg 指向欲连线的数据结构内容, 参数flags 一般设0, 详细描述请参考send(). 返回值:成功则返回接收到的字符数, 失败则返回-1, 错误原因存于errno 中.

send函数 定义函数:int send(int s, const void * msg, int len, unsigned int falgs); 函数说明:send()用来将数据由指定的socket 传给对方主机. 参数s 为已建立好连接的socket. 参数msg 指向欲连线的数据内容. 参数len 则为数据长度. 参数flags 一般设0, 其他数值定义如下: MSG_OOB 传送的数据以out-of-band 送出. MSG_DONTROUTE 取消路由表查询 MSG_DONTWAIT 设置为不可阻断运作 MSG_NOSIGNAL 此动作不愿被SIGPIPE 信号中断. 返回值:成功则返回实际传送出去的字符数, 失败返回-1. 错误原因存于errno.

结构msghdr定义如下:

struct msghdr { void *msg_name; //发送或接收数据的地址 socklen_t msg_namelen; //地址长度 strcut iovec * msg_iov; //要发送或接受数据 size_t msg_iovlen; //容器数据长度 void * msg_control; //附属数据 size_t msg_controllen; //附属数据长度 int msg_flags; //接收消息的标志 }; 返回值:成功则返回实际传送出去的字符数, 失败返回-1, 错误原因存于errno 错误代码:

1、EBADF 参数s 非合法的socket 处理代码. 2、EFAULT 参数中有一指针指向无法存取的内存空间 3、ENOTSOCK 参数s 为一文件描述词, 非socket. 4、EINTR 被信号所中断. 5、EAGAIN 此操作会令进程阻断, 但参数s 的socket 为不可阻断. 6、ENOBUFS 系统的缓冲内存不足 7、ENOMEM 核心内存不足 EINVAL 传给系统调用的参数不正确. 附属数据msg_control结构 控制信息头部本身由下面的C结构定义:

struct cmsghdr { socklen_t cmsg_len; int cmsg_level; int cmsg_type; /* u_char cmsg_data[]; */ }; 其成员描述如下:

成员 描述 cmsg_len 附属数据的字节计数,这包含结构头的尺寸。这个值是由CMSG_LEN()宏计算的。 cmsg_level 这个值表明了原始的协议级别(例如,SOL_SOCKET)。 cmsg_type 这个值表明了控制信息类型(例如,SCM_RIGHTS)。 cmsg_data 这个成员并不实际存在,用来指明实际的额外附属数据所在的位置。 用sendmsg来传递数据程序实例

/*sendmsg.c*/ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> int main(int argc,char *argv[]) { int ret; /* 返回值 */ int sock[2]; /* 套接字对 */ struct msghdr msg; struct iovec iov[1]; char send_buf[100] = “it is a test”; struct msghdr msgr; struct iovec iovr[1]; char recv_buf[100]; /* 创建套接字对 */ ret = socketpair(AF_LOCAL,SOCK_STREAM,0,sock); if(ret == -1){ printf(“socketpair err\n”); return 1; } /* sock[1]发送数据到本地主机 */ bzero(&msg, sizeof(msg)); msg.msg_name = NULL; /* void*类型 NULL本地地址*/ msg.msg_namelen = 0; iov[0].iov_base = send_buf; iov[0].iov_len = sizeof(send_buf); msg.msg_iov = iov;//要发送或接受数据设为iov msg.msg_iovlen = 1;//1个元素 printf(“开始发送数据:\n”); printf(“发送的数据为: %s\n”, send_buf); ret = sendmsg(sock[1], &msg, 0 ); if(ret == -1 ){ printf(“sendmsg err\n”); return -1; } printf(“发送成功!\n”); /* 通过sock[0]接收发送过来的数据 */ bzero(&msg, sizeof(msg)); msgr.msg_name = NULL; msgr.msg_namelen = 0; iovr[0].iov_base = &recv_buf; iovr[0].iov_len = sizeof(recv_buf); msgr.msg_iov = iovr; msgr.msg_iovlen = 1; ret = recvmsg(sock[0], &msgr, 0); if(ret == -1 ){ printf(“recvmsg err\n”); return -1; } printf(“接收成功!\n”); printf(“收到数据为: %s\n”, recv_buf); /* 关闭sockets */ close(sock[0]); close(sock[1]); return 0; } 执行程序结果:

yu@ubuntu:~/Linux/217/pro_pool/socketpair gcc -o sendmsg sendmsg.c yu@ubuntu:~/Linux/217/pro_pool/socketpair ./sendmsg 开始发送数据: 发送的数据为: it is a test 发送成功! 接收成功! 收到数据为: it is a test 程序分析:由套接字sock[1]发数据到本地主机,由套接字sock[0]接收发送过来的数据。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/181993.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022年10月14日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档