TCP IP网络编程(三) 地址族与数据序列
文章目录
- 分配给套接字的IP地址与端口号
- 网络地址
- 网络地址分类与主机地址边界
- 地址信息的表示
- 表示 IPv4地址的结构体
- 结构体sockaddr_in 的成员分析
- 网络字节序与地址变换
- 字节序与网络字节序
- 字节序转换
- 网络地址的初始化与分配
- 将字符串信息转换为网络字节序的整数型
- 网络地址初始化
- INADDR_ANY
- 向套接字分配网络地址
- 总结
分配给套接字的IP地址与端口号
网络地址
IP地址分为两类:
- IPv4 4字节地址族
- IPv6 16字节地址族
IPv4和IPv6的差别主要是表示在IP地址所用的字节数,目前通用的地址族为IPv4,而IPv6是为了应对IP地址耗尽的问题而提出的标准,目前主要还是使用IPv4
IPv4标准的4字节IP地址分为网络地址和主机地址,且分为A、B、C、D等类型。
A类 网络ID 主机ID 主机ID 主机ID
B类 网络ID 网络ID 主机ID 主机ID
C类 网络ID 网络ID 网络ID 主机ID
D类 网络ID 网络ID 网络ID 网络ID (多播IP地址)
网络地址分类与主机地址边界
通过IP地址的第一个字节即可判断网络地址占用的字节数
- A类地址的首字节范围:0-127
- B类地址的首字节范围:128-191
- C类地址的首字节范围:191-223
还有另一种表述方式
- A类地址的首位以0开始
- B类地址的首位以10开始
- C类地址的首位以110开始
地址信息的表示
表示 IPv4地址的结构体
struct sockaddr_in
{sa_family_t sin_family; //地址族uint16_t sin_port; //16位TCP/UDP端口号struct in_addr sin_addr; //32位IP地址char sin_zero[8]; //不使用
};
该结构体中提到了另外一个结构体 in_addr 定义为:
struct in_addr
{in_addr_t s_addr; //32位IPv4地址
}
上述两个结构体包含一些数据类型,uint16_t、in_addr_t等类型可以参考POSIX。POSIX是为UNIX系统操作设立的标准
POSIX中定义的数据类型
数据类型名称 | 数据类型说明 | 声明头文件 |
---|---|---|
int8_t | signed 8-bit int | sys/types.h |
uint8_t | unsigned 8-bit int | sys/types.h |
int16_t | signed 16-bit int | sys/types.h |
uint16_t | unsigned 16-bit int | sys/types.h |
int32_t | signed 32-bit int | sys/types.h |
uint32_t | unsigned 32-bit int | sys/types.h |
sa_family_t | 地址族(address family) | sys/socket.h |
socklen_t | 长度(length of struct) | sys/socket.h |
in_addr_t | IP地址,,uint32_t | netinet/in.h |
in_port_t | 端口号,uint16_t | netinet/in.h |
结构体sockaddr_in 的成员分析
成员 sin_family
每种协议族适用的协议族均不同,比如IPv4使用4字节地址族,IPv6使用16字节地址族
地址族
地址族 | 含义 |
---|---|
AF_INET | IPv4网络协议中使用的地址族 |
AF_INET6 | IPv6网络协议中使用的地址族 |
AF_LOCAL | 本地通信中采用的UNIX协议的地址族 |
AF_LOCAL是为了说明具有多种地址族而添加的
成员sin_port
该成员保存16位端口号,重点在于,它以网络字节序保存
成员sin_addr
该成员保存32位IP地址信息,也以网络字节序保存,同时管擦结构体in_addr
成员sin_zero
无特殊含义,只是为使结构体sockaddr_in的大小与sockaddr结构体保存一致而插入的成员,必须填充为0
网络字节序与地址变换
字节序与网络字节序
CPU保存数据的方式有两种,意味着CPU解析数据的方式也分为两种
- 大端序:高位字节存放到低位地址
- 小端序:高位字节存放到高位地址
在通过网络传输数据时约定统一方式,这种约定称为网络字节序,统一为大端序
总结来说,将数据数组转发成大端序格式再进行网络传输,所有计算机接收数据时应该识别该数据是网络字节序格式,小端序系统传输时应该转化成大端序排列方式
字节序转换
填充结构体 sockadr_in 前将数据转换成网络字节序,介绍帮助转换字节序的函数
unsigned short htons(unsigned short)
unsigned short ntohs(unsigned short)
unsigned long htonl(unsigned short)
unsined long ntohl(unsigned long)
函数名的含义
- htons中的 h 代表主机(host)字节序
- htons中的 n 代表网络(network)字节序
- htons中的 s 指的是short
- htons中的 l 指的是long(Linux中long类型占用4个字节)
#include <stdio.h>
#include <arpa/inet.h>int main(int argc, char *argv[])
{unsigned short host_port=0x1234;unsigned short net_port;unsigned long host_addr=0x12345678;unsigned long net_addr;net_port=htons(host_port);net_addr=htonl(host_addr);printf("Host ordered port: %#x \n", host_port);printf("Network ordered port: %#x \n", net_port);printf("Host ordered address: %#lx \n", host_addr);printf("Network ordered address: %#lx \n", net_addr);return 0;
}
下面这就是在小端序CPU中运行的结果。如果在大端序CPU中运行,则变量值不会改变。大部分朋友都会得到类似的运行结果,因为Intel和AMD系列的CPU都采用小端序标准。
gcc endian_conv.c -o conv
./conv
输出:
Host ordered port : 0x1234
Network ordered port : 0x3412
Hostordered address : 0x12345678
Network ordered address : 0x78563412
网络地址的初始化与分配
将字符串信息转换为网络字节序的整数型
对于IP地址的表示,我们熟悉的是点分十进制表示法而非整数型数据表示法。幸运的是,有函数会帮我们将字符串形式的IP地址转换成32位整数型数据,在转换类型的同时进行网络字节序转换。
#include<arpa/inet.h>
in_addr_t inet_addr(const char * string);//成功时返回32位大端序整数型值,失败时返回INADDR_NONE。
该函数的调用过程
#include <stdio.h>
#include <arpa/inet.h>int main(int argc, char *argv[])
{char *addr1="127.212.124.78";char *addr2="127.212.124.256";unsigned long conv_addr=inet_addr(addr1);if(conv_addr==INADDR_NONE)printf("Error occured! \n");elseprintf("Network ordered integer addr: %#lx \n", conv_addr);conv_addr=inet_addr(addr2);if(conv_addr==INADDR_NONE)printf("Error occureded \n");elseprintf("Network ordered integer addr: %#lx \n\n", conv_addr);return 0;
}
从结果可以看出,inet_addr函数不仅可以把IP地址转成32位整数型,而且可以检测无效的IP地址
inet_aton函数与inet_addr函数在功能上完全相同,也将字符串形式IP地址转换为32位网络字节序整数并返回。不同的是该函数利用了in_addr结构体,且使用频率更高。
#include<arpa/inet.h>
int inet_aton(const char * string, struct in_addr * addr);成功时返回1,失败时返回0参数1:string,含有需转换的IP地址信息的字符串地址值。参数2:addr,将保存转换结果的in_addr结构体变量的地址值。
该函数的调用过程
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
void error_handling(char *message);int main(int argc, char *argv[])
{char *addr="127.232.124.79";struct sockaddr_in addr_inet;if(!inet_aton(addr, &addr_inet.sin_addr))error_handling("Conversion error");elseprintf("Network ordered integer addr: %#x \n", addr_inet.sin_addr.s_addr);return 0;
}void error_handling(char *message)
{fputs(message, stderr);fputc('\n', stderr);exit(1);
}
调用inet_addr函数,返回转换后的IP地址信息还需保存到sockaddr_in结构体中声明的in_addr结构体变量。而inet_aton函数则不需此过程,因为该函数会自动把结果存入该结构体变量。
还有一个函数,与 inet_aton() 正好相反,它可以把网络字节序整数型IP地址转换成我们熟悉的字符串形式
#include <arpa/inet.h>
char *inet_ntoa(struct in_addr adr);成功返回转换的字符串地址值,失败返回-1
-
该函数将通过参数传入的整数型IP地址转换为字符串格式并返回
-
但要小心,返回值为 char 指针,返回字符串地址意味着字符串已经保存在内存空间,但是该函数未向程序员要求分配内存,而是在内部申请了内存保存了字符串。也就是说调用了该函数候要立即把信息复制到其他内存空间。因为,若再次调用inet_ntoa函数,则有可能覆盖之前保存的字符串信息
-
总之,再次调用 inet_ntoa 函数前返回的字符串地址是有效的。若需要长期保存,则应该将字符串复制到其他内存空间
给出该函数的调用示例
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>int main(int argc, char *argv[])
{struct sockaddr_in addr1, addr2;char *str_ptr;char str_arr[20];addr1.sin_addr.s_addr=htonl(0x1020304);addr2.sin_addr.s_addr=htonl(0x1010101);str_ptr=inet_ntoa(addr1.sin_addr);strcpy(str_arr, str_ptr);printf("Dotted-Decimal notation1: %s \n", str_ptr);inet_ntoa(addr2.sin_addr);printf("Dotted-Decimal notation2: %s \n", str_ptr);printf("Dotted-Decimal notation3: %s \n", str_arr);return 0;
}
网络地址初始化
服务器端套接字创建过程中常见的网络地址信息初始化方法:
struct sockaddr_in addr;
char *serv_ip = "211.217.168.13"; // 声明 IP 地址字符串
char *serv_port = "9190"; // 声明端口号字符串
memset(&addr, 0, sizeof(addr)); // 结构体变量 addr 的所有成员初始化为 0,主要是为了将 sockaddr_in 的成员 sin_zero 初始化为 0。
addr.sin_family = AF_INET; // 指定地址族
addr.sin_addr.s_addr = inet_addr(serv_ip); // 基于字符串的 IP 地址初始化
addr.sin_port = htons(atoi(serv_port)); // 基于字符串的端口号初始化
INADDR_ANY
初始化地址信息
struct sockaddr_in addr;
char * serv_port = "9190";
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
add.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(atoi(serv_port));
与之前方式最大的区别在于,利用INADDR_ANY分配服务器端的IP地址若采用这种方式,则可自动获取运行服务器端的计算机IP地址,不必亲自输入。而且,若同一计算机中已分配多个IP地址,则只要端口号一致,就可以从不同IP地址接收数据。
向套接字分配网络地址
前面了解了sockaddr_in结构体的初始化方法,接下来就把初始化的地址信息分配给套接字。bind函数负责这项操作
#include<sys/socket.h>
int bind(int sockfd, struct sockaddr * myaddr, socklen_t addrlen);成功时返回0,失败时返回-1。参数1:sockfd,要分配地址信息(IP地址和端口号)的套接字文件描述符参数2:myaddr,存有地址信息的结构体变量地址值。参数3:addrlen,第二个结构体变量的长度。
如果此函数调用成功,则将第二个参数指定的地址信息分配给第一个参数中的相应套接字。
int serv_sock;
struct sockaddr_in serv_addr;
char * srev_port = "9190";/* 创建服务器端套接字(监听套接字)*/
serv_sock = socket(PF_INET, SOCK_STREAM, 0);/* 地址信息初始化 */
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(atoi(serv_port));/* 分配地址信息 */
bind(serv_sock, (struct sockaddr * )&serv_addr, sizeof(serv_addr));
服务器端代码结构如上
总结
这是《TCP/IP网络编程》专栏的第三篇文章,欢迎各位读者订阅!
更多资料点击 GitHub 欢迎各位读者去Star
⭐学术交流群Q 754410389 持续更新中~~~
相关文章:
TCP IP网络编程(三) 地址族与数据序列
文章目录 分配给套接字的IP地址与端口号网络地址网络地址分类与主机地址边界 地址信息的表示表示 IPv4地址的结构体结构体sockaddr_in 的成员分析 网络字节序与地址变换字节序与网络字节序字节序转换 网络地址的初始化与分配将字符串信息转换为网络字节序的整数型网络地址初始化…...

