79-辅助数据

Unix 域协议这一章的第一篇文章就是讨论如何在进程间传递描述符,可是后面似乎我们把这件事忘了。其实不然,我们一直在为这件事做铺垫,本文将进一步逼近“真相”。

辅助数据 (Ancillary) ,也叫控制数据,实际上在前面讲解 recvmsg 和 sendmsg 时提过一嘴,当时只是说先放一放。

1. 回忆 msghdr{}

还记得吧,这个结构体是 recvmsg 和 sendmsg 函数的第二个参数类型。

struct msghdr {
  void         *msg_name;
  socklen_t     msg_namelen;
  struct iovec *msg_iov;
  size_t        msg_iovlen;
  void         *msg_control; // 辅助数据
  size_t        msg_controllen; // 辅助数据大小
  int           msg_flags;
};

当时我们落下了两个成员 msg_control 和 msg_controllen 没有讲,现在时机到了。要想在进程间传递描述符,使用普通方法直接传递描述符是行不通的,所以辅助数据在这里派上了用场。

2. 辅助数据类型

辅助数据的类型是 cmsghdr{},如下:

struct cmsghdr {
  socklen_t     cmsg_len;
  int           cmsg_level;
  int           cmsg_type;
/* followed by
  unsigned char cmsg_data[]; */
};

如果要想在进程间传递描述符,可通过适当的设置 cmsg_level 和 cmsg_type 的值,并把描述符的值保存在 cmsg_data 中,就可以通过 sendmsg 将描述符发送给其它进程了。

msghdr{} 的成员 msg_control 是一个指针,它指向一个 cmsghdr{} 类型的”数组”。准确的说,它指向第一个辅助数据对象。


这里写图片描述
图1 msghdr{} 与 cmsghdr{}

2.1 三个长度概念

观察图1 ,一共有 3 个辅助数据对象,每个对象有三部分构成:{cmsghdr, 数据, 填充字节},这里衍生了几个长度概念:

  • CMSG_SPACE: 三部分长度的总和。
  • CMSG_LEN:cmsghdr 的长度 + 数据长度。
  • CMSG_ALIGN:数据长度 + 填充字节长度。(图中没有画)

实际上,这三个长度有着对应的宏,可以计算出来,分别是

size_t CMSG_SPACE(size_t length);
size_t CMSG_LEN(size_t length);
size_t CMSG_ALIGN(size_t length);

它们的参数,应该传递数据的长度。比如说数据长度是 4 字节,则根据三个宏算出来的 space, len 和 align 长度分别是:CMSG_SPACE(4), CMSG_LEN(4), CMSG_ALIGN(4).

2.2 根据 cmsghdr{} 地址获取数据地址

如果知道了 cmsghdr{} 的首地址,就可以取到数据的地址,使用宏 CMSG_DATA 就可以了,它的定义如下:

unsigned char *CMSG_DATA(struct cmsghdr *cmsg);

例如:

char* data = CMSG_DATA(&cm);

2.3 遍历所有 cmsghdr{}

有两个宏可以做到这一点:

// 根据 msghdr{} 获取第一个 cmsghdr{} 地址
struct cmsghdr *CMSG_FIRSTHDR(struct msghdr *msgh);

// 根据 msghdr{} 和 cmsghdr{} 获取下一个 cmsghdr{} 地址
struct cmsghdr *CMSG_NXTHDR(struct msghdr *msgh, struct cmsghdr *cmsg);

例如:

struct msghdr msg;
struct cmsghdr *cmptr;

/* 填充 msg */
/* 调用 recvmsg */

for (cmptr = CMSG_FIRSTHDR(&msg); cmptr != NULL; cmptr = CMSG_NEXTHDR(&msg, cmptr)); {
  char* data = CMSG_DATA(cmptr);
}

3. 实验

程序路径:

git clone https://git.oschina.net/ivan_allen/unp.git

如果你已经 clone 过这个代码了,请使用 git pull 更新一下。本节程序所使用的程序路径是 unp/program/unixdomainprotocols/ancillary.

程序 ancilla 使用方法如下:

./ancilla [--showsize size] [--showdata datacount]
  • --showsize:根据数据大小 size 计算 space, len, align 长度
  • --showdata:填充辅助数据,并遍历辅助数据,参数 datacount 表示创建几个辅助数据对象

