首页 > 其他分享 >socket地址API

socket地址API

时间:2024-02-06 19:34:11浏览次数:24  
标签:__ addr ip 地址 API 字节 inet socket

目录


主机字节序和网络字节序

在 Linux 系统中,主机字节序(Host Byte Order)和网络字节序(Network Byte Order)是两个重要的概念。

  • 主机字节序是指 CPU 直接处理数据时使用的字节序。在 x86 架构的 Linux 系统中,主机字节序通常是小端字节序(Little Endian),即最低有效字节(Least Significant Byte)位于最低内存地址。
  • 网络字节序是指在网络通信中使用的字节序。在 TCP/IP 协议中,网络字节序通常是大端字节序(Big Endian),即最高有效字节(Most Significant Byte)位于最低内存地址。

在进行网络编程时,经常需要在主机字节序和网络字节序之间进行转换。例如,在发送数据时,需要将主机字节序转换为网络字节序;在接收数据时,需要将网络字节序转换为主机字节序。
在 Linux 系统中,可以使用htonl()htons()ntohl()ntohs()等函数进行字节序转换。这些函数的命名规则如下:

  • h表示主机(Host)。
  • n表示网络(Network)。
  • l表示长整型(Long)。
  • s表示短整型(Short)。

例如,htonl()函数将一个 32 位的整数从主机字节序转换为网络字节序,ntohl()函数将一个 32 位的整数从网络字节序转换为主机字节序。

下面是一个简单的示例,展示了如何在 Linux 中进行字节序转换:

#include <iostream>
#include <arpa/inet.h>

int main() {
    // 定义一个32位整数
    uint32_t host = 0x12345678;

    // 将主机字节序转换为网络字节序
    uint32_t network = htonl(host);

    // 将网络字节序转换为主机字节序
    uint32_t host2 = ntohl(network);

    // 打印结果
    std::cout << "主机字节序:" << std::hex << host << std::endl;
    std::cout << "网络字节序:" << std::hex << network << std::endl;
    std::cout << "转换后的主机字节序:" << std::hex << host2 << std::endl;

    return 0;
}

在上面的示例中,我们定义了一个 32 位的整数host整数,然后使用htonl()函数将其转换为网络字节序,并使用ntohl()函数将其转换回主机字节序。最后,我们打印出转换前后的结果。

判断机器字节序

#include <iostream>
#include <endian.h>

// 判断机器字节序函数
bool isLittleEndian() {
    return __BYTE_ORDER__ == LITTLE_ENDIAN;
}

void isLittleEndian02() {
    union {
        short value;
        char union_bytes[sizeof(short)];
    } test;
    test.value = 0x0102;
    if (test.union_bytes[0] == 1 && test.union_bytes[1] == 2) {
        std::cout << "这台机器是大端字节序(big endian)" << std::endl;
    } else if (test.union_bytes[0] == 2 && test.union_bytes[1] == 1) {
        std::cout << "这台机器是小端字节序(little endian)" << std::endl;
    } else {
        std::cout << "unknown..." << std::endl;
    }
}

int main() {
    if (isLittleEndian()) {
        std::cout << "这台机器是小端字节序(little endian)" << std::endl;
    } else {
        std::cout << "这台机器是大端字节序(big endian)" << std::endl;
    }

    isLittleEndian02();

    return 0;
}

/*
这台机器是小端字节序(little endian)
这台机器是小端字节序(little endian)
*/

函数isLittleEndian(),它使用__BYTE_ORDER__和__LITTLE_ENDIAN__宏来判断机器的字节序。如果__BYTE_ORDER__等于__LITTLE_ENDIAN__,则说明机器是小端字节序;否则,机器是大端字节序。

函数isLittleEndian02(),在这个代码中,使用了一个union(联合体)来同时访问一个 16 位整数的不同字节。在这个union中,value成员是一个 16 位整数,而union_bytes成员是一个字符数组,长度为sizeof(short),即 2。
首先,将 0x0102 赋值给value成员。然后,检查union_bytes成员中的第一个和第二个字节的值。如果第一个字节的值为 1,第二个字节的值为 2,那么这台机器是大端字节序;如果第一个字节的值为 2,第二个字节的值为 1,那么这台机器是小端字节序;否则,字节序是未知的。