对比Flink、Storm、Spark Streaming 的反压机制
分析&回答 Flink 反压机制 Flink 如何处理反压? Storm 反压机制 Storm反压机制 Storm 在每一个 Bolt 都会有一个监测反压的线程(Backpressure Thread),这个线程一但检测到 Bolt 里的接收队列(recv queue)出现了…...
Ubuntu常用配置集合
Ubuntu配置软件镜像源 参考文章:Ubuntu如何配置软件镜像源 建议使用清华的源。 Ubuntu安装SSH服务: 参考文章:Ubuntu安装SSH服务 ubuntu下安装使用nvm 参考文章:ubuntu下安装使用nvm 出现下载sh文件不成功的情况,…...
传统三维重建和深度学习三维重建 MVS笔记总结、问题总结
什么是cost-volume ?(代价体) 什么是置信度?置信区间? pixel-wise,patch-wise,image-wise的区别 图像 4领域-8领域-16领域 及代码实现 文章目录 1 plane-sweeping2 传统三维重建深度学习三维重建有何不同呢?3 大型场景重建4 PMVS-精确、密集、鲁棒的多视图立体视觉…...

Ansible学习笔记10
1、在group1的被管理机里的mariadb里创建一个abc库; 1) 然后我们到agent主机上进行检查: 可以看到数据库已经创建成功。 再看几个其他命令: #a组主机重启mysql,并设置开机自启 ansible a -m service -a "namemy…...