3.1 showdata 代码

void showdata(int count) {
  int i, controllen;
  struct msghdr msg;
  struct cmsghdr *cmptr;
  union control{
    // 辅助数据头
    struct cmsghdr cm; 
    // 辅助数据对象大小是三部分的和。sizeof(int) 表示数据部分大小。
    char control[CMSG_SPACE(sizeof(int))]; 
  };
  union control *control_un;

  // 辅助数据总长度
  controllen = count * sizeof(union control);

  // 为辅助数据分配空间
  control_un = (union control*)malloc(controllen);;

  // 填充辅助数据
  for (i = 0; i < count; ++i) {
    control_un[i].cm.cmsg_len = CMSG_LEN(sizeof(int));
    control_un[i].cm.cmsg_level = i;
    control_un[i].cm.cmsg_type = i;
    *((int*) CMSG_DATA(&control_un[i].cm)) = 2*i + 1;
  }

  printf("controllen = %d\n", controllen);

  msg.msg_control = control_un;
  msg.msg_controllen = controllen;

  // 遍历辅助数据
  for (cmptr = CMSG_FIRSTHDR(&msg); cmptr != NULL; cmptr = CMSG_NXTHDR(&msg, cmptr)) {
    printf("cmsg_len = %d, cmsg_level = %d, cmsg_type = %d, data = %d\n"
        , cmptr->cmsg_len, cmptr->cmsg_level, cmptr->cmsg_type, *((int*) CMSG_DATA(cmptr)));
  }

  // 16 进制形式打印所有辅助数据
  printrawdata((char*)control_un, controllen);
}

3.2 实验结果


这里写图片描述
图2 查看三个长度


这里写图片描述
图3 遍历辅助数据

图 3 中创建了 5 个辅助数据对象,并进行遍历。

4. 总结

  • 掌握辅助数据的相关概念(几个长度概念)
  • 根据 cmsghdr{} 获取数据首地址
  • 遍历所有辅助数据对象
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
超级多的C#辅助类大全 网上有各式各样的帮助类,公共类,但是比较零碎,经常有人再群里或者各种社交账号上问有没有这个helper,那个helper,于是萌生了收集全部helper的念头,以便日后使用。各式各样的几乎都能找到,所有功能性代码都是独立的类,类与类之间没有联系,可以单独引用至项目。 1. C#读取AD域里用户名或组 2. Chart图形 3. cmd 4. Cookie&Session 5. CSV文件转换 6. DataTable转实体 7. DBHelper 8. DecimalUtility及中文大写数字 9. DLL 10. Excel操作类 11. FTP操作类 12. H5-微信 13. Html操作类 14. INI文件读写类 15. IP辅助类 16. Javascript 17. Json 18. JSON操作 19. JS操作 20. Lib 21. Mime 22. Net 23. NPOI 24. obj 25. packages 26. Path 27. PDF 28. Properties 29. QueryString 地址栏参数 30. RDLC直接打印帮助类 31. ResourceManager 32. RMB 33. SqlHelper 34. SQL语句拦截器 35. URL的操作类 36. VerifyCode 37. XML操作类 38. 上传下载 39. 二维码操作类 40. 共用工具类 41. 其他 42. 分词辅助类 43. 分页 44. 加密解密 45. 压缩解压缩 46. 各种验证帮助类 47. 图片 48. 图片操作类 49. 图片验证码 50. 处理多媒体的公共类 51. 处理枚举类 52. 字符串 53. 对象转换处理 54. 帮助文档 55. 序列化 56. 异步线程 57. 弹出消息类 58. 数据展示控件绑定数据类 59. 文件操作类 60. 日历 61. 日志 62. 时间戳 63. 时间操作类 64. 条形码 65. 条形码帮助类 66. 条形码转HTML 67. 检测是否有Sql危险字符 68. 正则表达式 69. 汉字转拼音 70. 注册表操作类 71. 科学计数,数学 72. 类型转换 73. 系统操作相关的公共类 74. 缓存 75. 网站安全 76. 网站路径操作类 77. 网络 78. 视频帮助类 79. 视频转换类 80. 计划任务 81. 邮件 82. 邮件2 83. 配置文件操作类 84. 阿里云 85. 随机数类 86. 页面辅助类 87. 验证码

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值