漫话linux:sockaddr

1.Socket API

它是一层网络编程接口,抽象了底层的网络协议,定义在netinet/in.h中,适用于多种网络通信方式,如IPV4,IPV6以及UNIX域套接字(用于本地进程间通信),通过Socket API程序可以实现跨网络的进程间通信(如通过IP地址和端口号进行的网络通信),也可以实现本地的进程通信

常见API(感知)

// 创建 socket 文件描述符 (TCP/UDP, 客户端 + 服务器)
int socket(int domain, int type, int protocol);
 
// 绑定端口号 (TCP/UDP, 服务器) 
int bind(int socket, const struct sockaddr *address, socklen_t address_len);
 
// 开始监听socket (TCP, 服务器)
int listen(int socket, int backlog);
 
// 接收请求 (TCP, 服务器)
int accept(int socket, struct sockaddr* address,socklen_t* address_len);
 
// 建立连接 (TCP, 客户端)
int connect(int sockfd, const struct sockaddr *addr,
 socklen_t addrlen);
2.sockaddr结构

网络通信的套接字的种类很多,常见的有三种

1.unix域间套接字编程(同一个机器内)

2.原始套接字编程(网络工具)

3.网络套接字编程(用户间的网络通信)

设计者想将网络接口统一抽象化(参数类型必须统一),底层是一种多态的设计

运用场景:

1.网络套接字:运用于网络跨主机之间通信+本地通信

2.unix域间套接字:本地通信

3.原始套接字:跳过传输层访问其他层协议的有效数据,主要用于抓包或者侦测网络,现在在使用网络编程通信时是应用层调传输层的接口,而原始套接字不属于这一类

表面上是三种,其实就是参数不同的三个多态类,其他网络问题也可以将套接字改变参数进行处理

跨网络或本地通信方式有不同地址格式,套接字使用不同的结构体来封装地址信息

sockaddr_in:用于跨网络通信(例如通过IP和端口号进行通信)

sockaddr_un:用于本地通信(通过文件路径进行通信)

为了解决这些不同地址格式的兼容性问题,套接字提供了一个通用的地址结构体sockaddr,用于统一处理不同的地址结构

3.sockaddr,sockaddr_in和sockaddr_un的关系

sockaddr是一个通用的套接字地址结构,它为所有不同类型的通信方式提供了统一的接口。具体通信时sockaddr实际上指向特点的地址结构如(sockaddr_in和sockaddr_un),然后通过强制类型转换来区分通信方式,这种设计类似于对象编程的多态,sockaddr可以看作父类,而sockaddr_in和sockarr_un可以看作子类,在程序中套接字函数接受sockaddr*类型的参数,然后根据具体的通信信息进行处理

sockaddr结构体

struct sockaddr {
    __SOCKADDR_COMMON(sa_); /* 公共数据:地址家族和长度 */
    char sa_data[14];       /* 地址数据 */
};

sockaddr_in结构体(IPV4套接字地址)

struct sockaddr_in {
    __SOCKADDR_COMMON(sin_);
    in_port_t sin_port;      /* 端口号 */
    struct in_addr sin_addr; /* IP地址 */
    unsigned char sin_zero[sizeof(struct sockaddr) - 
                           __SOCKADDR_COMMON_SIZE - 
                           sizeof(in_port_t) - 
                           sizeof(struct in_addr)];
};

sockaddr_un结构体(Unix域套接字地址)

struct sockaddr_un {
    __SOCKADDR_COMMON(sun_);
    char sun_path[108]; /* 文件路径 */
};
4.sockaddr通用结构的意义

sockaddr作为通用结构,它的前16个比特位用于存储协议家族(sa_family字段),这个字段用于表明是那种通信方式

AF_INET:IPV4网络通信

AF_INET6:IPV6网络通信

AF_UNIX:本地通信(UNIX域套接字)

通过这种设计,Socket API可以通过统一的函数接口,处理不同类型的地址格式,开发者只需要将具体地址结构转换为sockaddr,并设置协议家族字段,套接字函数能识别出应该进行那种通信

5.通用性带来的优势

Socket API的这种设计带来了极大的通用性,使得开发者在同一套代码中处理不同的协议类型,比如函数sendto()或recvfrom()可以接受sockaddr*作为参数,无论是处理IPV4,IPV6还是UNIX Domacin Socket,代码都不需要做出太大改动

int sendto(int sockfd, const void *msg, size_t len, int flags,
           const struct sockaddr *dest_addr, socklen_t addrlen);

在这个函数中,dest_addr是一个通用的sockaddr*,程序只需根据实际使用的通信方式(如IPV4或IPV6)并对其进行强转类型转换即可

6.IPV4域IPV6的地址表示

IPV4地址格式:使用sockaddr_in结构体,地址类型是AF_INET,端口号和IP地址需要转换为网络字节序也就是大端序

IPV6地址格式:使用sockaddr_in6结构体,地址类型是AF_INET6

7.代码示例

in_addr结构体(用于表示IPV4地址)

typedef uint32_t in_addr_t;
struct in_addr {
    in_addr_t s_addr; // 32位IP地址
};

in_addr是一个32位的整数,用来表示IPV4的IP地址,通信过程中,IP地址通常是通过字符串格式如(122.51.179.128)转换为in_addr_t类型的数值来表示

8.总结

通过sockaddr结构体,Socket API实现了网络通信和本地通信的统一接口,它的设计理论类似于多态,即通过一个通用的接口来处理多种类型的地址格式

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值