通用socket地址

在 Linux 中,sockaddr结构体用于表示网络套接字的地址信息。它是一个通用的数据结构,用于指定套接字连接的源或目标地址。

以下是sockaddr结构体的定义:

struct sockaddr {
    sa_family_t sa_family; /* 地址家族 */
    char sa_data[14]; /* 协议地址 */
};

其中,sa_family_t sa_family字段表示地址家族,它指定了使用的网络协议族(如 IPv4、IPv6 等)。char sa_data[14]字段是一个字符数组,用于存储具体的协议地址。


专用socket地址

对于不同的地址家族,sockaddr结构体可能会有不同的扩展结构体。例如,对于 IPv4 地址,使用struct sockaddr_in结构体;对于 IPv6 地址,使用struct sockaddr_in6结构体。这些扩展结构体包含了更详细的地址信息。

以下是 unix 本地域协议族的struct sockaddr_un结构体的定义:

#include <sys/un.h>
// unix本地域协议族
struct sockaddr_un {
    sa_family_t sin_family;     /* 地址族:AF_UNIX */
    char sun_path[108];         /* 文件路径名 */
};

以下是 IPv4 地址的struct sockaddr_in结构体的定义:

#include </usr/include/netinet/in.h>
// ipv4专用结构体
struct sockaddr_in {
    sa_family_t sin_family;     /* 地址族:AF_INET */
    u_int16_t sin_port;         /* 端口号,要用网络字节序表示 */
    struct in_addr sin_addr;    /* ipv4地址结构体,见下面 */
};
/* Internet address.  */
typedef uint32_t in_addr_t;
struct in_addr {
    in_addr_t s_addr;           /* ipv4地址,要用网络字节序表示 */
};

其中,sin_family字段仍然表示地址家族,sin_port字段表示端口号,sin_addr字段表示 IPv4 地址。

以下是 IPv6 地址的struct sockaddr_in6结构体的定义:

#include </usr/include/netinet/in.h>
// ipv6专用结构体
struct sockaddr_in6 {
    sa_family_t sin_family;     /* 地址族:AF_INET6 */
    u_int16_t sin6_port;        /* 端口号,要用网络字节序表示 */
    u_int32_t sin6_flowinfo;    /* 流信息,应设置为0 */
    struct in6_addr sin6_addr;  /* ipv6地址结构体,见下面 */
    u_int32_t sin6_scope_id;    /* scpoe ID,尚处于实验阶段*/
};

#if !__USE_KERNEL_IPV6_DEFS
/* IPv6 address */
struct in6_addr
  {
    union
      {
	uint8_t	__u6_addr8[16];
	uint16_t __u6_addr16[8];
	uint32_t __u6_addr32[4];
      } __in6_u;
#define s6_addr			__in6_u.__u6_addr8
#ifdef __USE_MISC
# define s6_addr16		__in6_u.__u6_addr16
# define s6_addr32		__in6_u.__u6_addr32
#endif
  };
#endif /* !__USE_KERNEL_IPV6_DEFS */

这段代码定义了用于IPv6的两个结构体:sockaddr_in6in6_addr。以下是它们的具体说明:

  1. sockaddr_in6 结构体:

    • sa_family_t sin_family: 这是一个表示地址族的数据类型。对于IPv6地址,这个字段的值应该是AF_INET6
    • u_int16_t sin6_port: 这是一个16位的无符号整数,表示端口号。注意,这个值通常应该使用网络字节序,而不是主机字节序。
    • u_int32_t sin6_flowinfo: 这是一个32位的无符号整数,用于表示IPv6流标签。在大多数情况下,这个字段的值应该设置为0。
    • struct in6_addr sin6_addr: 这是一个in6_addr结构体,用于表示IPv6地址。
    • u_int32_t sin6_scope_id: 这是一个32位的无符号整数,用于表示作用域ID。这个字段在一些特殊的网络环境中使用,比如多点传送地址。需要注意的是,这个字段在某些系统或库中可能还处于实验阶段。
  2. in6_addr 结构体:

这个结构体表示一个IPv6地址,由16个字节组成。为了方便访问这些字节,它提供了一个联合(union),使得可以通过多种方式访问这16个字节:

