Linux 之 【网络套接字编程】(网络字节序、字节序转换函数、套接字编程类型、标准套接字编程的头文件、sockaddr结构、整数IP与字符串IP的转换)

Linux 之 【网络套接字编程】(网络字节序、字节序转换函数、套接字编程类型、标准套接字编程的头文件、sockaddr结构、整数IP与字符串IP的转换)

目录

一、网络字节序

定义

字节序转换函数

概览

命名规律

htons

htonl

ntohl

ntohs

二、套接字编程的类型

域间套接字:同一机器内的进程间通信

原始套接字:直接操作网络层及以下的数据包

网络套接字:跨网络的用户间通信

三、标准套接字编程的头文件

四、sockaddr结构

核心设计思想:通用接口与具体实现

通用地址结构:struct sockaddr

IPv4 专用地址结构:struct sockaddr_in

bzero

IPv4 地址封装:struct in_addr

整数IP<--->字符串IP

inet_addr

inet_pton

inet_ntoa

inet_ntop

结构体关系与强制转换示例


一、网络字节序

定义

TCP/IP协议强制规定,网络上传输的数据流必须使用大端字节序(低地址存放高位字节)
通俗理解:像我们写数字一样,左边(低地址)是高位,右边(高地址)是低位。例如 0x12345678,先发 0x12,最后发 0x78。
  • 统一原因
互联网由不同架构的机器组成(x86是小端,PowerPC/某些网络设备是大端)

网络传输严格遵循从低地址到高地址的顺序发送和接收:发送端将数据在内存中从低地址字节开始依次发出,接收端按收到顺序依次存入本地的低地址到高地址。这意味着网络上的字节流顺序完全取决于发送端的内存布局——小端机发送时先发低位字节,大端机先发高位字节。接收端则原样按序存入内存,最终解释出的数值由本机字节序决定。这就是为什么直接发送会导致跨平台错误,而使用htons/ntohs统一转换为网络字节序(大端)发送,能保证无论发送端是什么机器,网络上的字节流都是“高位在前”的标准顺序,接收端再根据自身字节序正确还原
机器类型内存表示 (低→高)发送顺序网络字节流大端机接收解释小端机接收解释
小端机发78 56 34 1278→56→34→1278 56 34 120x78563412 ❌0x12345678 ✅
大端机发12 34 56 7812→34→56→7812 34 56 780x12345678 ✅0x78563412 ❌
  • 发送端(编码)
通过将数据从主机字节序转换为网络字节序,保证线上的数据流符合 TCP/IP 标准

如果是大端机:不需要转(或者说转了也不变)

如果是小端机:必须翻转字节顺序
  • 接收端(解码)
通过将数据从网络字节序转换回主机字节序,保证本地CPU能够读取到正确的数据

如果是大端机:不需要转

如果是小端机:必须翻转字节顺序

字节序转换函数

概览

函数名全称功能应用场景
htonlHost to Network Long主机序 → 网络序 (32位)发送IP地址前转换
htonsHost to Network Short主机序 → 网络序 (16位)发送端口号前转换
ntohlNetwork to Host Long网络序 → 主机序 (32位)收到IP地址后转换
ntohsNetwork to Host Short网络序 → 主机序 (16位)收到端口号后转换
如果主机是大端:函数直接返回原值(空操作,效率高)

如果主机是小端:函数进行字节翻转(Bit Flip)后返回

命名规律

h = Host(主机字节序)

n = Network(网络字节序)

l = Long(32位整数,如IP地址)

s = Short(16位整数,如端口号)

to = 转换方向

htons

项目说明
函数名htons
全称Host to Network Short
原型uint16_t htons(uint16_t hostshort);
参数hostshort:待转换的16位主机字节序整数
返回值转换后的16位网络字节序整数
头文件<arpa/inet.h>
功能将16位整数从主机字节序转换为网络字节序
应用场景发送端口号前转换

htonl

项目说明
函数名htonl
全称Host to Network Long
原型uint32_t htonl(uint32_t hostlong);
参数hostlong:待转换的32位主机字节序整数
返回值转换后的32位网络字节序整数
头文件<arpa/inet.h>
功能将32位整数从主机字节序转换为网络字节序
应用场景发送IP地址前转换

ntohl

