socket 初识

本文深入探讨了套接字通信的基本原理,包括套接字描述符的概念,如何使用socket()函数创建套接字,以及IPv4和IPv6套接字地址结构的详细解析。文章还介绍了字节序的重要性及转换函数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

套接字

套接字描述符

套接字是通信端点的抽象。就比如使用文件描述符访问文件,应用程序用套接字描述符访问套接字。

#include <sys/socket.h>
int socket(int domain, int type, int protocol);
  • 参数说明:
  1. domain (域): 确定通信的特性,包括地址格式。

套接字通信域(部分表)

描述
AF_INETIPv4 因特网域
AF_INET6IPv6 因特网域
  1. type: 确定套接字类型,进一步确定通信特征。

图:套接字类型

类型描述
SOCK_DGRAM固定长度的、无连接的、不可靠的报文传递
SOCK_RAMIP 协议的数据报接口
SOCK_SEQPACKET固定长度的、有序的、可靠的、面向连接的报文传递
SOCK_STREAM有序的、可靠的、双向的、面向连接的字节流
  1. protocol: 通常为0, 表示为给定的域和套接字类型选择默认的协议。当对同一域和套接字类型支持多个协议式,可以使用 protocol 选择一个特定的协议。在 AF_INET 通信域中,套接字类型 SOCK_STREAM 的默认协议是 TCP 协议;套接字类型 SOCK_DGRAM 默认协议是 UDP。
协议描述
IPPROTO_IPIPv4 网际协议
IPPROTO_IPV6IPv6 网际协议
IPPROTO_ICMP因特网控制报文协议
IPPROTO_RAW原始 IP 数据包协议
IPPROTO_TCP/6传输控制协议
IPPROTO_UDP/17用户数据报协议

寻址

1. 字节序

字节序

2. 地址格式

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

  • 通用套接字地址结构
    一个地址标识一个特定通信域的套接字端点,地址格式与这个特定的通信域相关。为了使不同的格式地址能够传入到套接字函数,地址会被强制转换成一个通用的地址结构体 sockaddr:
 struct sockaddr                                          
 {
      uint8_t               sa_len;
      unsigned short int sa_family;  /* address family: AF_xxx */
      unsigned char sa_data[14];   /* variable-length address */
 };

对于开发人员说,通用套接字地址唯一的作用就是对指向特定于协议的套接字地址结构的指针执行类型强制转换。

  1. IPv4 套接字地址结构
    IPv4 套接字地质结构通常也称为“网际套接字地质结构”,它以 sockaddr_in 命名,定义在 <netinet/in.h> 头文件中。
    路径: /usr/include/netinet/in.h
     /* Internet address.  */
typedef uint32_t in_addr_t;
struct in_addr
 {
   in_addr_t s_addr;   /* 32-bit IPv4 address */
                               /* network byte ordered */   
 };   
/* Structure describing an Internet socket address.  */
struct sockaddr_in
  {
   
    uint8_t    sin_len;    /* length of structure (16) */
    sa_family_t    sin_family;     /* AF_INET */
    in_port_t sin_port;         /* Port number.  */
    struct in_addr sin_addr;        /* Internet address.  */

    /* Pad to size of `struct sockaddr'.  */
   unsigned char sin_zero[8];
             
  };                                         
  • 对套接字地址结构体的说明:
    1)长度字段 sin_len 是为了增加对 OSI 协议的支持而添加的。它是后来被更新之后的,本来第一个字段是 sin_family,它是一个无符号短整数(unsigned short)。并不是所有的内核都会有的字段,而且 POSIX 规范也不要求有这个成员。
    (2)即使有长度字段,我们也无须设置和检查它,除非设计路由套接字。
    (3)POSIX 规范只需要这个结构中3个字段:sin_family, sin_addr 和 sin_port。对于额外的结构字段也是可以接受的,几乎所有的实现都添加了 sin_zero 字段,用来填充这个结构。所以所有的套接字地质结构大小至少16字节。

    (4)IPv4 地址和 TCP 或 UDP 端口号在套接字地址结构中总是以网络字节序来存储的。在使用这些字段时候,必须要严格按照这个要求来。
    (5)sin_zero 字段未曾使用,不过在填写这种套接字地址结构时,我们总是把该字段置为0。
    (6)套接字地址结构仅在给定主机上使用:虽然结构中的某些字段用在不同主机之间的通信中,但是结构本身并不在主机之间传递。

    1. IPv6 套接字地址结构(不在详细赘述)
535 /* IPv6 packet information.  */
536 struct in6_pktinfo
537   {
538     struct in6_addr ipi6_addr;  /* src/dst IPv6 address */ 
539     unsigned int ipi6_ifindex;  /* send/recv interface index */
540   };

套接字地址结构的比较

在这里插入图片描述

字节排序函数

由于 IP 地址和 TCP 或 UDP 端口在网络传输中均要使用网络字节序,那么如果我们的主机字节序和网络字节序不同时就要转换。
俩种字节序的转换函数:

#include <netinet/in.h>

uint16_t htons(uint16_t host16bitvalue);

uint32_t htonl(uint32_t host32bitvalue);
                                    均返回:网络字节序的值
uint16_t ntohs(uint16_t net16bitvalue);

uint32_t ntohl(uint16_t net32bitvalue);
                                    均返回:主机字节序的值

说明:
h 代表 host, n 代表 network, s 代表 short, l 代表 long。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值