* `__u6_addr8[16]`: 这是一个包含16个元素的数组,每个元素是一个8位的无符号整数。通过这个数组,可以直接访问IPv6地址中的每一个字节。
* `__u6_addr16[8]`: 这是一个包含8个元素的数组,每个元素是一个16位的无符号整数。通过这个数组,可以按16位为一组访问IPv6地址。
* `__u6_addr32[4]`: 这是一个包含4个元素的数组,每个元素是一个32位的无符号整数。通过这个数组,可以按32位为一组访问IPv6地址。

此外,这个结构体还定义了一些宏,用于简化对这些字段的访问:

* `s6_addr`: 这是一个宏,用于访问`__u6_addr8`数组。
* `s6_addr16`: 这是一个宏,用于访问`__u6_addr16`数组。需要注意的是,这个宏在`__USE_MISC`被定义时才可用。
* `s6_addr32`: 这是一个宏,用于访问`__u6_addr32`数组。同样,这个宏也在`__USE_MISC`被定义时才可用。

注意:__USE_KERNEL_IPV6_DEFS__USE_MISC是预处理器宏,它们可能在不同的系统或编译环境中有不同的定义。这些宏通常用于控制哪些代码片段被包含或排除在编译过程中。


ip地址转换函数


在Linux下,如果你想要进行IP地址的转换,通常涉及的操作包括点分十进制(dotted-decimal)表示法和整数表示法之间的转换,或者进行网络地址和主机地址的计算等。这里提供一些常见的转换方法。

  1. 点分十进制到整数的转换:
    你可以使用标准的库函数,如inet_atoninet_ntoa,但这些函数主要用于IPv4地址。对于IPv6地址,你需要使用inet_ptoninet_ntop

    • inet_aton: 将点分十进制的IPv4地址转换为网络字节序的整数形式。
    • inet_ntoa: 将网络字节序的整数形式转换为点分十进制的IPv4地址。
    • inet_pton: 将点分十进制(IPv4)或冒号分隔的十六进制(IPv6)转换为二进制格式。
    • inet_ntop: 将二进制格式转换为点分十进制(IPv4)或冒号分隔的十六进制(IPv6)。
/* Convert from presentation format of an Internet number in buffer
   starting at CP to the binary network format and store result for
   interface type AF in buffer starting at BUF.  */
extern int inet_pton (int __af, const char *__restrict __cp,
		      void *__restrict __buf) __THROW;

/* Convert a Internet address in binary network format for interface
   type AF in buffer starting at CP to presentation form and place
   result in buffer of length LEN astarting at BUF.  */
extern const char *inet_ntop (int __af, const void *__restrict __cp,
			      char *__restrict __buf, socklen_t __len)
     __THROW;

示例代码(使用inet_ptoninet_ntop):

#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>

int main() {
    char ip_str[] = "192.0.2.1";
    struct in_addr ip_addr;

    // 点分十进制到整数(网络字节序的整数形式)的转换
    if (inet_pton(AF_INET, ip_str, &ip_addr) != 1) {
        perror("inet_pton");
        return 1;
    }
    printf("%x\n", ip_addr.s_addr);

    // 整数(网络字节序的整数形式)到点分十进制的转换
    char buffer[INET_ADDRSTRLEN];
    if (inet_ntop(AF_INET, &ip_addr, buffer, sizeof(buffer)) == NULL) {
        perror("inet_ntop");
        return 1;
    }
    printf("%s\n", buffer);

    return 0;
}

/*
10200c0
192.0.2.1
*/
  1. 自定义函数进行转换:
    如果你想要手动进行转换,而不使用库函数,你可以编写自己的函数来处理字符串和数字之间的转换。

例如,一个简单的点分十进制到整数的转换函数可以这样写:

#include <stdint.h>
#include <stdio.h>

uint32_t ip_string_to_int(const char *ip) {
    uint32_t result = 0;
    char *end;
    for (int i = 0; i < 4; ++i) {
        result <<= 8;
        unsigned long part = strtoul(ip, &end, 10);
        if (end == ip || part > 255) {
            return 0; // 无效IP
        }
        result |= part;
        ip = end + 1;
    }
    return result;
}

int main() {
    const char *ip_str = "192.0.2.1";
    uint32_t ip_int = ip_string_to_int(ip_str);
    printf("IP as integer: %u\n", ip_int);
    return 0;
}