肖sir__linux详解__002(系统命令)
linux系统命令 1、df 查看磁盘使用情况 (1)df 查看磁盘使用情况(按kb单位显示) (2)df -h 按单位显示磁盘使用情况 2、top 实时查看动态进程 (1)top 详解: 第一行&…...

AI绘画:StableDiffusion实操教程-斗罗大陆2-江楠楠-常服(附高清图下载)
前段时间我分享了StableDiffusion的非常完整的教程:“AI绘画:Stable Diffusion 终极宝典:从入门到精通 ” 尽管如此,还有读者反馈说,尽管已经成功安装,但生成的图片与我展示的结果相去甚远。真实感和质感之…...

JavaScript运行机制与实践应用
一、JavsScript运行机制 1、JavaScript 是一种解释型语言,它的执行机制主要包括以下几个步骤: 2、事件循环 3、JavaScript运行模型 4、JavaScript任务 5、JavaScript宏任务和微任务 6、案例分析 console.log(script start) setTimeout(function () {co…...

【算法奥义】最大矩形问题
首先建立一个二维数组,这个二维数组,计算出矩阵的每个元素的左边连续 1 的数量,使用二维数组 left记录,其中left[i][j] 为矩阵第 i 行第 j 列元素的左边连续 1 的数量。 也就是从这个元素开始,从右往左边数有多少个连…...
06 Kafka线上集群部署方案
kafka部署在linux上有什么好处 网络传输效率 kafka部署在linux上,可以用到linux的零拷贝提升网络传输效率,提高kafka的吞吐量。利用零拷贝可以使数据不经过用户态直接通过网卡发送给接收方,实现数据的高性能传输 kafka和零拷贝技术 kafka…...
flex-shrink计算题
当我们使用 flexbox 布局时,flex-shrink 属性用于指定 flex 项在空间不足时收缩的比例。它表示了一个 flex 项相对于其他 flex 项收缩的比例。 假设有一个 flex 容器,其中包含三个子项,它们的 flex-shrink 分别设置为 1、2 和 3。当容器的可…...
Springboot - 5.Bean的生命周期
✍1. Bean的生命周期: 当然,我会详细描述每一步的作用。 🎷1. 实例化Bean: 这是Bean生命周期的第一步。Spring容器通过反射机制创建Bean的实例。public class ExampleBean {// ... }🎷2. 设置Bean的属性: Spring容器将根据配置…...

华为云 sfs 服务浅谈
以root用户登录弹性云服务器。 以root用户登录弹性云服务器。 安装NFS客户端。 查看系统是否安装NFS软件包。 CentOS、Red Hat、Oracle Enterprise Linux、SUSE、Euler OS、Fedora或OpenSUSE系统下,执行如下命令: rpm -qa|grep nfs Debian或Ubuntu系统下…...

CSS中如何实现元素的渐变背景(Gradient Background)效果?
聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ CSS 渐变背景效果⭐ 线性渐变背景⭐ 径向渐变背景⭐ 添加到元素的样式⭐ 写在最后 ⭐ 专栏简介 前端入门之旅:探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅&…...

buildroot修改内核防止清理重新加载办法
当你使用 Buildroot 构建 Linux 内核时,如果对内核文件进行了手动修改,重新执行 Buildroot 的构建过程将会覆盖你所做的修改。这是因为 Buildroot会根据配置重新下载、提取和编译内核。 为了避免在重新构建时覆盖你的修改,可以采取以下两种方…...

Vue框架--Vue中的事件
1.事件处理 事件的基本使用: (1).使用v-on:xxx 或 @xxx 绑定事件,其中xxx是事件名; (2).事件的回调需要配置在methods对象中,最终会在vm上; (3).methods中配置的函数,不要用箭头函数!否则this就不是vm了; (4).methods中配置的函数,都是被Vue所管理的函数,this的…...
1921. 消灭怪物的最大数量
原题地址 解法一 排序贪心即可。思想为先计算出每一个怪兽到达城市的时间,然后排序,有小到大进行消灭,此时的下标可视作时间。当怪兽到达城市的时间超过或等于当前时间时,即已经到达了城市,游戏失败,下标…...

创建一个空的vue项目,配置及步骤
查看需要的环境及插件版本 创建vue命令 默认配置 手动配置 其他 hash和history的区别: hash 模式,url后,会带着#,改变hash,页面不会刷新,不会更改整个页面,只会更改#后面路由配置的内容&#x…...

一篇文章教会你如何编写一个简单的Shell脚本
文章目录 简单Shell脚本编写1. 简单脚本编写2. Shell脚本参数2.1 Shell脚本参数判断2.1.1 文件测试语句2.1.2 逻辑测试语句2.1.3 整数值测试语句2.1.4 字符串比较语句 3. Shell流程控制语句3.1 if 条件测试语句3.1.1 if...3.1.2 if...else...3.1.3 if...elif...else 4. Shell脚…...
SSM框架-spring
SSM框架参考 spring...

【入坑系列】TiDB 强制索引在不同库下不生效问题
文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...

python/java环境配置
环境变量放一起 python: 1.首先下载Python Python下载地址:Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个,然后自定义,全选 可以把前4个选上 3.环境配置 1)搜高级系统设置 2…...
系统设计 --- MongoDB亿级数据查询优化策略
系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log,共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题,不能使用ELK只能使用…...

ios苹果系统,js 滑动屏幕、锚定无效
现象:window.addEventListener监听touch无效,划不动屏幕,但是代码逻辑都有执行到。 scrollIntoView也无效。 原因:这是因为 iOS 的触摸事件处理机制和 touch-action: none 的设置有关。ios有太多得交互动作,从而会影响…...
基于matlab策略迭代和值迭代法的动态规划
经典的基于策略迭代和值迭代法的动态规划matlab代码,实现机器人的最优运输 Dynamic-Programming-master/Environment.pdf , 104724 Dynamic-Programming-master/README.md , 506 Dynamic-Programming-master/generalizedPolicyIteration.m , 1970 Dynamic-Programm…...

网站指纹识别
网站指纹识别 网站的最基本组成:服务器(操作系统)、中间件(web容器)、脚本语言、数据厍 为什么要了解这些?举个例子:发现了一个文件读取漏洞,我们需要读/etc/passwd,如…...

Docker 本地安装 mysql 数据库
Docker: Accelerated Container Application Development 下载对应操作系统版本的 docker ;并安装。 基础操作不再赘述。 打开 macOS 终端,开始 docker 安装mysql之旅 第一步 docker search mysql 》〉docker search mysql NAME DE…...

LabVIEW双光子成像系统技术
双光子成像技术的核心特性 双光子成像通过双低能量光子协同激发机制,展现出显著的技术优势: 深层组织穿透能力:适用于活体组织深度成像 高分辨率观测性能:满足微观结构的精细研究需求 低光毒性特点:减少对样本的损伤…...

Qemu arm操作系统开发环境
使用qemu虚拟arm硬件比较合适。 步骤如下: 安装qemu apt install qemu-system安装aarch64-none-elf-gcc 需要手动下载,下载地址:https://developer.arm.com/-/media/Files/downloads/gnu/13.2.rel1/binrel/arm-gnu-toolchain-13.2.rel1-x…...

消防一体化安全管控平台:构建消防“一张图”和APP统一管理
在城市的某个角落,一场突如其来的火灾打破了平静。熊熊烈火迅速蔓延,滚滚浓烟弥漫开来,周围群众的生命财产安全受到严重威胁。就在这千钧一发之际,消防救援队伍迅速行动,而豪越科技消防一体化安全管控平台构建的消防“…...