UDP涉及到的结构体和函数原型

42 篇文章 0 订阅
涉及到的结构体和函数原型
(一)涉及到的结构体
1、struct in_addr
 
struct in_addr {
    in_addr_t s_addr;
};
结构体in_addr 用来表示一个32位的IPv4地址.
in_addr_t 一般为 32位的unsigned long,其字节顺序为网络顺序(network byte ordered),即该无符号整数采用大端字节序
2、struct msghdr
recvmsg()使用 msghdr 结构体(structure )减少参数传递的数目。这个结构体定义在 <sys/socket.h>中,如下所示
struct iovec {                   /* Scatter/gather array items */
   void  *iov_base;              /* Starting address */
   size_t iov_len;               /* Number of bytes to transfer */
};

struct msghdr {
   void         *msg_name;       /* optional address */
   socklen_t     msg_namelen;    /* size of address */
   struct iovec *msg_iov;        /* scatter/gather array */
   size_t        msg_iovlen;     /* # elements in msg_iov */
   void         *msg_control;    /* ancillary data, see below */
   size_t        msg_controllen; /* ancillary data buffer len */
   int           msg_flags;      /* flags on received message */
};

struct msghdr看上去似乎是一个需要创建的巨大的结构。但是不要怕。其结构成员可分为四组:
 套接口地址成员: msg_name与msg_namelen。
I/O向量引用:msg_iov与msg_iovlen。
附属数据缓冲区成员:msg_control与msg_controllen。
接收信息标记位:msg_flags。
在我们将这个结构分为上面的几类以后,结构看起来就不那样巨大了。
成员msg_name与msg_namelen
这些成员只有当我们的套接口是一个数据报套接口时才需要。msg_name成员指向我们要发送或是接收信息的套接口地址。成员msg_namelen指明了这个套接口地址的长度。
当调用recvmsg时,msg_name会指向一个将要接收的地址的接收区域。当调用sendmsg时,这会指向一个数据报将要发送到的目的地址。
注意,msg_name定义为一个(void *)数据类型。我们并不需要将我们的套接口地址转换为(struct sockaddr *)。
成员msg_iov与msg_iovlen
这些成员指定了我们的I/O向量数组的位置以及他包含多少项。msg_iov成员指向一个struct iovec数组。我们将会回忆起I/O向量指向我们的缓冲区。成员msg_iov指明了在我们的I/O向量数组中有多少元素。
成员msg_control与msg_controllen
这些成员指向了我们附属数据缓冲区并且表明了缓冲区大小。msg_control指向附属数据缓冲区,而msg_controllen指明了缓冲区大小。
成员msg_flags
当使用recvmsg时,这个成员用于接收特定的标记位(他并不用于sendmsg)。在这个位置可以接收的标记位如下表所示:
标记位
描述 
MSG_EOR
 当接收到记录结尾时会设置这一位。这通常对于SOCK_SEQPACKET套接口类型十分有用。
MSG_TRUNC
这个标记位表明数据的结尾被截短,因为接收缓冲区太小不足以接收全部的数据。
MSG_CTRUNC
这个标记位表明某些控制数据(附属数据)被截短,因为缓冲区太小。
MSG_OOB
这个标记位表明接收了带外数据。
MSG_ERRQUEUE
个标记位表明没有接收到数据,但是返回一个扩展错误。
 
3、struct cmsghdr结构
recvmsg与sendmsg函数允许程序发送或是接收附属数据。然而,这些额外的信息受限于一定的格式规则。下面将会介绍控制信息头与程序将会用来管理这些信息的宏。
属信息可以包括0,1,或是更多的单独附属数据对象。在每一个对象之前都有一个struct cmsghdr结构。头部之后是填充字节,然后是对象本身。最后,附属数据对象之后,下一个cmsghdr之前也许要有更多的填充字节。在这里,我们将要关注的附属数据对象是文件描述符与证书结构。
图1显示了一个包含附属数据的缓冲区是如何组织的。
 
                   
                                                  图1  辅助数据结构是由各种子结构、数据区, 填充字节构成
