套接字编程

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了套接字编程相关的知识,希望对你有一定的参考价值。

一、套接字地址结构

  大多数套接字函数都需要一个指向套接字地址结构的指针作为参数,每个协议族都定义它自己的套接字地址结构,这些结构的名字均以sockaddr_开头,并以对应每个协议族的唯一后缀结尾。

1.1  IPv4套接字地址结构

  IPv4套接字地址结构通常也称为“网际套接字地址结构”,它以sockaddr_in命名,定义在<netinet/in.h>头文件中。以下为POSIX定义:

struct in_addr{
  in_addr_t a_addr;  //32_bit IPv4 address,network byte ordered
};        

其中in_addr_t数据类型必须是一个至少32位的无符号整数类型。

 

struct sockaddr_in{

  uint8_t         sin_len;        //length of structure (16)

  sa_family_t       sin_family;    //AF_INET

  in_port_t        sin_port;       //16-bit TCP or UDP port number,network byte ordered 

  struct in_addr    sin_addr;       //32-bit IPv4 address,network byte ordered 

  char           sin_zero[8];     //unused

};

 

 各结构体成员解析:

1)sin_len:不是所有的厂家都支持这个字段,POSIX规范也不要求这个成员,它是为增加OSI协议的支持而随4.3BSD-Reno添加的。简化了长度可变套接字地址结构的处理。除了涉及路由套接字,其他都不需要设置和检查这个字段。

2)sin_family:指代协议族,socket编程使用AF_INET。数据类型sa_family_t可以是任何无符号整数类型。在支持长度字段的实现中,它通常是一个8位无符号整数,不支持长度字段的实现,则为一个16位的无符号整数。

3)sin_port:端口号,必须是一个至少16位的无符号整数。网络字节序

4)sin_addr:IP地址,32位无符号整数,网络字节序。32位IPV4地址存在两种访问方法:①serv.sin_addr将按in_addr结构引用其中的32位IPv4地址②serv.sin_addr.s_addr将按in_addr_t引用地址32位IPv4地址。

5)sin_zero:未曾使用,在初始化结构时,我们一般是将整个结构设置为0,而不仅仅是设置sin_zero成员为0。虽然多数结构的使用不要求这一成员为0,但当捆绑一个非通配IPv4地址时,此成员必须为0

 

注意点:

in_addr结构之前是多种结构的联合,之后废除了联合,所以现在in_addr定义为仅有一个In_addr_t字段的结构。

套接口地址结构仅在给定主机上使用:虽然结构中的某些成员(如IP地址和端口号)用在不同主机间的通信中,但结构本身并不参与通信

 

1.2  通用套接字地址结构

  当作为一个参数传递进任何套接字函数时,套接字地址结构总是以引用形式(也就是以指向该结构的指针)来传递。但是这样的话任何套接字函数必须处理来自所支持的任何协议族的套接字地址结构。通用套接字地址结构就是为解决这个问题诞生的。

在<sys/socket.h>头文件中定义了一个通用的套接字地址结构,如下:

struct sockaddr{
  uint8_t    sa_len;        
  sa_family_t  sa_family;       //address family:AF_XXX value
  char      sa_data[14];      //protocol-specific address
};

 

于是,套接字函数被定义为以指向某个通用套接字地址结构的一个指针作为参数之一,如bind函数的ANSI C函数原型:

int bind(int,struct sockaddr *,socklen_t);

也就是说,指向特定协议的套接字地址结构的指针强制转换成通用套接字地址结构。

struct sockaddr_in serv;

bind(sockfd,(struct sockaddr *)&serv,sizeof(serv));

 

1.3  IPV6套接字地址结构

  IPv6套接字地址结构在<netinet/in.h>头文件中定义:

struct in6_addr{
  uint8_t  s6_addr[16];            //128-bit IPv6 address
};

#define SIN6_LEN                 //required for compile-time tests
     struct sockaddr_in6{
  uint8_t       sin6_len;       
//length of this struct(28)   sa_family_t     sin6_family;     //AF_INET6   in_port_t      sin6_port;       //transport layer port#  network byte ordered   uint32_t      sin6_flowinfo;   //flow information,undefined   struct in6_addr  sin6_addr;       //IPv6 address   network byte ordered   uint32_t      sin6_scope_id;   //set of interfaces for a scope };

 

注意点:

1)如果系统支持套接字地址结构中的长度字段,那么SIN6_LEN常值必须定义。

2)IPv6的地址族是AF_INET6,而IPv4是AF_INET。

3)结构中字段的先后做过编排,使得如果sockaddr_in6结构本身是64位对齐的,那么128位的sin6_addr字段也是64位对齐。在一些64位处理机上,如果64位数据存储在某个64位边界位置,那么对它的访问将得到优化处理。

4)sin6_flowinfo是流标字段,底序20位是流标,高12位保留。

5)对于具备范围的地址,sin6_scope_id字段标识其范围。

 

1.4  新的通用套接字地址结构

  作为IPv6套接字API的一部分而定义的新的通用套接字地址结构克服了现有struce sockaddr的一些缺点。其足以容纳系统所支持的任何套接字地址结构。sockaddr_storage定义在<netinet/in.h>头文件中:

struct sockaddr_storage{

uint8_t      ss_len;      //length of this struct(implementation dependent)
sa_family  ss_family;      //address family:AF_XXX value

};

  

1)如果系统支持的任何套接字地址结构有对齐需要,那么sockaddr_storage能够满足苛刻的对齐要求。

2)sockaddr_storage足够大,能够容纳系统支持的任何套接字地址结构。

3)除了上面两个字段(如果有的话),sockaddr_storage结构的其他字段对用户来说是透明的。

4)sockaddr_storage结构必须类型强制转换成或复制到适合与ss_family字段所给出地址类型的套接字结构中,才能访问其他字段。

 

1.5  套接字地址结构的比较

技术分享

 

以上是关于套接字编程的主要内容,如果未能解决你的问题,请参考以下文章

片段和活动之间的核心区别是啥?哪些代码可以写成片段?

VSCode自定义代码片段——JS中的面向对象编程

VSCode自定义代码片段9——JS中的面向对象编程

使用 Pygments 检测代码片段的编程语言

面向面试编程代码片段之GC

如何在 Django Summernote 中显示编程片段的代码块?