Various structures of socket in Linux network programming

The following source codes are in these source files

#include <sys/socket.h>	// 通用socket地址存放的地方
#include <linux/in.h>		// ipv4版本的socket地址存放的地方
#include <linux/in6.h>	// ipv6版本的socket地址存放的地方
#include <linux/un.h>		// unix版本的socket地址存放的地方

Universal address of socket

 struct socketaddr{
    
    
     sa_family_t sa_Family;           /** 指明socket所属的协议族类型,主要有3种
                                        * 地址族:AF_UNIX、          AF_INET、        AF_INET6
                                        * 协议族:PF_UNIX、          PF_INET、        PF_INET6
                                        * 描述 :UNIX本地域协议族、   TCP/IPv4协议族、  TCP/IPv6协议族
                                        * 他们3个的对应的地址族和协议族的值都是相等的,因此都是可以互换着用的
                                        */
     char sa_data[14];                /** 用于存放socket地址值,地址的长度也和协议族有关系
                                        * PF_UNIX:文件的路径名,长度可达108字节
                                        * PF_INET:16bit端口号和32bitIPv4地址,共6字节
                                        * PF_INET6: 16bit的端口号,32bit流标识,128bitIpv6地址,32bit范围ID,共26字节
                                        * 因此这里只有14字节的长度是不够使用的,后来使用下面那种
                                        */
 };


/**
 * 5.1.2 新的通用socket地址
 */
 struct socketaddr_storage{
    
    
     sa_family_t sa_family;
     unsigned long int __ss_align;
     char __ss_padding[128-sizeof(__ss_align)]; // 存放socket地址,总共120字节
     // 3种协议的地址值都可以存放,这里和源码不太一样,想要对齐128还需要减去sa_family的大小,最后应为118,最后数组大小应该为
     // char __ss_padding[128-sizeof(__ss_align)-sizeof(sa_family_t)]
 };

Let's go to the source code

// 在socket.h中
// 下面这个sockaddr和上面的socketaddr是大致是一样的
struct sockaddr
  {
    
    
    __SOCKADDR_COMMON (sa_);	/* Common data: address family and length.  */
    char sa_data[14];		/* Address data.  */
  };

// 前往查看__SOCKADDR_COMMON,本质上是sa_family_t的别名,在预处理时会替换回去
#define	__SOCKADDR_COMMON(sa_prefix) \
  sa_family_t sa_prefix##family
// 前往查看sa_family_t,本质上是unsigned short int的别名,用数字代表某些地址族,和协议族相对应,在上面展示了主要是用的地址族和他们对应的协议族
typedef unsigned short int sa_family_t;

// 看第二个对应的socket通用类型的源码,
struct sockaddr_storage
  {
    
    
    __SOCKADDR_COMMON (ss_);	/* Address family, etc.  */
    char __ss_padding[_SS_PADSIZE];
    __ss_aligntype __ss_align;	/* Force desired alignment.  */
  };
// 第一个成员的和上面一样
// 第二个成员是一个char数组,大小为_SS_PADSIZE
#define _SS_PADSIZE \
  (_SS_SIZE - __SOCKADDR_COMMON_SIZE - sizeof (__ss_aligntype))

// 这3个都是别名,在预处理时会替换,我的机器上数组大小为120,
#define _SS_SIZE 128
#define __SOCKADDR_COMMON_SIZE	(sizeof (unsigned short int))
#define __ss_aligntype	unsigned long int

Private socket address

All special socket address type variables need to be converted to the general socket address type sockaddr in actual use, because all socket programming interfaces use address parameters of the type sockaddr.
So both need to be less than 118 bytes.

  1. Private socket address of IPv4 protocol family
struct sockaddr_in {
    
    
  __kernel_sa_family_t	sin_family;	/* Address family		*/
  __be16		sin_port;	/* Port number			*/
  struct in_addr	sin_addr;	/* Internet address		*/

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

// 第一个就不多说
// 第二个参数是端口也就是unsigned short,为两个字节,16bit,对应tcp/ip报头的端口所占位数
typedef __u16 __bitwise __be16;
typedef unsigned short __u16;
// 第三个成员是ip地址,他是一个结构体,里面包含一个32位的unsigned int类型的成员,共4字节
struct in_addr {
    
    
	__be32	s_addr;
};
typedef __u32 __bitwise __be32;
typedef unsigned int __u32;
// 第四个成员是用来填充的,因为网络上都是用的通用socket,到解构时才根据对应的协议的专用socket进行解析具体信息,
// 因此需要专用的socket长度和通用相等,使得他们能相互转换,等到使用时在转换回来就行,因此这里需要将整个结构体填充成16字节,这里对应的是第一种通用结构体,128太大了浪费内存
#define __SOCK_SIZE__	16
  1. Private socket address of IPv6 protocol family
// 总计大小为2+2+4+16+4=28字节
struct sockaddr_in6 {
    
    
	unsigned short int	sin6_family;    /* AF_INET6 */
	__be16			sin6_port;      /* Transport layer port # */
	__be32			sin6_flowinfo;  /* IPv6 flow information */
	struct in6_addr		sin6_addr;      /* IPv6 address */
	__u32			sin6_scope_id;  /* scope id (new in RFC2553) */
};
// 第一个成员类型:unsigned short int	大小为2字节,共16bit
// 第二个成员类型:unsigned short 大小为2字节,共16bit,符合报文中的首部的端口号大小格式
typedef __u16 __bitwise __be16;
typedef unsigned short __u16;
// 第三个成员类型: unsigned int 大小为4个字节,共32bit,这里应该是流标号,书上为20bit,这里用32bit,以实际为准
typedef __u32 __bitwise __be32;
typedef unsigned int __u32;
// 第四个成员为ipv6地址大小为128bit,也就是16字节
// 下面是一个union,每时每刻union中只有一个成员有值,这些成员的大小都是128bit因此union大小为128bit也就是16字节
struct in6_addr {
    
    
	union {
    
    
		__u8		u6_addr8[16];
#if __UAPI_DEF_IN6_ADDR_ALT
		__be16		u6_addr16[8];
		__be32		u6_addr32[4];
#endif
	} in6_u;
typedef unsigned char __u8;
typedef __u16 __bitwise __be16;
typedef unsigned short __u16;
typedef __u32 __bitwise __be32;
typedef unsigned int __u32;
// 第四个成员是范围ID,大小为32bit,共4字节,类型为unsigned int
typedef unsigned int __u32;
	
  1. The dedicated socket address of the UNIX protocol family. One way of inter-process communication is to use UNIX sockets. When people use this method, they often use a method called local sockets instead of network sockets. . Doing so avoids leaving a back door for hackers.
// 很简单,通过上面那些例子这个就很容易看懂了
struct sockaddr_un {
    
    
	__kernel_sa_family_t sun_family; /* AF_UNIX */
	char sun_path[UNIX_PATH_MAX];	/* pathname */
};
#define UNIX_PATH_MAX	108

Guess you like

Origin blog.csdn.net/A_easy_learner/article/details/129316552
Recommended