我们需要注意以下几点:
cmsg_len与CMSG_LEN()宏值所显示的长度相同。
CMSG_SPACE()宏可以计算一个附属数据对象的所必需的空白。
msg_controllen是CMSG_SPACE()长度之后,并且为每一个附属数据对象进行计算。
 
struct cmsghdr {
   socklen_t cmsg_len;    /* data byte count, including header */
   int       cmsg_level;  /* originating protocol */
   int       cmsg_type;   /* protocol-specific type */
   /* followed by unsigned char cmsg_data[]; */
};
其成员描述如下:
成员    描述
cmsg_len      附属数据的字节计数,这包含结构头的尺寸。这个值是由CMSG_LEN()宏计算的。
cmsg_level   这个值表明了原始的协议级别(例如,SOL_SOCKET)。
cmsg_type    这个值表明了控制信息类型(例如,SCM_RIGHTS)。
cmsg_data   这个成员并不实际存在。他用来指明实际的额外附属数据所在的位置。
这一章所用的例子程序只使用SOL_SOCKET的cmsg_level值。这一章我们感兴趣的控制信息类型如下(cmsg_level=SOL_SOCKET):
cmsg_level
描述
SCM_RIGHTS
附属数据对象是一个文件描述符
SCM_CREDENTIALS
附属数据对象是一个包含证书信息的结构
    
(二)涉及的函数
1、setsockopt函数原型
//setsockopt函数原型
#include <sys/types.h>
#include <sys/socket.h>
int setsockopt(int s, int level, int optname,
                      const void *optval, socklen_t optlen);
 
2、cmsg 宏
由于附属数据结构的复杂性,Linux系统提供了一系列的C宏来简化我们的工作。另外,这些宏可以在不同的UNIX平台之间进行移植,并且采取了一些措施来防止将来的改变。这些宏是由cmsg(3)的man手册页来进行描述的,其概要如下:

#include <sys/socket.h>
struct cmsghdr *CMSG_FIRSTHDR(struct msghdr *msgh);
struct cmsghdr *CMSG_NXTHDR(struct msghdr *msgh, struct cmsghdr *cmsg);
size_t CMSG_ALIGN(size_t length);
size_t CMSG_SPACE(size_t length);
size_t CMSG_LEN(size_t length);
void *CMSG_DATA(struct cmsghdr *cmsg);

CMSG_DATA()宏
这个宏接受一个指向cmsghdr结构的指针。返回的指针值指向跟随在头部以及填充字节之后的附属数据的第一个字节(如果存在)。如果指针mptr指向一个描述文件描述符的可用的附属数据信息头部,这个文件描述符可以用下面的代码来得到:
struct cmsgptr *mptr;
int fd; /* File Descriptor */
. . .
fd = *(int *)CMSG_DATA(mptr);
CMSG_FIRSTHDR()宏
这个宏用于返回一个指向附属数据缓冲区内的第一个附属对象的struct cmsghdr指针。输入值为是指向struct msghdr结构的指针(不要与struct cmsghdr相混淆)。这个宏会估计msghdr的成员msg_control与msg_controllen来确定在缓冲区中是否存在附属对象。然后,他会计算返回的指针。
如果不存在附属数据对象则返回的指针值为NULL。否则,这个指针会指向存在的第一个struct cmsghdr。这个宏用在一个for循环的开始处,来开始在附属数据对象中遍历。
CMSG_NXTHDR()宏
这个用于返回下一个附属数据对象的struct cmsghdr指针。这个宏会接受两个输入参数:
指向struct msghdr结构的指针
指向当前struct cmsghdr的指针
如果没有下一个附属数据对象,这个宏就会返回NULL。
 
参考链接
Get destination address of a received UDP packet
套接字选项(四)
inet_pton & inet_ntop函数
in_addr
Listen for and receive UDP datagrams in C
关于struct msghdr和struct cmsghdr
Linux Socket Programming by Example - Warren Gay
Linux Socket学习
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值