标签:__,addr,ip,地址,API,字节,inet,socket
From: https://www.cnblogs.com/yubo-guan/p/18010217

相关文章

  • 探索Web API SpeechSynthesis:给你的网页增添声音
    WebAPISpeechSynthesis是一项强大的浏览器功能,它允许开发者将文本转换为语音,并通过浏览器播放出来。本文将深入探讨SpeechSynthesis的控制接口,包括其功能、用法和一个完整的JavaScript示例。参考资料:SpeechSynthesis-WebAPI接口参考|MDN(mozilla.org)文本语音互......
  • 技能 | 如何申请谷歌地图API密钥
    CloudAce云一是GoogleCloud全球战略合作伙伴,在亚太地区、欧洲、美洲和非洲拥有二十多个办公室。CloudAce在谷歌专业领域认证及专业知识目前排名全球第一位,并连续多次获得GoogleCloud各类奖项。作为谷歌云托管服务商,提供谷歌云、谷歌地图、谷歌办公套件、谷歌云认证培训等......
  • 【OpenVINO™】在 MacOS 上使用 OpenVINO™ C# API 部署 Yolov5
    在MacOS上使用OpenVINO™C#API部署Yolov5项目介绍YOLOv5是革命性的"单阶段"对象检测模型的第五次迭代,旨在实时提供高速、高精度的结果,是世界上最受欢迎的视觉人工智能模型,代表了Ultralytics对未来视觉人工智能方法的开源研究,融合了数千小时研发中......
  • 技能 | 如何申请谷歌地图API密钥
    CloudAce 是GoogleCloud全球战略合作伙伴,在亚太地区、欧洲、美洲和非洲拥有二十多个办公室。CloudAce在谷歌专业领域认证及专业知识目前排名全球第一位,并连续多次获得GoogleCloud各类奖项。作为谷歌云托管服务商,提供谷歌云、谷歌地图、谷歌办公套件、谷歌云认证培训等服......
  • Gateway API 实践之(九)FSM Gateway 的双向 TLS
    FSMGateway流量管理策略系列:故障注入黑白名单访问控制限速重试会话保持健康检查负载均衡算法TLS上游双向TLS网关开启mTLS(双向TLS验证)的功能是一种高级安全措施,它不仅要求服务器向客户端证明其身份,同样要求客户端提供证书以证实其身份。这种双向验证极大地增强了通信的安全性......
  • fastapi基础
    一些fastApi的基础运行命令:uvicornmain:app--reload查看接口文档【swagger-ui】:http://127.0.0.1:8000/docs路径后面加/docs......
  • 淘宝/天猫商品详情API:返回值参数详解及商业逻辑实现
    在电子商务的高速发展过程中,API接口扮演了至关重要的角色。对于淘宝和天猫这样的大型电商平台,商品详情API是商家与消费者信息沟通的桥梁。本文将深入探讨这一API的返回值参数,并展示如何通过编程利用这些数据实现商业逻辑。一、商品详情API的核心作用商品详情页是电商体验中的重要环......
  • WebSocket 协议 message, ping , Pong, 消息
    以前一直不明白,WebSocket 已经有了message回调函数,可以接收任何的消息,按理说,ping和pong也只是  message 众多消息类型中的两个消息特里,直到看到 <<WebSocket协议 >>的定义,才明白,为什么了 一、数据帧(DataFraming)WebSocket协议中,数据是通过数据帧来传递的,协议......
  • WINAPI 线程创建简单测试
    #include"Windows.h"#include<stdlib.h>#include<stdio.h>DWORDWINAPIThreadFunc(LPVOIDparam){printf("启动线程\n");return0;}intmain(){DWORDthreadID=0;HANDLEthreadObj=NULL;threadObj=......
  • IP地址揭秘:他们能否通过IP地址找到我家?
    从去年开始,各大互联网平台陆续显示用户IP属地,而用户方则无法选择开启或关闭这一功能。最先被发现的,是不少认证为“本地资讯博主”和“海外资讯博主”的账号,IP属地与资料地址并不吻合。一些人支持平台强制在前台显示用户IP属地,他们认为有人会因此收敛,至少无法假装在某地,假冒他......