您的位置:首页 > 理论基础 > 计算机网络

网络编程相关结构体整理

2016-04-13 17:49 627 查看
常用的套接字类型有3种:

  (1)流套接字(SOCK——STREAM):使用了面向连接的可靠的数据通信方式,即TCP协议;

  (2)数据报套接字(Raw Sockets):使用了不面向连接的数据传输方式,即UDP;

  (3)原始套接字(SOCK——RAW):没有经过处理的IP数据包,可以根据自己程序的要求进行封装。

1、套接字相关的数据类型:sockaddr和sockaddr_in;sockaddr用来保存一个套接字,定义如下:

struct sockaddr

{

unsigned short int sa_family; //指定通信地址类型,如果是TCP/IP通信,则值为AF_inet

char sa_data[14]; //最多用14个字符长度,用来保存IP地址和端口信息

};

struct sockaddr是通用的套接字地址,而struct sockaddr_in则是internet环境下套接字的地址形式,二者长度一样,都是16个字节。二者是并列结构,指向sockaddr_in结构的指针也可以指向sockaddr。一般情况下,需要把sockaddr_in结构强制转换成sockaddr结构再传入系统调用函数中。

struct sockaddr_in

{

unsigned short int sin_family; //指定通信地址类型

uint16_t sin_port; //套接字使用的端口号

struct in_addr sin_addr; //需要访问的IP地址

unsigned char sin_zero[8]; //未使用的字段,填充为0

};

  在这一结构中,in_addr也是一个结构体,定义如下,用于保存一个IP地址:

/* IPv4 address */

struct in_addr

{

uint32_t s_addt;

};

/* IPv6 address */

struct in6_addr

{

union

{

uint8_t __u6_addr8[16];

if defined __USE_MISC || defined __USE_GNU

uint16_t __u6_addr16[8];
uint32_t __u6_addr32[4];


endif

} __in6_u;


}

2、内核中用于接收/发送数据的结构体

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;

};

struct iovec {

ptr_t iov_base; /* Starting address */

size_t iov_len; /* Length in bytes */

};

成员msg_name与msg_namelen

这些成员只有当我们的套接口是一个数据报套接口时才需要。msg_name成员指向我们要发送或是接收信息的套接口地址。成员msg_namelen指明了这个套接口地址的长度。

当调用recvmsg时,msg_name会指向一个将要接收的地址的接收区域。当调用sendmsg时,这会指向一个数据报将要发送到的目的地址。

注意,msg_name定义为一个(void )数据类型。我们并不需要将我们的套接口地址转换为(struct sockaddr )。

成员msg_iov与msg_iovlen

Msg_iov中,iov_base字段指向一个缓冲区,缓冲区是存放的是所接收的数据或是将要发送的数据。iov_len字段在各种情况下分别确定了接收的最大长度以及实际写入的长度。

这些成员指定了我们的I/O向量数组的位置以及他包含多少项。msg_iov成员指向一个struct iovec数组。我们将会回忆起I/O向量指向我们的缓冲区。成员msg_iovlen指明了在我们的I/O向量数组中有多少元素。

成员msg_control与msg_controllen

这些成员指向了我们附属数据缓冲区并且表明了缓冲区大小。msg_control指向附属数据缓冲区,而msg_controllen指明了缓冲区大小。

成员msg_flags

当使用recvmsg时,这个成员用于接收特定的标记位(他并不用于sendmsg)。

3、向内核发送消息时使用msghdr,netlink socket使用自己的消息头nlmsghdr和自己的消息地址sockaddr_nl

struct nlmsghdr {

__u32 nlmsg_len;

__u16 nlmsg_type;

__u16 nlmsg_flags;

__u32 nlmsg_seq;

__u32 nlmsg_pid;

};

nlmsg_len 指定消息的总长度,包括紧跟该结构的数据部分长度以及该结构的大小,一般地,我们使用netlink提供的宏NLMSG_LENGTH来计算这个长度,仅需向NLMSG_LENGTH宏提供要发送的数据的长度,它会自动计算对齐后的总长度;

nlmsg_type 用于应用内部定义消息的类型,它对 netlink 内核实现是透明的,因此大部分情况下设置为 0;

nlmsg_flags 用于设置消息标志,对于一般的使用,用户把它设置为 0 就可以,只是一些高级应用(如 netfilter 和路由 daemon 需要它进行一些复杂的操作);

字段 nlmsg_seq 和 nlmsg_pid 用于应用追踪消息,前者表示顺序号,后者为消息来源进程 ID。

struct sockaddr_nl {

sa_family_t nl_family;

unsigned short nl_pad;

__u32 nl_pid;

__u32 nl_groups;

};

成员 nl_family为协议簇 AF_NETLINK;

成员 nl_pad 当前没有使用,因此要总是设置为 0;

成员 nl_pid 为接收或发送消息的进程的 ID,如果希望内核处理消息或多播消息,就把该字段设置为 0,否则设置为处理消息的进程 ID;

成员 nl_groups 用于指定多播组,bind 函数用于把调用进程加入到该字段指定的多播组,如果设置为 0,表示调用者不加入任何多播组。

4、控制信息头部本身由下面的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 这个成员并不实际存在。他用来指明实际的额外附属数据所在的位置。

/* Protocol families. */





nlmsg_type 决定这次要执行的操作,如查询当前路由表信息,所使用的就是RTM_GETROUTE。标准nlmsg_type包括:NLMSG_NOOP, NLMSG_DONE, NLMSG_ERROR等。根据采用的nlmsg_type不同,还要选取不同的数据结构来填充到nlmsghdr后面:

操作 数据结构

RTM_NEWLINK ifinfomsg

RTM_DELLINK

RTM_GETLINK

RTM_NEWADDR ifaddrmsg

RTM_DELADDR

RTM_GETADDR

RTM_NEWROUTE rtmsg

RTM_DELROUTE

RTM_GETROUTE

RTM_NEWNEIGH ndmsg/nda_chcheinfo

RTM_DELNEIGH

RTM_GETNEIGH

RTM_NEWRULE rtmsg

RTM_DELRULE

RTM_GETRULE

RTM_NEWQDISC tcmsg

RTM_DELQDISC

RTM_GETQDISC

RTM_NEWTCLASS tcmsg

RTM_DELTCLASS

RTM_GETTCLASS

RTM_NEWTFILTER tcmsg

RTM_DELTFILTER

RTM_GETTFILTER
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  sockets 通信 linux