Chinaunix首页 | 论坛 | 博客
  • 博客访问: 234921
  • 博文数量: 31
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 296
  • 用 户 组: 普通用户
  • 注册时间: 2016-06-22 11:52
文章分类

全部博文(31)

文章存档

2018年(3)

2017年(11)

2016年(12)

2015年(5)

我的朋友

分类: C/C++

2017-06-18 21:29:22


点击(此处)折叠或打开

  1. /***********ipv4的套接字地址*********************************/

  2. struct sockaddr_in {
  3.   __kernel_sa_family_t sin_family; /* AF_INET */
  4.   __be16 sin_port; /* Port number */
  5.   struct in_addr sin_addr; /* Internet address */

  6.   /* Pad to size of `struct sockaddr'. */
  7.   unsigned char __pad[__SOCK_SIZE__ - sizeof(short int) -
  8.                         sizeof(unsigned short int) - sizeof(struct in_addr)];
  9. };


点击(此处)折叠或打开

  1. /********* ipv6的套接字地址***********************/

  2. struct sockaddr_in6 {
  3.         unsigned short int sin6_family; /* AF_INET6 */
  4.         __be16 sin6_port; /* Transport layer port # */
  5.         __be32 sin6_flowinfo; /* IPv6 flow information */
  6.         struct in6_addr sin6_addr; /* IPv6 address */
  7.         __u32 sin6_scope_id; /* scope id (new in RFC2553) */
  8. };

点击(此处)折叠或打开

  1. /*********netlink通讯的套接字地址**************************/
  2. struct sockaddr_nl {
  3.         __kernel_sa_family_t nl_family; /* AF_NETLINK */
  4.         unsigned short nl_pad; /* zero */
  5.         __u32 nl_pid; /* port ID */
  6.         __u32 nl_groups; /* multicast groups mask */
  7. };

点击(此处)折叠或打开

  1. /*设备无关的物理层地址结构,通过setsockopt可以设置网卡的多播或混杂模*/

  2. struct sockaddr_ll {
  3.         unsigned short sll_family; /* AF_PACKET*/
  4.         __be16 sll_protocol;
  5.         int sll_ifindex;
  6.         unsigned short sll_hatype;
  7.         unsigned char sll_pkttype;
  8.         unsigned char sll_halen;
  9.         unsigned char sll_addr[8];
  10. };
  11. linux 2.0 以前的版本是用struct sockaddr_pkt 的,而且获取二层的socket是通过socket(AF_INET, SOCK_PACKET, protocol)来获取的,并没有AF_PACKET 这个domain ,只有SOCK_PACKET这个socket_type


点击(此处)折叠或打开

  1. /*********通用套接字地址**************************/

  2. struct sockaddr {
  3.         sa_family_t sa_family; /* address family, AF_xxx */
  4.         char sa_data[14]; /* 14 bytes of protocol address */
  5. }


  6. #define _K_SS_MAXSIZE    128    /* Implementation specific max size */
  7. #define _K_SS_ALIGNSIZE    (__alignof__ (struct sockaddr *))
  8.                 /* Implementation specific desired alignment */

  9. typedef unsigned short __kernel_sa_family_t;

  10. #define sockaddr_storage __kernel_sockaddr_storage
  11. struct __kernel_sockaddr_storage {
  12.     __kernel_sa_family_t    ss_family;        /* address family */
  13.     /* Following field(s) are implementation specific */
  14.     char        __data[_K_SS_MAXSIZE - sizeof(unsigned short)];
  15.                 /* space to achieve desired size, */
  16.                 /* _SS_MAXSIZE value minus size of ss_family */
  17. } __attribute__ ((aligned(_K_SS_ALIGNSIZE)));    /* force desired alignment */

  18. struct sockaddr 和struct sockaddr_storage 都是通用套接字


为了统一各种协议,socket对应的接口就定义了两个通用结构,分别是sockaddr(16字节)sockaddr_storage(128字节) ,其中sockaddr_storage是为了适配sockaddr_in6(28字节)这样长度比较大的协议而后来定义的,如果需要用到sockaddr_storage 这样的通用套接字,则强转为sockaddr,并且长度用sizeof(struct sockaddr_storage) 

 

网络编程中的一下几个接口会用到以上的数据结构

应用层->内核,对应用层来说就是发送的,数据是送到协议栈的,addrlen是入参

int bind   (int sockfd, struct sockaddr *my_addr, socklen_t addrlen);

int connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen);

int sendto (int s, const void *msg, size_t len, int flags, const struct sockaddr *to, socklen_t tolen);

内核->应用层的,对应用层来说就是接收的,数据从协议栈上来的,addrlen是值-结果参数

int  accept     (int s, struct sockaddr *addr, socklen_t *addrlen);

int  recvfrom (int s, void  *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen);

int  getpeername(int s, struct sockaddr *name, socklen_t *namelen);

int  getsockname(int s, struct sockaddr *name, socklen_t *namelen);

 

getsockname: 返回本地协议地址:getpeername:返回远程协议地址

适用场景:

1.当不用bind()或调用bind()没有指定本地协议地址时,可以调用getsockname()来返回内核分配给此连接的本地IP地址和端口号,还可以获得某套接口的协议族。

2.当一个新的连接建立时,服务器也可以调用getsockname()来获得分配给此连接的本地IP地址。

3.当一个服务器的子进程调用exec函数启动执行时,只能调用getpeername()函数来获得客户的Ip地址和端口号。

4.未调用bind()就调用了connect(),这时唯有getsockname()调用可以获知系统内定的本地地址。在返回时,namelen参数包含了名字的实际字节数。

 

阅读(21138) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~