socketpair()函数的声明:

#include <sys/types.h>
#include <sys/socket.h>
int socketpair(int d, int type, int protocol, int sv[2]);

socketpair()函数用于创建一对无名的、相互连接的套接子。 
如果函数成功,则返回0,创建好的套接字分别是sv[0]和sv[1];否则返回-1,错误码保存于errno中。

基本用法: 
1. 这对套接字可以用于全双工通信,每一个套接字既可以读也可以写。例如,可以往sv[0]中写,从sv[1]中读;或者从sv[1]中写,从sv[0]中读; 
2. 如果往一个套接字(如sv[0])中写入后,再从该套接字读时会阻塞,只能在另一个套接字中(sv[1])上读成功; 
3. 读、写操作可以位于同一个进程,也可以分别位于不同的进程,如父子进程。如果是父子进程时,一般会功能分离,一个进程用来读,一个用来写。因为文件描述副sv[0]和sv[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;//要发送或接受数据设为iovmsg.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]接收发送过来的数据。

socketpair的用法和理解相关推荐

  1. socketpair的用法和理解之非阻塞

     阻塞状态:读阻塞 #include <stdio.h> #include <string.h> #include <unistd.h> #include < ...

  2. promise用法_JavaScript中的async/await的用法和理解

    昨天更新的是"JavaScript中的Promise使用详解",其实也就是说了下基本用法和自己对Promise的理解,可能有错误之处,也欢迎指出.今天就说一说"JavaS ...

  3. JavaScript中异步/等待的用法和理解

    昨天更新的是"JavaScript中的Promise使用详解",其实也就是说了下基本用法和自己对Promise的理解,可能有错误之处,也欢迎指出.今天就说一说"JavaS ...

  4. 从kernel源代码的角度分析signal的错误用法和理解

    读这份文档之前,建议先浏览一下 <Unix Advanced Programming >里面的signal 一章和下面这份出 自IBM 论坛的文章:进程间通信 信号(上) http://w ...

  5. std:move基本用法和理解

    场景: C++ 标准库使用比如vector::push_back 等这类函数时,会对参数的对象进行复制,连数据也会复制.这就会造成对象内存的额外创建, 本来原意是想把参数push_back进去就行了. ...

  6. 关于一个学习计算机专业,迷茫的大一新生的看法和理解

    一.高考志愿选择时的想法: 在2022年,我在经历了丰富精彩的高三生活后,我终于在高考成绩公布的那晚,整个人都如释重负了,高中三年的努力让我上了一个不错的本科,但也怪自己不是那种拼命努力学习的人,高考 ...

  7. JS中的async/await的用法和理解

    1.首先需要理解async 和 await的基本含义 async 是一个修饰符,async 定义的函数会默认的返回一个Promise对象resolve的值,因此对async函数可以直接进行then操作 ...

  8. mysql explain 用法和理解

    explain显示了mysql如何使用索引来处理select语句以及连接表.可以帮助选择更好的索引和写出更优化的查询语句. 使用方法:在select语句钱加上explain就可以了 example:  ...

  9. repo 的用法和理解

    repo是调git的脚本 repo的用法 注:repo只是google用Python脚本写的调用git的一个脚本,主要是用来下载.管理Android项目的软件仓库.(也就是说,他是用来管理给git管理 ...

最新文章

  1. Safari下弹窗问题的解决办法
  2. VISUAL STUDIO 2019 快捷键
  3. commons-lang常用工具类StringEscapeUtils使用--转
  4. 如何实现可以获取最小值的栈?
  5. mysql online ddl和pt_online ddl与pt-osc详解
  6. 不来这里买器件?亏大发了!
  7. 学习ASP.NET Core,你必须知道“中间件”是什么?中间件如何注册?请求处理管道是如何通过中间件构建的?
  8. 【HDU - 5963】朋友(博弈,思维,必胜态必败态,找规律)
  9. hdu 2612 FindAWay 两点BFS
  10. Java基础知识(JAVA中String、StringBuffer、StringBuilder类的区别)
  11. Coursera心理学课程考试小抄
  12. Python学习-2.安装IDE
  13. C#System.Text.RegularExpressions.Regex使用
  14. R语言使用timeROC包计算存在竞争风险情况下的生存资料多时间AUC值、使用cox模型、并添加协变量、R语言使用timeROC包的plotAUCcurve函数可视化多时间生存资料的AUC曲线
  15. sikuli实现百度云批量离线下载
  16. 各类dp的总结+例题
  17. 【迁移学习】STL(Stratified Transfer Learning)小结
  18. 谈谈Gameplay,以及UE4的Gameplay框架
  19. android 布局覆盖 超出一部分_谈谈移动端屏幕适配的几种方法
  20. python爬虫论文参考文献格式_Python爬虫进阶必备 | XX文学加密分析实例

热门文章

  1. 超级计算机英语怎么读的,沃森超级计算机的意思
  2. 看完吊打面试官!微信小程序趋势及前景,复习指南
  3. 热烈祝贺惠州学院翰墨缘书法协会第十三届书法作品展圆满成功!
  4. android 彩信
  5. 基于SSM和Boostrap实现的电影评论网站设计
  6. linux系统串口透传,基于CC2540的USB虚拟串口透传方案
  7. 教你用tcgames电脑玩刺激战场匹配手机的正确姿势:如何降低延迟卡顿
  8. 学校人员定位管理系统
  9. 获取汉字的首字母和全拼
  10. html5--6-44信纸设计