Linux网络编程套接字地址结构和字节操作函数

本文涉及的产品
公网NAT网关,每月750个小时 15CU
简介: Linux网络编程套接字地址结构和字节操作函数

前言

本篇文章将给大家介绍套接字地址结构和字节操作函数的使用。


一、IPV4套接字地址结构

IPV4套接字地址结构通常也称为"网际套接字地址结构"它以sockaddr_in命名。定义在头文件中。


sin_family:表示协议族,一般为AF_INET。

sin_port:表示端口号,需要以网络字节序存储,通常使用htons()函数进行转换。

sin_addr:表示IP地址,类型为in_addr结构体指针,也需要以网络字节序存储。可以使用inet_aton()或inet_addr()函数进行转换,或者手动设置。

sin_zero:用于填充,保证长度为sockaddr的长度。

/* Structure describing an Internet socket address.  */
struct sockaddr_in
  {
    __SOCKADDR_COMMON (sin_);
    in_port_t sin_port;     /* Port number.  */
    struct in_addr sin_addr;    /* Internet address.  */
    /* Pad to size of `struct sockaddr'.  */
    unsigned char sin_zero[sizeof (struct sockaddr) -
         __SOCKADDR_COMMON_SIZE -
         sizeof (in_port_t) -
         sizeof (struct in_addr)];
  };

前面的客户端和服务端编程我们都对这个结构体进行设置。这里我们详细讲解一下客户端和服务端是如何设置这个结构体的参数的。


客户端:

sin_family设置为AF_INET代表使用的是IPV4协议。

sin_port代表端口号这里设置为了8888

sin_addr代表客户端要连接服务端的IP地址

servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(8888);
if(inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0)
{
    printf("inet_pton is err\n");
}

服务端:

服务端和客户端最大的区别就是在s_addr 的设置上。

INADDR_ANY是一个常量,它的值是0,定义在头文件中。它的作用是让套接字可以监听任意IP地址,这通常在多网卡机器或者服务端需要监听多个网络接口时使用。

 saddr.sin_family = AF_INET;
 saddr.sin_addr.s_addr = htonl(INADDR_ANY);
 saddr.sin_port = htons(8888);

二、通用套接字地址结构

套接字通用地址结构通常用于存储网络地址和端口号等信息,它的定义如下:

struct sockaddr {
    unsigned short sa_family; // 地址族(Address Family)
    char sa_data[14];         // 可变长度的地址数据
};

看到之前的编写的程序是如何使用到这个通用套接字地址结构的:

bind(server, (struct sockaddr*)&saddr, sizeof(saddr))

这个saddr我们在编写代码的时候是使用的IPV4的地址结构。在使用bind函数时第二个参数需要指定为套用套接字地址结构,所以这里需要进行一个强制类型转换。

将IPV4套接字地址结构改变为套用套接字地址结构。


为什么要把IPV4地址结构转换为通用套接字地址结构呢?


因为 BSD socket API 可以同时支持 IPv4 和 IPv6 网络协议族,而这些网络协议族的地址结构可能不同。所以需要用 struct sockaddr 结构体体现通用性,便于能够适配多个协议族的网络地址结构。


三、字节操作函数

1.网络字节序主机字节序转换函数

htons和htonl都是指网络字节序和主机字节序之间的转换函数。在计算机网络中,网络字节序是一种通用的数据表示形式,它用于在互联网上传输数据。不同的计算机体系结构使用不同的字节序,即大端字节序和小端字节序。网络字节序是一种统一的字节序,它与主机字节序不同。因此,在发送和接收网络数据时,必须将数据从主机字节序转换为网络字节序,并在接收数据时将其转换回主机字节序。htons和htonl是用于这种转换的函数。


htons和htonl都是位于arpa/inet.h头文件中的函数。htons函数的作用是将主机字节序的16位整数转换为网络字节序的16位整数。htonl函数的作用是将主机字节序的32位整数转换为网络字节序的32位整数。


代码的使用:

这里是将8888这个端口号从主机字节序转换为了网络字节序。

servaddr.sin_port = htons(8888);

2.地址转换函数

我们熟知的地址一般是以字符串的形式出现的例如:“206.168.112.96”

但是在网络中进行通信时需要把字符串形式的IP地址转换为二进制类型的地址。

将字符串地址转换成二进制地址是为了在网络中让设备能够准确识别和处理数据包,从而实现正确的数据传输。


1.inet_aton、inet_addr、inet_ntoa函数

在man手册中都可以查看到这些函数的具体用法。

inet_aton:

int inet_aton(const char *cp, struct in_addr *inp);

inet_aton函数将一个点分十进制的IP地址转换成一个32位的整数,并将结果存储在指向结构体in_addr的指针中。其操作非常简单,直接输入一个字符串形式的IP地址,指定一个in_addr结构体类型的指针,即可完成ip字符串转整数的转换,如果转换成功则返回非零值(1),否则返回 0。

inet_addr

in_addr_t inet_addr(const char *cp);

inet_addr函数与inet_aton函数类似,同样是把以点分十进制表示的字符串IP地址转换成32位的网络字节序整数。它的返回值是一个in_addr_t类型的整数,若调用失败则返回-1。

inet_ntoa