项目说明
函数名ntohl
全称Network to Host Long
原型uint32_t ntohl(uint32_t netlong);
参数netlong:待转换的32位网络字节序整数
返回值转换后的32位主机字节序整数
头文件<arpa/inet.h>
功能将32位整数从网络字节序转换回主机字节序
应用场景接收到IP地址后解析

ntohs

项目说明
函数名ntohs
全称Network to Host Short
原型uint16_t ntohs(uint16_t netshort);
参数netshort:待转换的16位网络字节序整数
返回值转换后的16位主机字节序整数
头文件<arpa/inet.h>
功能将16位整数从网络字节序转换回主机字节序
应用场景接收到端口号后解析

二、套接字编程的类型

域间套接字:同一机器内的进程间通信

项目说明
名称Unix Domain Socket (UDS) / 本地套接字
通信范围同一台主机内部
地址形式文件路径(如 /tmp/test.sock
核心优势高效:不经过网络协议栈,不进行报文封装和校验,直接在内核层面拷贝数据,比TCP本地环回(127.0.0.1)更快
典型场景Nginx与FastCGI通信、MySQL本地连接、Docker守护进程与客户端通信
编程特点用法与网络套接字类似,但地址族使用 AF_UNIX 或 AF_LOCAL

原始套接字:直接操作网络层及以下的数据包

项目说明
名称Raw Socket
通信范围跨网络(但工作在更底层)
核心能力允许程序员自己构造IP头部、ICMP头部等,绕过TCP/UDP协议栈
典型场景Ping工具(构造ICMP包)、Traceroute、Wireshark等抓包工具、网络攻击与防御工具
编程特点需要root权限,地址族使用 AF_PACKET(Linux)或 AF_INET 配合 SOCK_RAW,需要自己处理协议细节
注意事项不经过传输层,所以没有TCP的可靠性和端口概念

网络套接字:跨网络的用户间通信

项目说明
名称Network Socket / Internet Socket
通信范围不同主机之间(局域网或互联网)
地址形式IP地址 + 端口号
核心协议TCP (SOCK_STREAM) 和 UDP (SOCK_DGRAM)
典型场景浏览器访问网站、微信聊天、远程登录SSH、视频直播
编程特点地址族使用 AF_INET(IPv4)或 AF_INET6(IPv6),最常用的套接字类型

三、标准套接字编程的头文件

// 标准套接字编程包含 #include <sys/socket.h> // socket(), bind(), connect() 等 #include <netinet/in.h> // sockaddr_in, sockaddr_in6 结构体 #include <arpa/inet.h> // inet_pton(), inet_ntop() 等地址转换函数 #include <string.h> // memset() #include <unistd.h> // close()
头文件作用关键函数/结构体
<sys/socket.h>提供套接字基础APIsocket()bind()connect()listen()accept()send()recv()
<netinet/in.h>定义IPv4/IPv6地址结构struct sockaddr_in (IPv4), struct sockaddr_in6 (IPv6)
<arpa/inet.h>地址转换函数(字符串↔二进制)inet_pton() (字符串→二进制), inet_ntop() (二进制→字符串)
<string.h>内存操作(如初始化结构体)memset()memcpy()
<unistd.h>系统调用(如关闭套接字)close()

四、sockaddr结构

核心设计思想:通用接口与具体实现

Socket API 的设计者面临一个问题:如何用一套统一的函数处理不同协议的地址
  • IPv4 地址是 4 字节 + 2 字节端口
  • IPv6 地址是 16 字节 + 2 字节端口
  • Unix Domain Socket 是文件路径字符串
解决方案使用强制类型转换和地址族字段
  1. 定义一个通用的基类结构体 struct sockaddr
  2. 定义具体的派生类结构体 struct sockaddr_in (IPv4)、struct sockaddr_in6 (IPv6)
  3. 所有 API 函数都接受 struct sockaddr * 类型的指针
  4. 程序员在使用时,将具体的结构体指针强制转换为通用指针传给 API
  5. API 内部通过检查第一个字段 sa_family 来判断实际传入的是哪种结构体,并解析数据

通用地址结构:struct sockaddr

这是所有 socket 地址结构的“基类”,主要用于函数参数的类型统一
成员类型说明
sa_familysa_family_t地址族(关键字段!)。标识协议类型:
AF_INET (IPv4)
AF_INET6 (IPv6)
AF_UNIX / AF_LOCAL (Unix Domain Socket)
sa_datachar[14]地址数据。存放具体的地址信息(如IP、端口、路径等)。
注意:程序不应直接访问此数组,需通过具体结构体解析。
作用:提供统一的指针类型 struct sockaddr *,使 bind()connect() 等函数能接受任何协议的地址

IPv4 专用地址结构:struct sockaddr_in

这是 IPv4 的“派生类”,包含具体的 IPv4 地址信息。定义在头文件 <netinet/in.h> 中
成员类型说明
sin_familysa_family_t必须设为 AF_INET。对应基类的 sa_family
sin_portuint16_t16位端口号必须使用网络字节序(大端序)!
需用 htons() 函数转换。
sin_addrstruct in_addr32位 IPv4 地址必须使用网络字节序
需用 htonl() 或 inet_addr() 转换。
sin_zerochar[8]填充字段。为了保持与 struct sockaddr 大小一致而存在。
必须用 memset 或 bzero 清零,无实际意义。

关键点:

  • 在代码中我们操作的是 sockaddr_in。
  • 传给 API 时强制转换为 (struct sockaddr *)&addr。
  • 字节序:sin_port 和 sin_addr 必须是网络字节序(大端序)
  • 必须清零
对 struct sockaddr_in 清零的核心原因在于:该结构体中的 sin_zero[8] 是内核强制要求的填充字段,必须全为0;由于结构体是分配在栈上的局部变量,其内存内容为随机的垃圾数据,若不通过 memset 或初始化显式清零,这些残留数据(尤其是 sin_zero 中的随机值)会被内核读取,导致 bind() 等系统调用不可预期地失败,同时也带来非确定性行为、调试困难和潜在的安全隐患

bzero

项目说明
函数名bzero
全称Byte Zero(将字节区域清零)
头文件<strings.h> (注意:不是 <string.h>
原型void bzero(void *s, size_t n);
参数1s:指向要清零的内存区域的指针
参数2n:要清零的字节数
返回值无返回值(void
功能将指定内存区域的前 n 个字节设置为 0
起源BSD 系统引入的函数,起源于早期 Unix
标准状态废弃函数(在 POSIX.1-2001 中标记为过时,POSIX.1-2008 中已移除)

与 memset 的对比

对比维度bzeromemset
原型void bzero(void *s, size_t n);void *memset(void *s, int c, size_t n);
功能将内存区域清零将内存区域设置为指定值
参数2只填 0(固定)可填任意字节(如 0、'\0' 等)
返回值返回指向 s 的指针
头文件<strings.h><string.h>
标准废弃(legacy)ANSI C / ISO C 标准
可移植性差(非标准)好(所有平台支持)

IPv4 地址封装:struct in_addr

专门用于表示 32 位 IPv4 地址的结构体
结构体作用关键字段字节序要求
struct sockaddr通用基类(API接口用)sa_family
struct sockaddr_inIPv4 专用结构sin_familysin_portsin_addr端口和IP必须网络字节序
struct in_addr封装 IPv4 地址s_addr (32位整数)必须网络字节序
类型变量说明
struct in_addrsin_addr封装 IPv4 地址
uint32_ts_addr(sin_addr的成员)32位 IPv4 地址(网络字节序)。
注意:不能直接赋值为 192.168.1.1 这样的十进制数,必须使用 htonl() 或 inet_addr()

IP地址设计为结构体的原因:

原因说明
历史兼容性早期的 Unix 实现中,IP 地址可能有多种表达方式,结构体便于扩展
抽象与封装隐藏底层数据类型,允许未来修改实现而不影响上层代码
语义清晰明确表示这是一个 IP 地址,而不是一个普通的 32 位整数
支持多种地址族为后续支持 IPv6 等不同长度的地址奠定基础
操作便利性可以方便地定义针对 IP 地址的操作函数

整数IP<--->字符串IP

整数IP与字符串IP转换的核心思想是利用IP地址的32位二进制与点分十进制的一一对应关系。转换时有两种方法:一是通过位运算直接操作整数的各字节(整数→字符串:右移提取各字节;字符串→整数:左移拼接各字节),容易实现;二是利用内存映射定义四字段结构体,通过指针强转直接访问各字节,较难实现
实际开发中应优先使用标准库函数inet_pton/inet_ntop
// 网络字节序整数 -> 点分十进制字符串 std::string ip_to_str(uint32_t net_ip) noexcept { uint8_t bytes[4] = { static_cast<uint8_t>(net_ip >> 24), static_cast<uint8_t>(net_ip >> 16), static_cast<uint8_t>(net_ip >> 8), static_cast<uint8_t>(net_ip) }; char buffer[16] = {0}; snprintf(buffer, sizeof(buffer), "%hhu.%hhu.%hhu.%hhu", bytes[0], bytes[1], bytes[2], bytes[3]); return buffer; } // 点分十进制字符串 -> 网络字节序整数 // 返回 bool 表示成功/失败,结果通过参数返回 bool str_to_ip(const std::string& ip, uint32_t& result) noexcept { unsigned int a, b, c, d; // 用unsigned避免溢出 int pos = 0; // 使用 %n 检查完全匹配 if (sscanf(ip.c_str(), "%u.%u.%u.%u%n", &a, &b, &c, &d, &pos) == 4 && pos == static_cast<int>(ip.length()) && (a | b | c | d) <= 0xFF) { // 快速范围检查 result = (a << 24) | (b << 16) | (c << 8) | d; return true; } return false; }

inet_addr

项目说明
函数名inet_addr
全称Internet Address (IPv4)
头文件<arpa/inet.h> (Linux/Unix) <winsock2.h> (Windows)
原型in_addr_t inet_addr(const char *cp);
参数cp:点分十进制格式的 IPv4 地址字符串(如 "192.168.1.100"
返回值成功:返回 32位IPv4地址(网络字节序)
失败:返回 INADDR_NONE (通常是 0xFFFFFFFF,即 -1 或 255.255.255.255)
功能将点分十进制字符串转换为 32位网络字节序的二进制值
适用场景在 sockaddr_in 结构体中填充 sin_addr.s_addr 字段

inet_pton

项目说明
函数名inet_pton
全称Internet Presentation to Network (地址呈现格式转网络格式)
头文件<arpa/inet.h> (Linux/Unix) <ws2tcpip.h> (Windows)
原型int inet_pton(int af, const char *src, void *dst);
参数1af:地址族,AF_INET (IPv4) 或 AF_INET6 (IPv6)
参数2src:点分十进制 (IPv4) 或十六进制 (IPv6) 格式的地址字符串
参数3dst:指向存储二进制结果的指针(struct in_addr * 或 struct in6_addr *
返回值1:成功
0:输入的字符串不是有效的IP地址格式
-1:地址族不支持或发生错误(并设置 errno)
功能将人可读的IP地址字符串转换为网络字节序的二进制格式
适用场景现代网络编程中替代 inet_addr 和 inet_aton,填充 sin_addr 或 sin6_addr 结构

inet_ntoa

项目说明
函数名inet_ntoa
全称Internet Network to Address(网络格式转地址字符串)
头文件<arpa/inet.h> (Linux/Unix) <winsock2.h> (Windows)
原型char *inet_ntoa(struct in_addr in);
参数instruct in_addr 结构体,包含网络字节序的32位IPv4地址
返回值返回指向点分十进制字符串的指针(如 "192.168.1.100"
功能将网络字节序的二进制IP地址转换为点分十进制字符串
适用场景打印IP地址、日志记录、调试输出
线程安全非线程安全(使用静态缓冲区)

inet_ntop

项目说明
函数名inet_ntop
全称Internet Network to Presentation(网络格式转呈现格式)
头文件<arpa/inet.h> (Linux/Unix) <ws2tcpip.h> (Windows)
原型const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
参数1af:地址族,AF_INET (IPv4) 或 AF_INET6 (IPv6)
参数2src:指向二进制IP地址的指针(struct in_addr * 或 struct in6_addr *
参数3dst:调用者提供的缓冲区,用于存储转换后的字符串
参数4size:缓冲区大小(字节数)
返回值成功:返回 dst 指针
失败:返回 NULL,并设置 errno
功能将网络字节序的二进制IP地址转换为人可读的字符串格式(点分十进制或十六进制)
适用场景打印IP地址、日志记录、调试输出、响应构造
线程安全线程安全(调用者提供缓冲区)

结构体关系与强制转换示例

#include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> // 1. 定义并初始化 IPv4 具体结构体 struct sockaddr_in server_addr; memset(&server_addr, 0, sizeof(server_addr)); // 清零,包括 sin_zero server_addr.sin_family = AF_INET; // 地址族:IPv4 server_addr.sin_port = htons(8080); // 端口号:8080 (主机序转网络序) server_addr.sin_addr.s_addr = inet_addr("192.168.1.100"); // IP地址 (字符串转网络序) // 或者: server_addr.sin_addr.s_addr = htonl(0xC0A80164); // 2. 调用 bind 时,强制转换为通用指针 // 注意第三个参数是具体结构体的大小 int ret = bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));

Read more

《C/C+++ Boost 轻量级搜索引擎实战:架构流程、技术栈与工程落地指南——构造正/倒排索引(中篇)》

《C/C+++ Boost 轻量级搜索引擎实战:架构流程、技术栈与工程落地指南——构造正/倒排索引(中篇)》

前引:这是一个聚焦基础搜索引擎核心工作流的实操项目,基于 C/C++ 技术生态落地:从全网爬虫抓取网页资源,到服务器端完成 “去标签 - 数据清洗 - 索引构建” 的预处理,再通过 HTTP 服务接收客户端请求、检索索引并拼接结果页返回 —— 完整覆盖了轻量级搜索引擎的端到端逻辑。项目采用 C++11、STL、Boost 等核心技术栈,搭配 CentOS 7 云服务器 + GCC 编译环境(或 VS 系列开发工具)部署,既适配后端工程的性能需求,也能通过可选的前端技术(HTML5/JS 等)优化用户交互,是理解搜索引擎底层原理与 C++ 工程实践的典型案例 目录 【一】Jieba分词工具 【二】正/倒排索引结构设计

By Ne0inhk

【Web】RCTF 2025 wp(随便看看

随便看看 目录 photographer RootKB Auth maybe_easy photographer 看到要求Auth::type()小于0才能拿到flag 而$user['type']是从findById里取出来的 findById是个左联查询,返回的不只是user的信息,还有photo的信息 题目用的是SQLITE3_ASSOC模式,也就是返回以列名索引的数组 这里有个前置知识 而user和photo均有type字段 photo的type字段是从mime-type里取的 先随便注册个用户 访问/compose路由上传背景图片 Content-Type改为-1 设置背景图片 再访问superadmin.php拿到flag RootKB 题目是最新版的 https://github.com/1Panel-dev/MaxKB/tree/v2 创建工具处可以在线运行python代码 但有些限制 2.3.1版本tool_code.py多了个LD_PRELOAD

By Ne0inhk

基于.Net的Web API 控制器及方法相关注解属性

文章目录 * 1. 路由与 HTTP 方法 (`Microsoft.AspNetCore.Mvc` 命名空间) * 2. 参数绑定源 (`Microsoft.AspNetCore.Mvc` 命名空间) * 3. 响应类型与格式 (`Microsoft.AspNetCore.Mvc` 命名空间) * 4. 授权与认证 (`Microsoft.AspNetCore.Authorization` 命名空间) * 5. Swagger/OpenAPI 文档增强 (`Swashbuckle.AspNetCore.Annotations` 或 `Microsoft.AspNetCore.Mvc`) 这些属性主要用于定义 API 的路由、HTTP 方法、参数绑定、响应类型、授权、Swagger 文档等,通常位于控制器类或 Action

By Ne0inhk

5分钟快速上手WebVOWL:本体可视化完整指南

5分钟快速上手WebVOWL:本体可视化完整指南 【免费下载链接】WebVOWLVisualizing ontologies on the Web 项目地址: https://gitcode.com/gh_mirrors/we/WebVOWL WebVOWL是一个强大的开源工具,专门用于在网页上可视化本体(Ontologies),能够将复杂的RDF和OWL数据转换为直观的图形化表示。无论你是语义网研究者、数据科学家还是本体工程师,这个本体可视化工具都能帮助你更好地理解和分析本体结构,提升数据洞察能力。 🚀 准备工作:系统环境检查 在开始安装WebVOWL之前,请确保你的系统已经安装了以下必备软件: * Node.js (版本12或更高) - JavaScript运行时环境 * Git - 版本控制工具 你可以通过以下命令检查是否已安装: node --version git --version 📥 项目获取与安装 1. 克隆项目仓库 首先需要获取WebVOWL的源代码: git clone https://gitcode.com/

By Ne0inhk