char *inet_ntoa(struct in_addr in)

inet_ntoa函数则将一个32位二进制整数转换成一个点分十进制IP地址的字符串。其传入一个in_addr结构体类型的数据,即可得到相应的IP字符串,如果转换成功,则返回表示该字符串IP地址的指针,否则返回 NULL。需要注意的是,由于inet_ntoa函数的返回值是一个指向静态存储区的指针,所以多次调用该函数时需要在调用存储之间将其复制到一个缓冲区中。


2.inet_pton、inet_ntop函数

这两个函数是随着IPV6的出现而出现的函数。在IPV4和IPV6都是适用的。


inet_pton:

int inet_pton(int af, const char *src, void *dst);

inet_pton函数用于将IPv4或IPv6地址字符串转换为网络字节序的二进制格式。

其中,af表示地址族(AF_INET代表IPv4地址族,AF_INET6代表IPv6地址族),src是一个字符串,表示待转换的IP地址,dst是一个指向存储转换后结果的内存单元的指针。


inet_ntop:

const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);

inet_ntop函数则用于将网络字节序的IPv4或IPv6地址转换为可读的地址字符串。

其中,af表示地址族(AF_INET代表IPv4地址族,AF_INET6代表IPv6地址族),src是指向网络字节序的二进制形式的地址的结构体指针,dst是存储转换后结果的缓冲区指针,size表示缓冲区大小。


4.编程实验

这里我们只使用inet_pton和inet_ntop这两个函数进行实验。其他的函数大家可以自己去尝试。


代码:

#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
#define INET_ADDRSTRLEN 100
int main() {
    struct in_addr addr;
    char ip_str[INET_ADDRSTRLEN];
    // 将IP地址从字符串转换为二进制形式
    if (inet_pton(AF_INET, "192.168.1.1", &addr) != 1) {
        printf("inet_pton");
    }
    // 将二进制形式的IP地址转换为字符串
    const char *ret = inet_ntop(AF_INET, &addr, ip_str, INET_ADDRSTRLEN);
    if (ret == NULL) {
        printf("inet_ntop");
    }
    printf("IPv4 address: %s\n", ip_str);
    return 0;
}

上述代码中,inet_pton函数将IPv4地址从字符串转换为二进制形式,inet_ntop函数将二进制形式的IP地址转换为字符串,并将结果存储在ip_str数组中。其中,INET_ADDRSTRLEN是一个宏定义,表示IPv4地址字符串的最大长度。如果转换失败,inet_pton或inet_ntop函数会返回-1,并设置errno值。


总结

本篇文章主要介绍了通用套接字地址结构和IPV4套接字地址结构,以及字节操作函数的使用。


相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
相关文章
|
5天前
|
机器学习/深度学习 算法
神经网络的结构与功能
神经网络是一种广泛应用于机器学习和深度学习的模型,旨在模拟人类大脑的信息处理方式。它们由多层不同类型的节点或“神经元”组成,每层都有特定的功能和责任。
14 0
|
17天前
|
监控 Linux 测试技术
Linux系统命令与网络,磁盘和日志监控总结
Linux系统命令与网络,磁盘和日志监控总结
40 0
|
17天前
|
监控 Linux 测试技术
Linux系统命令与网络,磁盘和日志监控三
Linux系统命令与网络,磁盘和日志监控三
33 0
|
1月前
|
编解码 人工智能 文件存储
卷积神经网络架构:EfficientNet结构的特点
EfficientNet是一种高效的卷积神经网络架构,它通过系统化的方法来提升模型的性能和效率。
37 1
|
2月前
|
存储 Linux Shell
在Linux中,如何使用脚本,实现判断 192.168.1.0/24 网络里,当前在线的 IP 有哪些?能ping 通则 认为在线。
在Linux中,如何使用脚本,实现判断 192.168.1.0/24 网络里,当前在线的 IP 有哪些?能ping 通则 认为在线。
|
2月前
|
存储 Linux 网络安全
【Azure 存储服务】如何把开启NFS 3.0协议的Azure Blob挂载在Linux VM中呢?(NFS: Network File System 网络文件系统)
【Azure 存储服务】如何把开启NFS 3.0协议的Azure Blob挂载在Linux VM中呢?(NFS: Network File System 网络文件系统)
|
2月前
|
存储 Linux 网络安全
【Azure 应用服务】App Service For Linux 如何在 Web 应用实例上住抓取网络日志
【Azure 应用服务】App Service For Linux 如何在 Web 应用实例上住抓取网络日志
|
2月前
|
网络协议 Linux Shell
【Azure 应用服务】App Service For Linux 中安装paping, 用于验证从App Service向外请求的网络连通性
【Azure 应用服务】App Service For Linux 中安装paping, 用于验证从App Service向外请求的网络连通性
|
网络协议 Linux C语言
linux下CC++网络编程基本:socket实现tcp和udp的例子
linux下CC++网络编程基本:socket实现tcp和udp的例子
226 0
|
5月前
|
存储 网络协议 算法
【探索Linux】P.28(网络编程套接字 —— 简单的UDP网络程序模拟实现)
【探索Linux】P.28(网络编程套接字 —— 简单的UDP网络程序模拟实现)
48 0